Skip to content
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

Only set RequiresReplace if value has changed and config is non-null #203

Closed
wants to merge 1 commit into from

Conversation

kmoe
Copy link
Member

@kmoe kmoe commented Oct 7, 2021

The following conditions must now be met in order for the RequiresReplace helpers to set RequiresReplace on the attribute:

  • The planned value must not be equal to the current state.
  • The config value must not be null.

This more closely mirrors the ForceNew behaviour in SDKv2, and corrects unexpected behaviour in which Computed attributes with null config values would force resource recreation whenever updated by the provider.

Should fix #187.

Needs careful testing.

The following conditions must now be met in order for the RequiresReplace helpers to set RequiresReplace on the attribute:

- The planned value must not be equal to the current state.
- The config value must not be null.

This more closely mirrors the ForceNew behaviour in SDKv2, and corrects unexpected behaviour in which Computed attributes with null config values would force resource recreation whenever updated by the provider.
paddycarver added a commit that referenced this pull request Oct 27, 2021
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.
@paddycarver
Copy link
Contributor

Superseded by #213.

paddycarver added a commit that referenced this pull request Oct 28, 2021
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.
paddycarver added a commit that referenced this pull request Nov 3, 2021
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.
paddycarver added a commit that referenced this pull request Nov 3, 2021
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.
paddycarver added a commit that referenced this pull request Nov 3, 2021
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>
@github-actions
Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active contributions.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 27, 2021
@bflad bflad deleted the kmoe-requiresreplace-conditional branch January 11, 2023 17:33
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Strange behavior with Computed attributes after v0.4.2 upgrade
3 participants