]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/terraform/transform_import_state.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / transform_import_state.go
1 package terraform
2
3 import (
4 "fmt"
5
6 "github.com/hashicorp/terraform/addrs"
7 "github.com/hashicorp/terraform/providers"
8 "github.com/hashicorp/terraform/tfdiags"
9 )
10
11 // ImportStateTransformer is a GraphTransformer that adds nodes to the
12 // graph to represent the imports we want to do for resources.
13 type ImportStateTransformer struct {
14 Targets []*ImportTarget
15 }
16
17 func (t *ImportStateTransformer) Transform(g *Graph) error {
18 for _, target := range t.Targets {
19 // The ProviderAddr may not be supplied for non-aliased providers.
20 // This will be populated if the targets come from the cli, but tests
21 // may not specify implied provider addresses.
22 providerAddr := target.ProviderAddr
23 if providerAddr.ProviderConfig.Type == "" {
24 providerAddr = target.Addr.Resource.Resource.DefaultProviderConfig().Absolute(target.Addr.Module)
25 }
26
27 node := &graphNodeImportState{
28 Addr: target.Addr,
29 ID: target.ID,
30 ProviderAddr: providerAddr,
31 }
32 g.Add(node)
33 }
34 return nil
35 }
36
37 type graphNodeImportState struct {
38 Addr addrs.AbsResourceInstance // Addr is the resource address to import into
39 ID string // ID is the ID to import as
40 ProviderAddr addrs.AbsProviderConfig // Provider address given by the user, or implied by the resource type
41 ResolvedProvider addrs.AbsProviderConfig // provider node address after resolution
42
43 states []providers.ImportedResource
44 }
45
46 var (
47 _ GraphNodeSubPath = (*graphNodeImportState)(nil)
48 _ GraphNodeEvalable = (*graphNodeImportState)(nil)
49 _ GraphNodeProviderConsumer = (*graphNodeImportState)(nil)
50 _ GraphNodeDynamicExpandable = (*graphNodeImportState)(nil)
51 )
52
53 func (n *graphNodeImportState) Name() string {
54 return fmt.Sprintf("%s (import id %q)", n.Addr, n.ID)
55 }
56
57 // GraphNodeProviderConsumer
58 func (n *graphNodeImportState) ProvidedBy() (addrs.AbsProviderConfig, bool) {
59 // We assume that n.ProviderAddr has been properly populated here.
60 // It's the responsibility of the code creating a graphNodeImportState
61 // to populate this, possibly by calling DefaultProviderConfig() on the
62 // resource address to infer an implied provider from the resource type
63 // name.
64 return n.ProviderAddr, false
65 }
66
67 // GraphNodeProviderConsumer
68 func (n *graphNodeImportState) SetProvider(addr addrs.AbsProviderConfig) {
69 n.ResolvedProvider = addr
70 }
71
72 // GraphNodeSubPath
73 func (n *graphNodeImportState) Path() addrs.ModuleInstance {
74 return n.Addr.Module
75 }
76
77 // GraphNodeEvalable impl.
78 func (n *graphNodeImportState) EvalTree() EvalNode {
79 var provider providers.Interface
80
81 // Reset our states
82 n.states = nil
83
84 // Return our sequence
85 return &EvalSequence{
86 Nodes: []EvalNode{
87 &EvalGetProvider{
88 Addr: n.ResolvedProvider,
89 Output: &provider,
90 },
91 &EvalImportState{
92 Addr: n.Addr.Resource,
93 Provider: &provider,
94 ID: n.ID,
95 Output: &n.states,
96 },
97 },
98 }
99 }
100
101 // GraphNodeDynamicExpandable impl.
102 //
103 // We use DynamicExpand as a way to generate the subgraph of refreshes
104 // and state inserts we need to do for our import state. Since they're new
105 // resources they don't depend on anything else and refreshes are isolated
106 // so this is nearly a perfect use case for dynamic expand.
107 func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) {
108 var diags tfdiags.Diagnostics
109
110 g := &Graph{Path: ctx.Path()}
111
112 // nameCounter is used to de-dup names in the state.
113 nameCounter := make(map[string]int)
114
115 // Compile the list of addresses that we'll be inserting into the state.
116 // We do this ahead of time so we can verify that we aren't importing
117 // something that already exists.
118 addrs := make([]addrs.AbsResourceInstance, len(n.states))
119 for i, state := range n.states {
120 addr := n.Addr
121 if t := state.TypeName; t != "" {
122 addr.Resource.Resource.Type = t
123 }
124
125 // Determine if we need to suffix the name to de-dup
126 key := addr.String()
127 count, ok := nameCounter[key]
128 if ok {
129 count++
130 addr.Resource.Resource.Name += fmt.Sprintf("-%d", count)
131 }
132 nameCounter[key] = count
133
134 // Add it to our list
135 addrs[i] = addr
136 }
137
138 // Verify that all the addresses are clear
139 state := ctx.State()
140 for _, addr := range addrs {
141 existing := state.ResourceInstance(addr)
142 if existing != nil {
143 diags = diags.Append(tfdiags.Sourceless(
144 tfdiags.Error,
145 "Resource already managed by Terraform",
146 fmt.Sprintf("Terraform is already managing a remote object for %s. To import to this address you must first remove the existing object from the state.", addr),
147 ))
148 continue
149 }
150 }
151 if diags.HasErrors() {
152 // Bail out early, then.
153 return nil, diags.Err()
154 }
155
156 // For each of the states, we add a node to handle the refresh/add to state.
157 // "n.states" is populated by our own EvalTree with the result of
158 // ImportState. Since DynamicExpand is always called after EvalTree, this
159 // is safe.
160 for i, state := range n.states {
161 g.Add(&graphNodeImportStateSub{
162 TargetAddr: addrs[i],
163 State: state,
164 ResolvedProvider: n.ResolvedProvider,
165 })
166 }
167
168 // Root transform for a single root
169 t := &RootTransformer{}
170 if err := t.Transform(g); err != nil {
171 return nil, err
172 }
173
174 // Done!
175 return g, diags.Err()
176 }
177
178 // graphNodeImportStateSub is the sub-node of graphNodeImportState
179 // and is part of the subgraph. This node is responsible for refreshing
180 // and adding a resource to the state once it is imported.
181 type graphNodeImportStateSub struct {
182 TargetAddr addrs.AbsResourceInstance
183 State providers.ImportedResource
184 ResolvedProvider addrs.AbsProviderConfig
185 }
186
187 var (
188 _ GraphNodeSubPath = (*graphNodeImportStateSub)(nil)
189 _ GraphNodeEvalable = (*graphNodeImportStateSub)(nil)
190 )
191
192 func (n *graphNodeImportStateSub) Name() string {
193 return fmt.Sprintf("import %s result", n.TargetAddr)
194 }
195
196 func (n *graphNodeImportStateSub) Path() addrs.ModuleInstance {
197 return n.TargetAddr.Module
198 }
199
200 // GraphNodeEvalable impl.
201 func (n *graphNodeImportStateSub) EvalTree() EvalNode {
202 // If the Ephemeral type isn't set, then it is an error
203 if n.State.TypeName == "" {
204 err := fmt.Errorf("import of %s didn't set type", n.TargetAddr.String())
205 return &EvalReturnError{Error: &err}
206 }
207
208 state := n.State.AsInstanceObject()
209
210 var provider providers.Interface
211 var providerSchema *ProviderSchema
212 return &EvalSequence{
213 Nodes: []EvalNode{
214 &EvalGetProvider{
215 Addr: n.ResolvedProvider,
216 Output: &provider,
217 Schema: &providerSchema,
218 },
219 &EvalRefresh{
220 Addr: n.TargetAddr.Resource,
221 ProviderAddr: n.ResolvedProvider,
222 Provider: &provider,
223 ProviderSchema: &providerSchema,
224 State: &state,
225 Output: &state,
226 },
227 &EvalImportStateVerify{
228 Addr: n.TargetAddr.Resource,
229 State: &state,
230 },
231 &EvalWriteState{
232 Addr: n.TargetAddr.Resource,
233 ProviderAddr: n.ResolvedProvider,
234 ProviderSchema: &providerSchema,
235 State: &state,
236 },
237 },
238 }
239 }