Problem statement - TPF increases plan output verbosity
When migrating resources from SDK v2 over to TPF we have found that all computed attributes not defined in the resource configuration generate a -> (known after apply)
entry.
Example SDK v2 implementation plan output modifying single attribute:
# mongodbatlas_advanced_cluster.test6 will be updated in-place
~ resource "mongodbatlas_advanced_cluster" "test6" {
id = "Y2x1c3Rlcl9pZA==:Njc4Nzk5ZDI3MWI0ZmQyNjJiMGQ2YjA2-Y2x1c3Rlcl9uYW1l:T3RoZXJOYW1lNg==-cHJvamVjdF9pZA==:NjUwOTcyODQ4MjY5MTg1YzU1ZjQwY2Ex"
name = "OtherName6"
# (18 unchanged attributes hidden)
+ pinned_fcv {
+ expiration_date = "2025-01-15T11:00:44Z"
}
# (3 unchanged blocks hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
Example TPF implementation plan output modifying single attribute:
# mongodbatlas_advanced_cluster.test will be updated in-place
~ resource "mongodbatlas_advanced_cluster" "test" {
~ advanced_configuration = {
~ change_stream_options_pre_and_post_images_expire_after_seconds = -1 -> (known after apply)
~ default_read_concern = "" -> (known after apply)
~ default_write_concern = "" -> (known after apply)
~ fail_index_key_too_long = false -> (known after apply)
~ javascript_enabled = true -> (known after apply)
~ minimum_enabled_tls_protocol = "TLS1_2" -> (known after apply)
~ no_table_scan = false -> (known after apply)
~ oplog_min_retention_hours = 0 -> (known after apply)
~ oplog_size_mb = 0 -> (known after apply)
~ sample_refresh_interval_bi_connector = 0 -> (known after apply)
~ sample_size_bi_connector = 0 -> (known after apply)
~ transaction_lifetime_limit_seconds = 0 -> (known after apply)
} -> (known after apply)
~ bi_connector_config = {
~ enabled = false -> (known after apply)
~ read_preference = "secondary" -> (known after apply)
} -> (known after apply)
~ cluster_id = "67877b94cad4d051941efa6e" -> (known after apply)
+ config_server_management_mode = (known after apply)
+ config_server_type = (known after apply)
~ connection_strings = {
~ private = "" -> (known after apply)
+ private_endpoint = (known after apply)
~ private_srv = "" -> (known after apply)
~ standard = "mongodb://othername-shard-00-00.li87i.mongodb-qa.net:27017,othername-shard-00-01.li87i.mongodb-qa.net:27017,othername-shard-00-02.li87i.mongodb-qa.net:27017/?ssl=true&authSource=admin&replicaSet=atlas-nidyp1-shard-0" -> (known after apply)
~ standard_srv = "mongodb+srv://othername.li87i.mongodb-qa.net" -> (known after apply)
} -> (known after apply)
~ encryption_at_rest_provider = "NONE" -> (known after apply)
~ global_cluster_self_managed_sharding = false -> (known after apply)
~ mongo_db_version = "8.0.4" -> (known after apply)
name = "OtherName"
~ paused = false -> (known after apply)
+ pinned_fcv = {
+ expiration_date = "2025-01-15T09:40:44Z"
+ version = (known after apply)
}
~ replication_specs = [
~ {
~ container_id = {
- "AWS:US_EAST_1" = "67877b94cad4d051941efa6b"
} -> (known after apply)
~ external_id = "67877b94cad4d051941efa56" -> (known after apply)
~ id = "67877b94cad4d051941efa55" -> (known after apply)
~ region_configs = [
~ {
+ analytics_auto_scaling = (known after apply)
~ analytics_specs = {
~ disk_iops = 3000 -> (known after apply)
~ disk_size_gb = 10 -> (known after apply)
~ ebs_volume_type = "STANDARD" -> (known after apply)
~ instance_size = "M10" -> (known after apply)
~ node_count = 0 -> (known after apply)
} -> (known after apply)
~ auto_scaling = {
~ compute_enabled = false -> (known after apply)
~ compute_max_instance_size = "" -> (known after apply)
~ compute_min_instance_size = "" -> (known after apply)
~ compute_scale_down_enabled = false -> (known after apply)
~ disk_gb_enabled = false -> (known after apply)
} -> (known after apply)
~ electable_specs = {
~ disk_iops = 3000 -> (known after apply)
~ disk_size_gb = 10 -> (known after apply)
~ ebs_volume_type = "STANDARD" -> (known after apply)
# (2 unchanged attributes hidden)
}
# (3 unchanged attributes hidden)
},
]
~ zone_id = "67877b94cad4d051941efa54" -> (known after apply)
~ zone_name = "ZoneName managed by Terraform" -> (known after apply)
# (1 unchanged attribute hidden)
},
]
....
# (4 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
Available mitigations
UseStateForUnknown plan modifier is provided as a way of reducing these entries. This however has the following limitations:
- Modifying unknown values to known values using the state can only be done when the value of the attribute will not change. This has the risk of encountering
produced inconsistent result after apply
if used incorrectly. - Defining a value as known can have side effects on update operation logic which relies on the plan. Update logic will be coupled with any plan modifier logic for reducing plan verbosity.
Open questions
Is there any alternative recommendation for reducing this plan verbosity in plan outputs?
Some options which come to mind:
- Resource-level configuration to preserve SDK v2 behaviour of not displaying
-> (known after apply)
. - Configurable flag from user side when calling plan/apply operation to not display → (known after apply).
- A way to differentiate when ModifyPlan is called before showing the plan to the user and when called just before update operation (more aggressive / without unknowns to show to the user, less aggressive / with more unknowns for Update)