]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/terraform/transform_orphan_resource.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / transform_orphan_resource.go
CommitLineData
bae9f6d2
JC
1package terraform
2
3import (
107c1cdb
ND
4 "log"
5
6 "github.com/hashicorp/terraform/configs"
bae9f6d2 7 "github.com/hashicorp/terraform/dag"
107c1cdb 8 "github.com/hashicorp/terraform/states"
bae9f6d2
JC
9)
10
107c1cdb
ND
11// OrphanResourceInstanceTransformer is a GraphTransformer that adds orphaned
12// resource instances to the graph. An "orphan" is an instance that is present
13// in the state but belongs to a resource that is no longer present in the
bae9f6d2 14// configuration.
107c1cdb
ND
15//
16// This is not the transformer that deals with "count orphans" (instances that
17// are no longer covered by a resource's "count" or "for_each" setting); that's
18// handled instead by OrphanResourceCountTransformer.
19type OrphanResourceInstanceTransformer struct {
20 Concrete ConcreteResourceInstanceNodeFunc
bae9f6d2
JC
21
22 // State is the global state. We require the global state to
23 // properly find module orphans at our path.
107c1cdb 24 State *states.State
bae9f6d2 25
107c1cdb
ND
26 // Config is the root node in the configuration tree. We'll look up
27 // the appropriate note in this tree using the path in each node.
28 Config *configs.Config
bae9f6d2
JC
29}
30
107c1cdb 31func (t *OrphanResourceInstanceTransformer) Transform(g *Graph) error {
bae9f6d2
JC
32 if t.State == nil {
33 // If the entire state is nil, there can't be any orphans
34 return nil
35 }
107c1cdb
ND
36 if t.Config == nil {
37 // Should never happen: we can't be doing any Terraform operations
38 // without at least an empty configuration.
39 panic("OrphanResourceInstanceTransformer used without setting Config")
40 }
bae9f6d2
JC
41
42 // Go through the modules and for each module transform in order
43 // to add the orphan.
44 for _, ms := range t.State.Modules {
45 if err := t.transform(g, ms); err != nil {
46 return err
47 }
48 }
49
50 return nil
51}
52
107c1cdb 53func (t *OrphanResourceInstanceTransformer) transform(g *Graph, ms *states.Module) error {
bae9f6d2
JC
54 if ms == nil {
55 return nil
56 }
57
107c1cdb
ND
58 moduleAddr := ms.Addr
59
60 // Get the configuration for this module. The configuration might be
bae9f6d2
JC
61 // nil if the module was removed from the configuration. This is okay,
62 // this just means that every resource is an orphan.
107c1cdb
ND
63 var m *configs.Module
64 if c := t.Config.DescendentForInstance(moduleAddr); c != nil {
65 m = c.Module
bae9f6d2
JC
66 }
67
107c1cdb
ND
68 // An "orphan" is a resource that is in the state but not the configuration,
69 // so we'll walk the state resources and try to correlate each of them
70 // with a configuration block. Each orphan gets a node in the graph whose
71 // type is decided by t.Concrete.
72 //
73 // We don't handle orphans related to changes in the "count" and "for_each"
74 // pseudo-arguments here. They are handled by OrphanResourceCountTransformer.
75 for _, rs := range ms.Resources {
76 if m != nil {
77 if r := m.ResourceByAddr(rs.Addr); r != nil {
78 continue
79 }
bae9f6d2 80 }
bae9f6d2 81
107c1cdb
ND
82 for key := range rs.Instances {
83 addr := rs.Addr.Instance(key).Absolute(moduleAddr)
84 abstract := NewNodeAbstractResourceInstance(addr)
85 var node dag.Vertex = abstract
86 if f := t.Concrete; f != nil {
87 node = f(abstract)
88 }
89 log.Printf("[TRACE] OrphanResourceInstanceTransformer: adding single-instance orphan node for %s", addr)
90 g.Add(node)
bae9f6d2 91 }
107c1cdb
ND
92 }
93
94 return nil
95}
96
97// OrphanResourceTransformer is a GraphTransformer that adds orphaned
98// resources to the graph. An "orphan" is a resource that is present in
99// the state but no longer present in the config.
100//
101// This is separate to OrphanResourceInstanceTransformer in that it deals with
102// whole resources, rather than individual instances of resources. Orphan
103// resource nodes are only used during apply to clean up leftover empty
104// resource state skeletons, after all of the instances inside have been
105// removed.
106//
107// This transformer will also create edges in the graph to any pre-existing
108// node that creates or destroys the entire orphaned resource or any of its
109// instances, to ensure that the "orphan-ness" of a resource is always dealt
110// with after all other aspects of it.
111type OrphanResourceTransformer struct {
112 Concrete ConcreteResourceNodeFunc
113
114 // State is the global state.
115 State *states.State
bae9f6d2 116
107c1cdb
ND
117 // Config is the root node in the configuration tree.
118 Config *configs.Config
119}
120
121func (t *OrphanResourceTransformer) Transform(g *Graph) error {
122 if t.State == nil {
123 // If the entire state is nil, there can't be any orphans
124 return nil
125 }
126 if t.Config == nil {
127 // Should never happen: we can't be doing any Terraform operations
128 // without at least an empty configuration.
129 panic("OrphanResourceTransformer used without setting Config")
130 }
131
132 // We'll first collect up the existing nodes for each resource so we can
133 // create dependency edges for any new nodes we create.
134 deps := map[string][]dag.Vertex{}
135 for _, v := range g.Vertices() {
136 switch tv := v.(type) {
137 case GraphNodeResourceInstance:
138 k := tv.ResourceInstanceAddr().ContainingResource().String()
139 deps[k] = append(deps[k], v)
140 case GraphNodeResource:
141 k := tv.ResourceAddr().String()
142 deps[k] = append(deps[k], v)
143 case GraphNodeDestroyer:
144 k := tv.DestroyAddr().ContainingResource().String()
145 deps[k] = append(deps[k], v)
146 }
147 }
148
149 for _, ms := range t.State.Modules {
150 moduleAddr := ms.Addr
151
152 mc := t.Config.DescendentForInstance(moduleAddr) // might be nil if whole module has been removed
153
154 for _, rs := range ms.Resources {
155 if mc != nil {
156 if r := mc.Module.ResourceByAddr(rs.Addr); r != nil {
157 // It's in the config, so nothing to do for this one.
158 continue
159 }
160 }
161
162 addr := rs.Addr.Absolute(moduleAddr)
163 abstract := NewNodeAbstractResource(addr)
164 var node dag.Vertex = abstract
165 if f := t.Concrete; f != nil {
166 node = f(abstract)
167 }
168 log.Printf("[TRACE] OrphanResourceTransformer: adding whole-resource orphan node for %s", addr)
169 g.Add(node)
170 for _, dn := range deps[addr.String()] {
171 log.Printf("[TRACE] OrphanResourceTransformer: node %q depends on %q", dag.VertexName(node), dag.VertexName(dn))
172 g.Connect(dag.BasicEdge(node, dn))
173 }
174 }
bae9f6d2
JC
175 }
176
177 return nil
107c1cdb 178
bae9f6d2 179}