-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Strange behavior with Computed
attributes after v0.4.2 upgrade
#187
Comments
This behavior is (unfortunately) expected with the current implementation of As shown in hashicorp/terraform-provider-awscc#222 this behavior can be improved with the following workaround: tfsdk.RequiresReplaceIf(func(ctx context.Context, state, config attr.Value, path *tftypes.AttributePath) (bool, diag.Diagnostics) {
// TODO: Use config.IsNull() when available
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/193
if config.Equal(state) || config.Equal(types.String{Null: true}) {
return false, nil
}
return true, nil
}, "require replacement if configuration value changes", "require replacement if configuration value changes"), Whether either or both parts of the conditional there should be part of the |
So the solution we came up with to fix this is to:
As I'm writing tests and leaving a comment for why that exception is carved out, I'm struggling here. Why did we decide that was important? Is it only because we're trying to control for the scenario where Optional+Computed attributes aren't set, and the provider changes them, in which case the practitioner likely doesn't expect the resource to be destroyed and recreated? If so, should that conditional only apply to computed attributes? |
Fixes #187, supercedes #203. This changes the logic on our RequiresReplace function in the following ways: * if the attribute being modified has not changed, RequiresReplace isn't changed. This prevents the resource from being destroyed and recreated when _any_ attribute changes, limiting it only to the attribute with RequiresReplace set on it. * if the attribute being modified is computed and is null in the config, RequiresReplace isn't changed. This prevents the resource from being destroyed and recreated when the provider returns an unknown value in the plan, or even a new, provider-controlled value, because it's unlikely the practitioners expect their resource to be destroyed and recreated when an attribute out of their control changes. This has the unfortunate side-effect that practitioners removing an Optional+Computed field from their config will not prompt the default RequiresReplace behavior, but providers can specify their own, special plan modifier that has a better understanding of practitioner intent in that case. * if the resource is being created or destroyed, RequiresReplace isn't changed. This prevents the resource from being marked for destruction and recreation when it's just now being created or destroyed, which would be nonsensical. RequiresReplaceIf gets all these changes and an additional change that it will only set RequiresReplace to true, never to false, as its Modify method's GoDoc indicated. This means that RequiresReplaceIf functions can be chained, and that RequiresReplaceIf won't overwrite previous plan modifiers' determinations on whether or not the resource should be destroyed and recreated. Tests were added for RequiresReplace and RequiresReplaceIf to test these invariants.
Indeed, the second rule:
Should probably only apply to |
Yes - see hashicorp/terraform-provider-awscc#222. |
I think #213 meets these needs. Tests that I added should illustrate its behavior in various scenarios and explain what those scenarios are/why we decided to behave that way in those scenarios. |
Fixes #187, supercedes #203. This changes the logic on our RequiresReplace function in the following ways: * if the attribute being modified has not changed, RequiresReplace isn't changed. This prevents the resource from being destroyed and recreated when _any_ attribute changes, limiting it only to the attribute with RequiresReplace set on it. * if the attribute being modified is computed and is null in the config, RequiresReplace isn't changed. This prevents the resource from being destroyed and recreated when the provider returns an unknown value in the plan, or even a new, provider-controlled value, because it's unlikely the practitioners expect their resource to be destroyed and recreated when an attribute out of their control changes. This has the unfortunate side-effect that practitioners removing an Optional+Computed field from their config will not prompt the default RequiresReplace behavior, but providers can specify their own, special plan modifier that has a better understanding of practitioner intent in that case. * if the resource is being created or destroyed, RequiresReplace isn't changed. This prevents the resource from being marked for destruction and recreation when it's just now being created or destroyed, which would be nonsensical. RequiresReplaceIf gets all these changes and an additional change that it will only set RequiresReplace to true, never to false, as its Modify method's GoDoc indicated. This means that RequiresReplaceIf functions can be chained, and that RequiresReplaceIf won't overwrite previous plan modifiers' determinations on whether or not the resource should be destroyed and recreated. Tests were added for RequiresReplace and RequiresReplaceIf to test these invariants.
Fixes #187, supercedes #203. This changes the logic on our RequiresReplace function in the following ways: * if the attribute being modified has not changed, RequiresReplace isn't changed. This prevents the resource from being destroyed and recreated when _any_ attribute changes, limiting it only to the attribute with RequiresReplace set on it. * if the attribute being modified is computed and is null in the config, RequiresReplace isn't changed. This prevents the resource from being destroyed and recreated when the provider returns an unknown value in the plan, or even a new, provider-controlled value, because it's unlikely the practitioners expect their resource to be destroyed and recreated when an attribute out of their control changes. This has the unfortunate side-effect that practitioners removing an Optional+Computed field from their config will not prompt the default RequiresReplace behavior, but providers can specify their own, special plan modifier that has a better understanding of practitioner intent in that case. * if the resource is being created or destroyed, RequiresReplace isn't changed. This prevents the resource from being marked for destruction and recreation when it's just now being created or destroyed, which would be nonsensical. RequiresReplaceIf gets all these changes and an additional change that it will only set RequiresReplace to true, never to false, as its Modify method's GoDoc indicated. This means that RequiresReplaceIf functions can be chained, and that RequiresReplaceIf won't overwrite previous plan modifiers' determinations on whether or not the resource should be destroyed and recreated. Tests were added for RequiresReplace and RequiresReplaceIf to test these invariants.
Fixes #187, supercedes #203. This changes the logic on our RequiresReplace function in the following ways: * if the attribute being modified has not changed, RequiresReplace isn't changed. This prevents the resource from being destroyed and recreated when _any_ attribute changes, limiting it only to the attribute with RequiresReplace set on it. * if the attribute being modified is computed and is null in the config, RequiresReplace isn't changed. This prevents the resource from being destroyed and recreated when the provider returns an unknown value in the plan, or even a new, provider-controlled value, because it's unlikely the practitioners expect their resource to be destroyed and recreated when an attribute out of their control changes. This has the unfortunate side-effect that practitioners removing an Optional+Computed field from their config will not prompt the default RequiresReplace behavior, but providers can specify their own, special plan modifier that has a better understanding of practitioner intent in that case. * if the resource is being created or destroyed, RequiresReplace isn't changed. This prevents the resource from being marked for destruction and recreation when it's just now being created or destroyed, which would be nonsensical. RequiresReplaceIf gets all these changes and an additional change that it will only set RequiresReplace to true, never to false, as its Modify method's GoDoc indicated. This means that RequiresReplaceIf functions can be chained, and that RequiresReplaceIf won't overwrite previous plan modifiers' determinations on whether or not the resource should be destroyed and recreated. Tests were added for RequiresReplace and RequiresReplaceIf to test these invariants.
Fixes #187, supercedes #203. This changes the logic on our RequiresReplace function in the following ways: * if the attribute being modified has not changed, RequiresReplace isn't changed. This prevents the resource from being destroyed and recreated when _any_ attribute changes, limiting it only to the attribute with RequiresReplace set on it. * if the attribute being modified is computed and is null in the config, RequiresReplace isn't changed. This prevents the resource from being destroyed and recreated when the provider returns an unknown value in the plan, or even a new, provider-controlled value, because it's unlikely the practitioners expect their resource to be destroyed and recreated when an attribute out of their control changes. This has the unfortunate side-effect that practitioners removing an Optional+Computed field from their config will not prompt the default RequiresReplace behavior, but providers can specify their own, special plan modifier that has a better understanding of practitioner intent in that case. * if the resource is being created or destroyed, RequiresReplace isn't changed. This prevents the resource from being marked for destruction and recreation when it's just now being created or destroyed, which would be nonsensical. RequiresReplaceIf gets all these changes and an additional change that it will only set RequiresReplace to true, never to false, as its Modify method's GoDoc indicated. This means that RequiresReplaceIf functions can be chained, and that RequiresReplaceIf won't overwrite previous plan modifiers' determinations on whether or not the resource should be destroyed and recreated. Tests were added for RequiresReplace and RequiresReplaceIf to test these invariants. Co-authored-by: Brian Flad <bflad417@gmail.com>
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. |
I upgraded to
terraform-plugin-framework@v0.4.2
and am now seeing some strange behavior.A resource has an attribute
When
terraform plan
shows a difference in another attribute (description
in this case which is Optional and is now getting a value):The attribute
function_name
(which hasn't changed) is showing a change (and a replacement as it's ForceNew).arn
andid
are also both Computed attributes and their values have not changed.This behavior was not observed with
v0.4.0
.The text was updated successfully, but these errors were encountered: