]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - 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
1 package terraform
2
3 import (
4 "log"
5
6 "github.com/hashicorp/terraform/configs"
7 "github.com/hashicorp/terraform/dag"
8 "github.com/hashicorp/terraform/states"
9 )
10
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
14 // configuration.
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.
19 type OrphanResourceInstanceTransformer struct {
20 Concrete ConcreteResourceInstanceNodeFunc
21
22 // State is the global state. We require the global state to
23 // properly find module orphans at our path.
24 State *states.State
25
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
29 }
30
31 func (t *OrphanResourceInstanceTransformer) Transform(g *Graph) error {
32 if t.State == nil {
33 // If the entire state is nil, there can't be any orphans
34 return nil
35 }
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 }
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
53 func (t *OrphanResourceInstanceTransformer) transform(g *Graph, ms *states.Module) error {
54 if ms == nil {
55 return nil
56 }
57
58 moduleAddr := ms.Addr
59
60 // Get the configuration for this module. The configuration might be
61 // nil if the module was removed from the configuration. This is okay,
62 // this just means that every resource is an orphan.
63 var m *configs.Module
64 if c := t.Config.DescendentForInstance(moduleAddr); c != nil {
65 m = c.Module
66 }
67
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 }
80 }
81
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)
91 }
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.
111 type OrphanResourceTransformer struct {
112 Concrete ConcreteResourceNodeFunc
113
114 // State is the global state.
115 State *states.State
116
117 // Config is the root node in the configuration tree.
118 Config *configs.Config
119 }
120
121 func (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 }
175 }
176
177 return nil
178
179 }