Skip to content

Commit e97ae28

Browse files
committed
Combine all plan graphs, including import
Combine all plan-time graphs into a single graph builder, because _everything is a plan_! Convert the import graph to a plan graph. This should resolve a few edge cases about things not being properly evaluated during import, and takes a step towards being able to _plan_ an import.
1 parent 93ff272 commit e97ae28

14 files changed

Lines changed: 150 additions & 187 deletions

‎internal/terraform/context_import.go‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,14 @@ func (c *Context) Import(config *configs.Config, prevRunState *states.State, opt
5656
variables := opts.SetVariables
5757

5858
// Initialize our graph builder
59-
builder := &ImportGraphBuilder{
59+
builder := &PlanGraphBuilder{
6060
ImportTargets: opts.Targets,
6161
Config: config,
62+
State: state,
6263
RootVariableValues: variables,
6364
Plugins: c.plugins,
65+
skipRefresh: true,
66+
Operation: walkImport,
6467
}
6568

6669
// Build the graph

‎internal/terraform/context_plan.go‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ func (c *Context) planGraph(config *configs.Config, prevRunState *states.State,
560560
Targets: opts.Targets,
561561
ForceReplace: opts.ForceReplace,
562562
skipRefresh: opts.SkipRefresh,
563+
Operation: walkPlan,
563564
}).Build(addrs.RootModuleInstance)
564565
return graph, walkPlan, diags
565566
case plans.RefreshOnlyMode:
@@ -571,16 +572,18 @@ func (c *Context) planGraph(config *configs.Config, prevRunState *states.State,
571572
Targets: opts.Targets,
572573
skipRefresh: opts.SkipRefresh,
573574
skipPlanChanges: true, // this activates "refresh only" mode.
575+
Operation: walkPlan,
574576
}).Build(addrs.RootModuleInstance)
575577
return graph, walkPlan, diags
576578
case plans.DestroyMode:
577-
graph, diags := DestroyPlanGraphBuilder(&PlanGraphBuilder{
579+
graph, diags := (&PlanGraphBuilder{
578580
Config: config,
579581
State: prevRunState,
580582
RootVariableValues: opts.SetVariables,
581583
Plugins: c.plugins,
582584
Targets: opts.Targets,
583585
skipRefresh: opts.SkipRefresh,
586+
Operation: walkPlanDestroy,
584587
}).Build(addrs.RootModuleInstance)
585588
return graph, walkPlanDestroy, diags
586589
default:

‎internal/terraform/context_validate.go‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,12 @@ func (c *Context) Validate(config *configs.Config) tfdiags.Diagnostics {
5555
}
5656
}
5757

58-
graph, moreDiags := ValidateGraphBuilder(&PlanGraphBuilder{
58+
graph, moreDiags := (&PlanGraphBuilder{
5959
Config: config,
6060
Plugins: c.plugins,
6161
State: states.NewState(),
6262
RootVariableValues: varValues,
63+
Operation: walkValidate,
6364
}).Build(addrs.RootModuleInstance)
6465
diags = diags.Append(moreDiags)
6566
if moreDiags.HasErrors() {

‎internal/terraform/context_walk.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func (c *Context) graphWalker(operation walkOperation, opts *graphWalkOpts) *Con
7373
refreshState = states.NewState().SyncWrapper()
7474
prevRunState = states.NewState().SyncWrapper()
7575

76-
case walkPlan, walkPlanDestroy:
76+
case walkPlan, walkPlanDestroy, walkImport:
7777
state = inputState.DeepCopy().SyncWrapper()
7878
refreshState = inputState.DeepCopy().SyncWrapper()
7979
prevRunState = inputState.DeepCopy().SyncWrapper()

‎internal/terraform/graph_builder_destroy_plan.go‎

Lines changed: 0 additions & 17 deletions
This file was deleted.

‎internal/terraform/graph_builder_import.go‎

Lines changed: 0 additions & 101 deletions
This file was deleted.

‎internal/terraform/graph_builder_plan.go‎

Lines changed: 88 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package terraform
22

33
import (
4+
"log"
5+
46
"github.com/hashicorp/terraform/internal/addrs"
57
"github.com/hashicorp/terraform/internal/configs"
68
"github.com/hashicorp/terraform/internal/dag"
@@ -63,12 +65,16 @@ type PlanGraphBuilder struct {
6365
ConcreteResourceInstanceDeposed ConcreteResourceInstanceDeposedNodeFunc
6466
ConcreteModule ConcreteModuleNodeFunc
6567

66-
// destroy is set to true when create a full destroy plan.
67-
destroy bool
68+
// Plan Operation this graph will be used for.
69+
Operation walkOperation
70+
71+
// ImportTargets are the list of resources to import.
72+
ImportTargets []*ImportTarget
6873
}
6974

7075
// See GraphBuilder
7176
func (b *PlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
77+
log.Printf("[TRACE] building graph for %s", b.Operation)
7278
return (&BasicGraphBuilder{
7379
Steps: b.Steps(),
7480
Name: "PlanGraphBuilder",
@@ -77,14 +83,29 @@ func (b *PlanGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Dia
7783

7884
// See GraphBuilder
7985
func (b *PlanGraphBuilder) Steps() []GraphTransformer {
80-
b.init()
86+
switch b.Operation {
87+
case walkPlan:
88+
b.initPlan()
89+
case walkPlanDestroy:
90+
b.initDestroy()
91+
case walkValidate:
92+
b.initValidate()
93+
case walkImport:
94+
b.initImport()
95+
default:
96+
panic("invalid plan operation: " + b.Operation.String())
97+
}
8198

8299
steps := []GraphTransformer{
83100
// Creates all the resources represented in the config
84101
&ConfigTransformer{
85102
Concrete: b.ConcreteResource,
86103
Config: b.Config,
87-
skip: b.destroy,
104+
105+
// Resources are not added from the config on destroy.
106+
skip: b.Operation == walkPlanDestroy,
107+
108+
importTargets: b.ImportTargets,
88109
},
89110

90111
// Add dynamic values
@@ -94,21 +115,22 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
94115
&OutputTransformer{
95116
Config: b.Config,
96117
RefreshOnly: b.skipPlanChanges,
97-
removeRootOutputs: b.destroy,
118+
removeRootOutputs: b.Operation == walkPlanDestroy,
98119
},
99120

100121
// Add orphan resources
101122
&OrphanResourceInstanceTransformer{
102123
Concrete: b.ConcreteResourceOrphan,
103124
State: b.State,
104125
Config: b.Config,
105-
skip: b.destroy,
126+
skip: b.Operation == walkPlanDestroy,
106127
},
107128

108129
// We also need nodes for any deposed instance objects present in the
109-
// state, so we can plan to destroy them. (This intentionally
110-
// skips creating nodes for _current_ objects, since ConfigTransformer
111-
// created nodes that will do that during DynamicExpand.)
130+
// state, so we can plan to destroy them. (During plan this will
131+
// intentionally skips creating nodes for _current_ objects, since
132+
// ConfigTransformer created nodes that will do that during
133+
// DynamicExpand.)
112134
&StateTransformer{
113135
ConcreteCurrent: b.ConcreteResourceInstance,
114136
ConcreteDeposed: b.ConcreteResourceInstanceDeposed,
@@ -172,12 +194,7 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
172194
return steps
173195
}
174196

175-
func (b *PlanGraphBuilder) init() {
176-
// Do nothing if the user requests customizing the fields
177-
if b.CustomConcrete {
178-
return
179-
}
180-
197+
func (b *PlanGraphBuilder) initPlan() {
181198
b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
182199
return &NodeApplyableProvider{
183200
NodeAbstractProvider: a,
@@ -210,5 +227,61 @@ func (b *PlanGraphBuilder) init() {
210227
skipPlanChanges: b.skipPlanChanges,
211228
}
212229
}
230+
}
231+
232+
func (b *PlanGraphBuilder) initDestroy() {
233+
b.initPlan()
234+
235+
b.ConcreteResourceInstance = func(a *NodeAbstractResourceInstance) dag.Vertex {
236+
return &NodePlanDestroyableResourceInstance{
237+
NodeAbstractResourceInstance: a,
238+
skipRefresh: b.skipRefresh,
239+
}
240+
}
241+
}
213242

243+
func (b *PlanGraphBuilder) initValidate() {
244+
// Set the provider to the normal provider. This will ask for input.
245+
b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
246+
return &NodeApplyableProvider{
247+
NodeAbstractProvider: a,
248+
}
249+
}
250+
251+
b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
252+
return &NodeValidatableResource{
253+
NodeAbstractResource: a,
254+
}
255+
}
256+
257+
b.ConcreteModule = func(n *nodeExpandModule) dag.Vertex {
258+
return &nodeValidateModule{
259+
nodeExpandModule: *n,
260+
}
261+
}
262+
}
263+
264+
func (b *PlanGraphBuilder) initImport() {
265+
b.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
266+
return &NodeApplyableProvider{
267+
NodeAbstractProvider: a,
268+
}
269+
}
270+
271+
b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
272+
return &nodeExpandPlannableResource{
273+
NodeAbstractResource: a,
274+
275+
// For now we always skip planning changes for import, since we are
276+
// not going to combine importing with other changes. This is
277+
// temporary to try and maintain existing import behaviors, but
278+
// planning will need to be allowed for more complex configurations.
279+
skipPlanChanges: true,
280+
281+
// We also skip refresh for now, since the plan output is written
282+
// as the new state, and users are not expecting the import process
283+
// to update any other instances in state.
284+
skipRefresh: true,
285+
}
286+
}
214287
}

0 commit comments

Comments
 (0)