### Module version
<!---
Inspect your go.mod as below to find the version, and… paste the result between the ``` marks below.
go list -m github.com/hashicorp/terraform-plugin-framework/...
If you are not running the latest version of the framework, please try upgrading
because your bug may have already been fixed.
-->
```
1.4.2
```
We are currently migrating existing Plugin-SDK based resources to Plugin Framework (Plugin protocol v6). In below resource, we have some **optional+computed** list block attributes where certain nested attributes _if not configured/partially configured_ by the user in the config, the API/provider will still return those attributes. That response is currently persisted in the state.
In order to migrate these blocks to the Plugin Framework, we have tried using schema.ListNestedBlock but the returned plan after upgrade to the Framework-migrated resource is always non-empty. **This will be a breaking change for our users.**
**What is the recommended non-breaking way to migrate list attributes such as these?**
### Relevant provider source code
<!--
Paste any Go code that you believe to be relevant to the bug
e.g. schema or implementation of CRUD for a given resource or data source
-->
Terraform Plugin SDK based schema for "advanced_configuration" block:
```go
func ClusterAdvancedConfigurationSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Optional: true,
Computed: true,
ConfigMode: schema.SchemaConfigModeAttr,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"default_read_concern": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"default_write_concern": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"fail_index_key_too_long": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},
"javascript_enabled": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},
"minimum_enabled_tls_protocol": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"no_table_scan": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},
"oplog_size_mb": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
},
"oplog_min_retention_hours": {
Type: schema.TypeInt,
Optional: true,
},
........
},
},
}
}
```
Terraform Plugin Framework migrated schema:
```go
func clusterRSAdvancedConfigurationSchemaBlock() schema.ListNestedBlock {
return schema.ListNestedBlock{
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"default_read_concern": schema.StringAttribute{
Optional: true,
Computed: true,
},
"default_write_concern": schema.StringAttribute{
Optional: true,
Computed: true,
},
"fail_index_key_too_long": schema.BoolAttribute{
Optional: true,
Computed: true,
},
"javascript_enabled": schema.BoolAttribute{
Optional: true,
Computed: true,
},
"minimum_enabled_tls_protocol": schema.StringAttribute{
Optional: true,
Computed: true,
},
"no_table_scan": schema.BoolAttribute{
Optional: true,
Computed: true,
},
"oplog_min_retention_hours": schema.Int64Attribute{
Optional: true,
},
"oplog_size_mb": schema.Int64Attribute{
Optional: true,
Computed: true,
},
..........
},
},
Validators: []validator.List{
listvalidator.SizeAtMost(1),
},
PlanModifiers: []planmodifier.List{
listplanmodifier.UseStateForUnknown(),
},
}
}
```
### Terraform Configuration Files
<!--
Paste the relevant parts of your Terraform configuration between the ``` marks below.
For large Terraform configs, please use a service like Dropbox and share a link to the ZIP file. For security, you can also encrypt the files using our GPG public key.
-->
Use-case 1 (no blocks configured):
```hcl
main.tf:
resource "mongodbatlas_cluster" "cluster-no-blocks" {
project_id = mongodbatlas_project.project-tf.id
provider_name = "AWS"
name = "tfCluster1"
backing_provider_name = "AWS"
provider_region_name = "US_EAST_1"
provider_instance_size_name = "M10"
auto_scaling_compute_enabled = false
auto_scaling_compute_scale_down_enabled = false
provider_auto_scaling_compute_min_instance_size = "M10"
provider_auto_scaling_compute_max_instance_size = "M20"
}
terraform.tfstate (including only concerned blocks here due to large resource config):
"advanced_configuration": [
{
"default_read_concern": "",
"default_write_concern": "",
"fail_index_key_too_long": false,
"javascript_enabled": true,
"minimum_enabled_tls_protocol": "TLS1_2",
"no_table_scan": false,
"oplog_min_retention_hours": 0,
"oplog_size_mb": 0,
"sample_refresh_interval_bi_connector": 0,
"sample_size_bi_connector": 0,
"transaction_lifetime_limit_seconds": 0
}
],
"bi_connector_config": [
{
"enabled": false,
"read_preference": "secondary"
}
],
```
Use-case 2 (all blocks configured):
```hcl
main.tf:
resource "mongodbatlas_cluster" "cluster-multi-region-all-blocks" {
project_id = mongodbatlas_project.project-tf.id
name = "cluster-test-multi-region"
num_shards = 1
cloud_backup = true
cluster_type = "REPLICASET"
provider_name = "AWS"
provider_instance_size_name = "M10"
advanced_configuration { # block can be partially configured by user
minimum_enabled_tls_protocol = "TLS1_2"
default_read_concern = "available"
}
bi_connector_config {
enabled = false
read_preference = "secondary"
}
terraform.tfstate (including only concerned blocks here due to large resource config):
"advanced_configuration": [
{
"default_read_concern": "available",
"default_write_concern": "",
"fail_index_key_too_long": false,
"javascript_enabled": true,
"minimum_enabled_tls_protocol": "TLS1_2",
"no_table_scan": false,
"oplog_min_retention_hours": 0,
"oplog_size_mb": 0,
"sample_refresh_interval_bi_connector": 0,
"sample_size_bi_connector": 0,
"transaction_lifetime_limit_seconds": 0
}
],
"bi_connector_config": [
{
"enabled": false,
"read_preference": "secondary"
}
],
```
### Debug Output
<!--
Full debug output can be obtained by running Terraform with the environment variable `TF_LOG=trace`. Please create a GitHub Gist containing the debug output. Please do _not_ paste the debug output in the issue, since debug output is long.
Debug output may contain sensitive information. Please review it before posting publicly, and if you are concerned feel free to encrypt the files using the HashiCorp security public key.
-->
### Expected Behavior
<!--
What should have happened?
-->
After user upgrades to new provider version with the framework-migrated resource, user should not see any planned changes for optional+computed lists/set blocks when running `terraform plan` and not receive errors when running `terraform apply`.
### Actual Behavior
<!--
What actually happened?
-->
On running `terraform plan` below plan was produced by Terraform:
**Use-case 1 (no blocks configured):**
```
~ update in-place
Terraform will perform the following actions:
# mongodbatlas_cluster.cluster-no-blocks will be updated in-place
~ resource "mongodbatlas_cluster" "cluster-no-blocks" {
id = "Y2x1c3Rlcl9pZA==:NjU2ODhiMmYzZDI3MWYzZjg2MGI0NjQw-Y2x1c3Rlcl9uYW1l:dGZDbHVzdGVyMQ==-cHJvamVjdF9pZA==:NjRlY2MxNTkyNzVmMjM1OWY0Y2FlODEw-cHJvdmlkZXJfbmFtZQ==:QVdT"
name = "tfCluster1"
~ num_shards = 1 -> (known after apply)
# (34 unchanged attributes hidden)
- advanced_configuration {
- javascript_enabled = true -> null
- minimum_enabled_tls_protocol = "TLS1_2" -> null
- no_table_scan = false -> null
- oplog_min_retention_hours = 0 -> null
}
- bi_connector_config {
- enabled = false -> null
- read_preference = "secondary" -> null
}
```
**Use-case 2 (all blocks configured):**
```
~ update in-place
Terraform will perform the following actions:
# mongodbatlas_cluster.cluster-multi-region-all-blocks will be updated in-place
~ resource "mongodbatlas_cluster" "cluster-multi-region-all-blocks" {
id = "Y2x1c3Rlcl9pZA==:NjU2ODhlZTgzZDI3MWYzZjg2MGI0ZTY3-Y2x1c3Rlcl9uYW1l:dGYtbXVsdGktcmVnaW9uLWFsbC1ibG9ja3M=-cHJvamVjdF9pZA==:NjRlY2MxNTkyNzVmMjM1OWY0Y2FlODEw-cHJvdmlkZXJfbmFtZQ==:QVdT"
name = "tf-multi-region-all-blocks"
# (32 unchanged attributes hidden)
~ advanced_configuration {
+ default_write_concern = (known after apply)
+ fail_index_key_too_long = (known after apply)
~ no_table_scan = false -> (known after apply)
- oplog_min_retention_hours = 0 -> null
+ oplog_size_mb = (known after apply)
+ sample_refresh_interval_bi_connector = (known after apply)
+ sample_size_bi_connector = (known after apply)
+ transaction_lifetime_limit_seconds = (known after apply)
# (3 unchanged attributes hidden)
}
```
### Steps to Reproduce
<!--
Please list the full steps required to reproduce the issue, for example:
1. `terraform init`
3. `terraform apply`
-->
1. run `terraform init` for provider v.X (contains-Plugin-SDK-based-resource-implementation) for above resource
2. run `terraform plan`
4. run `terraform apply`
5. run `terraform plan` again -> plan returns `No changes.`
6. update provider version to v.Y (contains-Plugin-Framework-based-resource-implementation) for above resource, run `terraform init --upgrade`
7. run `terraform plan` -> Plan is not empty
### References
<!--
Are there any other GitHub issues (open or closed) or Pull Requests that should be linked here? For example:
- #6017
-->
Included advanced_configuration schema in this issue. Other block schemas mentioned in the example are:
- bi_connector_config [Plugin-SDK schema](https://github.com/mongodb/terraform-provider-mongodbatlas/blob/master/internal/service/cluster/resource_cluster.go#L91) - [migrated-Plugin-Framework schema](https://github.com/mongodb/terraform-provider-mongodbatlas/blob/INTMDB-976-migrate-cluster-framework/mongodbatlas/fw_resource_mongodbatlas_cluster.go#L344)