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

Configurable instance replacement via lifecycle replace_triggered_by #30900

Merged
merged 15 commits into from
Apr 22, 2022

Conversation

jbardin
Copy link
Member

@jbardin jbardin commented Apr 20, 2022

Add a replace_triggered_by option in the lifecycle meta block for managed resources, which can be used to couple the lifecycle of resources which may need to be replaced based on conditions in the configuration. References to other managed resources can be used to force replacement of the containing resource, acting similarly to triggers in the ubiquitous null_resource, a manual taint, or a plan -replace operation.

The replace_triggered_by argument is a list of pseudo-expressions which refer to other managed resources. The syntax is limited to resources, resource instances, and attributes of a resource instance. The only variable values allowed in the expression are count.index and each.key, which can be used to tie individual instances of expanded resources together.

The references in the argument list are not evaluated as we typically do within Terraform, rather they are used to lookup changes in the plan. If any of the references do correspond to a change, the containing resource will be planned to be replaced.

The steps for determining if a replace_triggered_by is going to force replacement are as follows:

  • Each expression provided is first split into the resource address and remaining attribute traversal. The address is used to locate the change (or changes in the case of multiple resource instances) in the plan.
  • If the reference is to a whole resource with multiple instances, any Update, DeleteThenCreate, or CreateThenDelete action on any instance will force replacement.
  • If the reference is to a resource instance with no remaining attribute traversal, a change action of Update, DeleteThenCreate, or CreateThenDelete will force replacement.
  • If there is a remaining attribute traversal and the change action is Update, DeleteThenCreate, or CreateThenDelete; then the before and after cty values of the change will be compared for equality. Unknown After values are considered a change in value for this purpose as well.

TODO: This initial implementation uses the existing mechanism in place for forced replacement (-replace=addr) to trigger the correct plan. The diff output will show that replace_triggered_by is the reason for replacement, but we may want to make a new mechanism for handing these replacements and a more specific message about the change in the diff output.

TODO: Cut a release of hcl before the RC.

Docs will be added in a separate PR.

Closes #8099
Closes #11418
Closes #22572
Closes #30210

Evaluate the expressions stored in replace_triggered_by into the
*addrs.Reference needed to lookup changes in the plan.
The EvalContext is the only place with all the information to be able to
complete the evaluation of the replace_triggered_by expressions. These
need to be evaluated into a reference, which is then looked up in the
pending changes which the context has access too. On top of needing the
plan changes, we also need access to all providers and schemas to decode
the changes if we need to traverse the resource values for individual
attributes.
The replace_triggered_by expressions create edges in the graph, so must
be returned in the References method.
Check for triggered resource replacement in the plan. While the
functionality of the feature works here, we ill want to follow up with a
way to indicate in the plan _why_ the resource was replaced.
Only immediate changes to the resource are considered.
replace_triggered_by references are scoped to the current module, so we
need to filter changes for the current module instance. Rather than
creating a ConfigResource and filtering the result, make a
Changes.InstancesForAbsResource method to get only the AbsResource
changes.
Set ResourceInstanceReplaceByTriggers in the change.
@jbardin jbardin requested a review from a team April 20, 2022 13:19
@jbardin jbardin self-assigned this Apr 20, 2022
Copy link
Contributor

@alisdair alisdair left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! I smoke tested locally and all I see in the diff is a couple of typos.

internal/configs/resource.go Outdated Show resolved Hide resolved
internal/terraform/node_resource_plan_instance.go Outdated Show resolved Hide resolved
@jbardin jbardin merged commit 7da52d9 into main Apr 22, 2022
@jbardin jbardin deleted the jbardin/replace-triggered-by branch April 22, 2022 18:36
@github-actions
Copy link

Reminder for the merging maintainer: if this is a user-visible change, please update the changelog on the appropriate release branch.

@OJFord
Copy link
Contributor

OJFord commented Apr 23, 2022

This is fantastic, thank you.

@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 May 24, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
3 participants