-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
Use plan graph builder for destroy #31163
Changes from all commits
b8e362d
e3a6e1f
d6f0d1e
6860596
77d1380
8fed14f
ec476af
e36ee75
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -574,7 +574,7 @@ func (c *Context) planGraph(config *configs.Config, prevRunState *states.State, | |
}).Build(addrs.RootModuleInstance) | ||
return graph, walkPlan, diags | ||
case plans.DestroyMode: | ||
graph, diags := (&DestroyPlanGraphBuilder{ | ||
graph, diags := DestroyPlanGraphBuilder(&PlanGraphBuilder{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be reasonable to make this be consistent with how we deal with I think I ended up leaving it in this odd shape where Of course fine to leave this for another day if it seems too risky, since it's just some further cleanup after all. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was following the pattern used by the validate graph, because I thought I would end up injecting more concrete functions that I ended using. I think as part of the follow up here we should get rid of both the validate and destroy builder entry points, and just make everything a plan ;) |
||
Config: config, | ||
State: prevRunState, | ||
RootVariableValues: opts.SetVariables, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,115 +1,17 @@ | ||
package terraform | ||
|
||
import ( | ||
"github.com/hashicorp/terraform/internal/addrs" | ||
"github.com/hashicorp/terraform/internal/configs" | ||
"github.com/hashicorp/terraform/internal/dag" | ||
"github.com/hashicorp/terraform/internal/states" | ||
"github.com/hashicorp/terraform/internal/tfdiags" | ||
) | ||
|
||
// DestroyPlanGraphBuilder implements GraphBuilder and is responsible for | ||
// planning a pure-destroy. | ||
// | ||
// Planning a pure destroy operation is simple because we can ignore most | ||
// ordering configuration and simply reverse the state. This graph mainly | ||
// exists for targeting, because we need to walk the destroy dependencies to | ||
// ensure we plan the required resources. Without the requirement for | ||
// targeting, the plan could theoretically be created directly from the state. | ||
type DestroyPlanGraphBuilder struct { | ||
// Config is the configuration tree to build the plan from. | ||
Config *configs.Config | ||
|
||
// State is the current state | ||
State *states.State | ||
|
||
// RootVariableValues are the raw input values for root input variables | ||
// given by the caller, which we'll resolve into final values as part | ||
// of the plan walk. | ||
RootVariableValues InputValues | ||
|
||
// Plugins is a library of plug-in components (providers and | ||
// provisioners) available for use. | ||
Plugins *contextPlugins | ||
|
||
// Targets are resources to target | ||
Targets []addrs.Targetable | ||
|
||
// If set, skipRefresh will cause us stop skip refreshing any existing | ||
// resource instances as part of our planning. This will cause us to fail | ||
// to detect if an object has already been deleted outside of Terraform. | ||
skipRefresh bool | ||
} | ||
|
||
// See GraphBuilder | ||
func (b *DestroyPlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) { | ||
return (&BasicGraphBuilder{ | ||
Steps: b.Steps(), | ||
Name: "DestroyPlanGraphBuilder", | ||
}).Build(path) | ||
} | ||
|
||
// See GraphBuilder | ||
func (b *DestroyPlanGraphBuilder) Steps() []GraphTransformer { | ||
concreteResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex { | ||
func DestroyPlanGraphBuilder(p *PlanGraphBuilder) GraphBuilder { | ||
p.ConcreteResourceInstance = func(a *NodeAbstractResourceInstance) dag.Vertex { | ||
return &NodePlanDestroyableResourceInstance{ | ||
NodeAbstractResourceInstance: a, | ||
skipRefresh: b.skipRefresh, | ||
} | ||
} | ||
concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex { | ||
return &NodePlanDeposedResourceInstanceObject{ | ||
NodeAbstractResourceInstance: a, | ||
DeposedKey: key, | ||
skipRefresh: b.skipRefresh, | ||
} | ||
} | ||
|
||
concreteProvider := func(a *NodeAbstractProvider) dag.Vertex { | ||
return &NodeApplyableProvider{ | ||
NodeAbstractProvider: a, | ||
skipRefresh: p.skipRefresh, | ||
} | ||
} | ||
p.destroy = true | ||
|
||
steps := []GraphTransformer{ | ||
// Creates nodes for the resource instances tracked in the state. | ||
&StateTransformer{ | ||
ConcreteCurrent: concreteResourceInstance, | ||
ConcreteDeposed: concreteResourceInstanceDeposed, | ||
State: b.State, | ||
}, | ||
|
||
// Create the delete changes for root module outputs. | ||
&OutputTransformer{ | ||
Config: b.Config, | ||
Destroy: true, | ||
}, | ||
|
||
// Attach the state | ||
&AttachStateTransformer{State: b.State}, | ||
|
||
// Attach the configuration to any resources | ||
&AttachResourceConfigTransformer{Config: b.Config}, | ||
|
||
transformProviders(concreteProvider, b.Config), | ||
|
||
// Destruction ordering. We require this only so that | ||
// targeting below will prune the correct things. | ||
&DestroyEdgeTransformer{ | ||
Config: b.Config, | ||
State: b.State, | ||
}, | ||
|
||
&TargetsTransformer{Targets: b.Targets}, | ||
|
||
// Close opened plugin connections | ||
&CloseProviderTransformer{}, | ||
|
||
// Close the root module | ||
&CloseRootModuleTransformer{}, | ||
|
||
&TransitiveReductionTransformer{}, | ||
} | ||
|
||
return steps | ||
return p | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heh... this comment represents exactly what I thought when I first read through this test and saw that it's only testing that the plan succeeds, not that it succeeded for the right reason.
Did you
TODO
this because there's something blocking us from actually configuring the provider right now? My first instinct here was that it should be possible to checkotherProvider.ConfigureProviderResponse
after the plan succeeds, but probably there's some extra complexity here I'm not understanding! If so, it would be nice to capture that in this comment too so we can see what needs to be true in order for usTODO
what this comment says. 😀There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup, the provider still won't be configured yet, that will be enabled in a follow up PR. This was intended to be a drop-in replacement of the destroy plan graph with no change in behavior.