aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/terraform/graph_builder_refresh.go
blob: 0634f9698d8fe7715f698af5b1c08dfc01a6c68c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package terraform

import (
	"log"

	"github.com/hashicorp/terraform/config"
	"github.com/hashicorp/terraform/config/module"
	"github.com/hashicorp/terraform/dag"
)

// RefreshGraphBuilder implements GraphBuilder and is responsible for building
// a graph for refreshing (updating the Terraform state).
//
// The primary difference between this graph and others:
//
//   * Based on the state since it represents the only resources that
//     need to be refreshed.
//
//   * Ignores lifecycle options since no lifecycle events occur here. This
//     simplifies the graph significantly since complex transforms such as
//     create-before-destroy can be completely ignored.
//
type RefreshGraphBuilder struct {
	// Module is the root module for the graph to build.
	Module *module.Tree

	// State is the current state
	State *State

	// Providers is the list of providers supported.
	Providers []string

	// Targets are resources to target
	Targets []string

	// DisableReduce, if true, will not reduce the graph. Great for testing.
	DisableReduce bool

	// Validate will do structural validation of the graph.
	Validate bool
}

// See GraphBuilder
func (b *RefreshGraphBuilder) Build(path []string) (*Graph, error) {
	return (&BasicGraphBuilder{
		Steps:    b.Steps(),
		Validate: b.Validate,
		Name:     "RefreshGraphBuilder",
	}).Build(path)
}

// See GraphBuilder
func (b *RefreshGraphBuilder) Steps() []GraphTransformer {
	// Custom factory for creating providers.
	concreteProvider := func(a *NodeAbstractProvider) dag.Vertex {
		return &NodeApplyableProvider{
			NodeAbstractProvider: a,
		}
	}

	concreteManagedResource := func(a *NodeAbstractResource) dag.Vertex {
		return &NodeRefreshableManagedResource{
			NodeAbstractCountResource: &NodeAbstractCountResource{
				NodeAbstractResource: a,
			},
		}
	}

	concreteManagedResourceInstance := func(a *NodeAbstractResource) dag.Vertex {
		return &NodeRefreshableManagedResourceInstance{
			NodeAbstractResource: a,
		}
	}

	concreteDataResource := func(a *NodeAbstractResource) dag.Vertex {
		return &NodeRefreshableDataResource{
			NodeAbstractCountResource: &NodeAbstractCountResource{
				NodeAbstractResource: a,
			},
		}
	}

	steps := []GraphTransformer{
		// Creates all the managed resources that aren't in the state, but only if
		// we have a state already. No resources in state means there's not
		// anything to refresh.
		func() GraphTransformer {
			if b.State.HasResources() {
				return &ConfigTransformer{
					Concrete:   concreteManagedResource,
					Module:     b.Module,
					Unique:     true,
					ModeFilter: true,
					Mode:       config.ManagedResourceMode,
				}
			}
			log.Println("[TRACE] No managed resources in state during refresh, skipping managed resource transformer")
			return nil
		}(),

		// Creates all the data resources that aren't in the state. This will also
		// add any orphans from scaling in as destroy nodes.
		&ConfigTransformer{
			Concrete:   concreteDataResource,
			Module:     b.Module,
			Unique:     true,
			ModeFilter: true,
			Mode:       config.DataResourceMode,
		},

		// Add any fully-orphaned resources from config (ones that have been
		// removed completely, not ones that are just orphaned due to a scaled-in
		// count.
		&OrphanResourceTransformer{
			Concrete: concreteManagedResourceInstance,
			State:    b.State,
			Module:   b.Module,
		},

		// Attach the state
		&AttachStateTransformer{State: b.State},

		// Attach the configuration to any resources
		&AttachResourceConfigTransformer{Module: b.Module},

		// Add root variables
		&RootVariableTransformer{Module: b.Module},

		// Create all the providers
		&MissingProviderTransformer{Providers: b.Providers, Concrete: concreteProvider},
		&ProviderTransformer{},
		&DisableProviderTransformer{},
		&ParentProviderTransformer{},
		&AttachProviderConfigTransformer{Module: b.Module},

		// Add the outputs
		&OutputTransformer{Module: b.Module},

		// Add module variables
		&ModuleVariableTransformer{Module: b.Module},

		// Connect so that the references are ready for targeting. We'll
		// have to connect again later for providers and so on.
		&ReferenceTransformer{},

		// Target
		&TargetsTransformer{Targets: b.Targets},

		// Close opened plugin connections
		&CloseProviderTransformer{},

		// Single root
		&RootTransformer{},
	}

	if !b.DisableReduce {
		// Perform the transitive reduction to make our graph a bit
		// more sane if possible (it usually is possible).
		steps = append(steps, &TransitiveReductionTransformer{})
	}

	return steps
}