]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - 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
CommitLineData
bae9f6d2
JC
1package terraform
2
3import (
4 "fmt"
107c1cdb
ND
5
6 "github.com/hashicorp/terraform/addrs"
7 "github.com/hashicorp/terraform/providers"
8 "github.com/hashicorp/terraform/tfdiags"
bae9f6d2
JC
9)
10
11// ImportStateTransformer is a GraphTransformer that adds nodes to the
12// graph to represent the imports we want to do for resources.
13type ImportStateTransformer struct {
14 Targets []*ImportTarget
15}
16
17func (t *ImportStateTransformer) Transform(g *Graph) error {
bae9f6d2 18 for _, target := range t.Targets {
107c1cdb
ND
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)
bae9f6d2
JC
25 }
26
107c1cdb
ND
27 node := &graphNodeImportState{
28 Addr: target.Addr,
15c0b25d 29 ID: target.ID,
107c1cdb
ND
30 ProviderAddr: providerAddr,
31 }
32 g.Add(node)
bae9f6d2 33 }
bae9f6d2
JC
34 return nil
35}
36
37type graphNodeImportState struct {
107c1cdb
ND
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
bae9f6d2 42
107c1cdb 43 states []providers.ImportedResource
bae9f6d2
JC
44}
45
107c1cdb
ND
46var (
47 _ GraphNodeSubPath = (*graphNodeImportState)(nil)
48 _ GraphNodeEvalable = (*graphNodeImportState)(nil)
49 _ GraphNodeProviderConsumer = (*graphNodeImportState)(nil)
50 _ GraphNodeDynamicExpandable = (*graphNodeImportState)(nil)
51)
52
bae9f6d2 53func (n *graphNodeImportState) Name() string {
107c1cdb 54 return fmt.Sprintf("%s (import id %q)", n.Addr, n.ID)
bae9f6d2
JC
55}
56
107c1cdb
ND
57// GraphNodeProviderConsumer
58func (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
15c0b25d
AP
65}
66
107c1cdb
ND
67// GraphNodeProviderConsumer
68func (n *graphNodeImportState) SetProvider(addr addrs.AbsProviderConfig) {
69 n.ResolvedProvider = addr
bae9f6d2
JC
70}
71
72// GraphNodeSubPath
107c1cdb
ND
73func (n *graphNodeImportState) Path() addrs.ModuleInstance {
74 return n.Addr.Module
bae9f6d2
JC
75}
76
77// GraphNodeEvalable impl.
78func (n *graphNodeImportState) EvalTree() EvalNode {
107c1cdb 79 var provider providers.Interface
bae9f6d2
JC
80
81 // Reset our states
82 n.states = nil
83
84 // Return our sequence
85 return &EvalSequence{
86 Nodes: []EvalNode{
87 &EvalGetProvider{
107c1cdb 88 Addr: n.ResolvedProvider,
bae9f6d2
JC
89 Output: &provider,
90 },
91 &EvalImportState{
107c1cdb 92 Addr: n.Addr.Resource,
bae9f6d2 93 Provider: &provider,
107c1cdb 94 ID: n.ID,
bae9f6d2
JC
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.
107func (n *graphNodeImportState) DynamicExpand(ctx EvalContext) (*Graph, error) {
107c1cdb
ND
108 var diags tfdiags.Diagnostics
109
bae9f6d2
JC
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.
107c1cdb 118 addrs := make([]addrs.AbsResourceInstance, len(n.states))
bae9f6d2 119 for i, state := range n.states {
107c1cdb
ND
120 addr := n.Addr
121 if t := state.TypeName; t != "" {
122 addr.Resource.Resource.Type = t
bae9f6d2
JC
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++
107c1cdb 130 addr.Resource.Resource.Name += fmt.Sprintf("-%d", count)
bae9f6d2
JC
131 }
132 nameCounter[key] = count
133
134 // Add it to our list
107c1cdb 135 addrs[i] = addr
bae9f6d2
JC
136 }
137
138 // Verify that all the addresses are clear
107c1cdb 139 state := ctx.State()
bae9f6d2 140 for _, addr := range addrs {
107c1cdb
ND
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
bae9f6d2
JC
149 }
150 }
107c1cdb
ND
151 if diags.HasErrors() {
152 // Bail out early, then.
153 return nil, diags.Err()
154 }
bae9f6d2
JC
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{
107c1cdb 162 TargetAddr: addrs[i],
15c0b25d 163 State: state,
15c0b25d 164 ResolvedProvider: n.ResolvedProvider,
bae9f6d2
JC
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!
107c1cdb 175 return g, diags.Err()
bae9f6d2
JC
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.
181type graphNodeImportStateSub struct {
107c1cdb
ND
182 TargetAddr addrs.AbsResourceInstance
183 State providers.ImportedResource
184 ResolvedProvider addrs.AbsProviderConfig
bae9f6d2
JC
185}
186
107c1cdb
ND
187var (
188 _ GraphNodeSubPath = (*graphNodeImportStateSub)(nil)
189 _ GraphNodeEvalable = (*graphNodeImportStateSub)(nil)
190)
191
bae9f6d2 192func (n *graphNodeImportStateSub) Name() string {
107c1cdb 193 return fmt.Sprintf("import %s result", n.TargetAddr)
bae9f6d2
JC
194}
195
107c1cdb
ND
196func (n *graphNodeImportStateSub) Path() addrs.ModuleInstance {
197 return n.TargetAddr.Module
bae9f6d2
JC
198}
199
200// GraphNodeEvalable impl.
201func (n *graphNodeImportStateSub) EvalTree() EvalNode {
202 // If the Ephemeral type isn't set, then it is an error
107c1cdb
ND
203 if n.State.TypeName == "" {
204 err := fmt.Errorf("import of %s didn't set type", n.TargetAddr.String())
bae9f6d2
JC
205 return &EvalReturnError{Error: &err}
206 }
207
107c1cdb 208 state := n.State.AsInstanceObject()
bae9f6d2 209
107c1cdb
ND
210 var provider providers.Interface
211 var providerSchema *ProviderSchema
bae9f6d2
JC
212 return &EvalSequence{
213 Nodes: []EvalNode{
214 &EvalGetProvider{
107c1cdb 215 Addr: n.ResolvedProvider,
bae9f6d2 216 Output: &provider,
107c1cdb 217 Schema: &providerSchema,
bae9f6d2
JC
218 },
219 &EvalRefresh{
107c1cdb
ND
220 Addr: n.TargetAddr.Resource,
221 ProviderAddr: n.ResolvedProvider,
222 Provider: &provider,
223 ProviderSchema: &providerSchema,
224 State: &state,
225 Output: &state,
bae9f6d2
JC
226 },
227 &EvalImportStateVerify{
107c1cdb 228 Addr: n.TargetAddr.Resource,
bae9f6d2
JC
229 State: &state,
230 },
231 &EvalWriteState{
107c1cdb
ND
232 Addr: n.TargetAddr.Resource,
233 ProviderAddr: n.ResolvedProvider,
234 ProviderSchema: &providerSchema,
235 State: &state,
bae9f6d2
JC
236 },
237 },
238 }
239}