1package terraform
2
3import (
4	"log"
5
6	"github.com/hashicorp/terraform/states"
7	"github.com/hashicorp/terraform/tfdiags"
8
9	"github.com/hashicorp/terraform/addrs"
10	"github.com/hashicorp/terraform/configs"
11	"github.com/hashicorp/terraform/dag"
12)
13
14// RefreshGraphBuilder implements GraphBuilder and is responsible for building
15// a graph for refreshing (updating the Terraform state).
16//
17// The primary difference between this graph and others:
18//
19//   * Based on the state since it represents the only resources that
20//     need to be refreshed.
21//
22//   * Ignores lifecycle options since no lifecycle events occur here. This
23//     simplifies the graph significantly since complex transforms such as
24//     create-before-destroy can be completely ignored.
25//
26type RefreshGraphBuilder struct {
27	// Config is the configuration tree.
28	Config *configs.Config
29
30	// State is the prior state
31	State *states.State
32
33	// Components is a factory for the plug-in components (providers and
34	// provisioners) available for use.
35	Components contextComponentFactory
36
37	// Schemas is the repository of schemas we will draw from to analyse
38	// the configuration.
39	Schemas *Schemas
40
41	// Targets are resources to target
42	Targets []addrs.Targetable
43
44	// DisableReduce, if true, will not reduce the graph. Great for testing.
45	DisableReduce bool
46
47	// Validate will do structural validation of the graph.
48	Validate bool
49}
50
51// See GraphBuilder
52func (b *RefreshGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
53	return (&BasicGraphBuilder{
54		Steps:    b.Steps(),
55		Validate: b.Validate,
56		Name:     "RefreshGraphBuilder",
57	}).Build(path)
58}
59
60// See GraphBuilder
61func (b *RefreshGraphBuilder) Steps() []GraphTransformer {
62	// Custom factory for creating providers.
63	concreteProvider := func(a *NodeAbstractProvider) dag.Vertex {
64		return &NodeApplyableProvider{
65			NodeAbstractProvider: a,
66		}
67	}
68
69	concreteManagedResource := func(a *NodeAbstractResource) dag.Vertex {
70		return &NodeRefreshableManagedResource{
71			NodeAbstractResource: a,
72		}
73	}
74
75	concreteManagedResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex {
76		return &NodeRefreshableManagedResourceInstance{
77			NodeAbstractResourceInstance: a,
78		}
79	}
80
81	concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex {
82		// The "Plan" node type also handles refreshing behavior.
83		return &NodePlanDeposedResourceInstanceObject{
84			NodeAbstractResourceInstance: a,
85			DeposedKey:                   key,
86		}
87	}
88
89	concreteDataResource := func(a *NodeAbstractResource) dag.Vertex {
90		return &NodeRefreshableDataResource{
91			NodeAbstractResource: a,
92		}
93	}
94
95	steps := []GraphTransformer{
96		// Creates all the managed resources that aren't in the state, but only if
97		// we have a state already. No resources in state means there's not
98		// anything to refresh.
99		func() GraphTransformer {
100			if b.State.HasResources() {
101				return &ConfigTransformer{
102					Concrete:   concreteManagedResource,
103					Config:     b.Config,
104					Unique:     true,
105					ModeFilter: true,
106					Mode:       addrs.ManagedResourceMode,
107				}
108			}
109			log.Println("[TRACE] No managed resources in state during refresh; skipping managed resource transformer")
110			return nil
111		}(),
112
113		// Creates all the data resources that aren't in the state. This will also
114		// add any orphans from scaling in as destroy nodes.
115		&ConfigTransformer{
116			Concrete:   concreteDataResource,
117			Config:     b.Config,
118			Unique:     true,
119			ModeFilter: true,
120			Mode:       addrs.DataResourceMode,
121		},
122
123		// Add any fully-orphaned resources from config (ones that have been
124		// removed completely, not ones that are just orphaned due to a scaled-in
125		// count.
126		&OrphanResourceInstanceTransformer{
127			Concrete: concreteManagedResourceInstance,
128			State:    b.State,
129			Config:   b.Config,
130		},
131
132		// We also need nodes for any deposed instance objects present in the
133		// state, so we can check if they still exist. (This intentionally
134		// skips creating nodes for _current_ objects, since ConfigTransformer
135		// created nodes that will do that during DynamicExpand.)
136		&StateTransformer{
137			ConcreteDeposed: concreteResourceInstanceDeposed,
138			State:           b.State,
139		},
140
141		// Attach the state
142		&AttachStateTransformer{State: b.State},
143
144		// Attach the configuration to any resources
145		&AttachResourceConfigTransformer{Config: b.Config},
146
147		// Add root variables
148		&RootVariableTransformer{Config: b.Config},
149
150		// Add the local values
151		&LocalTransformer{Config: b.Config},
152
153		// Add the outputs
154		&OutputTransformer{Config: b.Config},
155
156		// Add module variables
157		&ModuleVariableTransformer{Config: b.Config},
158
159		TransformProviders(b.Components.ResourceProviders(), concreteProvider, b.Config),
160
161		// Must attach schemas before ReferenceTransformer so that we can
162		// analyze the configuration to find references.
163		&AttachSchemaTransformer{Schemas: b.Schemas},
164
165		// Connect so that the references are ready for targeting. We'll
166		// have to connect again later for providers and so on.
167		&ReferenceTransformer{},
168
169		// Target
170		&TargetsTransformer{
171			Targets: b.Targets,
172
173			// Resource nodes from config have not yet been expanded for
174			// "count", so we must apply targeting without indices. Exact
175			// targeting will be dealt with later when these resources
176			// DynamicExpand.
177			IgnoreIndices: true,
178		},
179
180		// Close opened plugin connections
181		&CloseProviderTransformer{},
182
183		// Single root
184		&RootTransformer{},
185	}
186
187	if !b.DisableReduce {
188		// Perform the transitive reduction to make our graph a bit
189		// more sane if possible (it usually is possible).
190		steps = append(steps, &TransitiveReductionTransformer{})
191	}
192
193	return steps
194}
195