]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package terraform |
2 | ||
3 | import ( | |
4 | "log" | |
5 | ||
107c1cdb | 6 | "github.com/hashicorp/terraform/addrs" |
bae9f6d2 | 7 | "github.com/hashicorp/terraform/dag" |
107c1cdb | 8 | "github.com/hashicorp/terraform/states" |
bae9f6d2 JC |
9 | ) |
10 | ||
11 | // OrphanResourceCountTransformer is a GraphTransformer that adds orphans | |
12 | // for an expanded count to the graph. The determination of this depends | |
13 | // on the count argument given. | |
14 | // | |
15 | // Orphans are found by comparing the count to what is found in the state. | |
16 | // This transform assumes that if an element in the state is within the count | |
17 | // bounds given, that it is not an orphan. | |
18 | type OrphanResourceCountTransformer struct { | |
107c1cdb | 19 | Concrete ConcreteResourceInstanceNodeFunc |
bae9f6d2 | 20 | |
107c1cdb ND |
21 | Count int // Actual count of the resource, or -1 if count is not set at all |
22 | Addr addrs.AbsResource // Addr of the resource to look for orphans | |
23 | State *states.State // Full global state | |
bae9f6d2 JC |
24 | } |
25 | ||
26 | func (t *OrphanResourceCountTransformer) Transform(g *Graph) error { | |
107c1cdb ND |
27 | rs := t.State.Resource(t.Addr) |
28 | if rs == nil { | |
29 | return nil // Resource doesn't exist in state, so nothing to do! | |
30 | } | |
bae9f6d2 | 31 | |
107c1cdb ND |
32 | haveKeys := make(map[addrs.InstanceKey]struct{}) |
33 | for key := range rs.Instances { | |
34 | haveKeys[key] = struct{}{} | |
bae9f6d2 JC |
35 | } |
36 | ||
107c1cdb ND |
37 | if t.Count < 0 { |
38 | return t.transformNoCount(haveKeys, g) | |
39 | } | |
40 | if t.Count == 0 { | |
41 | return t.transformZeroCount(haveKeys, g) | |
bae9f6d2 | 42 | } |
107c1cdb ND |
43 | return t.transformCount(haveKeys, g) |
44 | } | |
45 | ||
46 | func (t *OrphanResourceCountTransformer) transformCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error { | |
47 | // Due to the logic in Transform, we only get in here if our count is | |
48 | // at least one. | |
bae9f6d2 | 49 | |
107c1cdb ND |
50 | _, have0Key := haveKeys[addrs.IntKey(0)] |
51 | ||
52 | for key := range haveKeys { | |
53 | if key == addrs.NoKey && !have0Key { | |
54 | // If we have no 0-key then we will accept a no-key instance | |
55 | // as an alias for it. | |
56 | continue | |
bae9f6d2 | 57 | } |
bae9f6d2 | 58 | |
107c1cdb ND |
59 | i, isInt := key.(addrs.IntKey) |
60 | if isInt && int(i) < t.Count { | |
bae9f6d2 JC |
61 | continue |
62 | } | |
63 | ||
107c1cdb ND |
64 | abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key)) |
65 | var node dag.Vertex = abstract | |
66 | if f := t.Concrete; f != nil { | |
67 | node = f(abstract) | |
68 | } | |
69 | log.Printf("[TRACE] OrphanResourceCount(non-zero): adding %s as %T", t.Addr, node) | |
70 | g.Add(node) | |
71 | } | |
72 | ||
73 | return nil | |
74 | } | |
bae9f6d2 | 75 | |
107c1cdb ND |
76 | func (t *OrphanResourceCountTransformer) transformZeroCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error { |
77 | // This case is easy: we need to orphan any keys we have at all. | |
bae9f6d2 | 78 | |
107c1cdb ND |
79 | for key := range haveKeys { |
80 | abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key)) | |
81 | var node dag.Vertex = abstract | |
82 | if f := t.Concrete; f != nil { | |
83 | node = f(abstract) | |
bae9f6d2 | 84 | } |
107c1cdb ND |
85 | log.Printf("[TRACE] OrphanResourceCount(zero): adding %s as %T", t.Addr, node) |
86 | g.Add(node) | |
87 | } | |
bae9f6d2 | 88 | |
107c1cdb ND |
89 | return nil |
90 | } | |
bae9f6d2 | 91 | |
107c1cdb ND |
92 | func (t *OrphanResourceCountTransformer) transformNoCount(haveKeys map[addrs.InstanceKey]struct{}, g *Graph) error { |
93 | // Negative count indicates that count is not set at all, in which | |
94 | // case we expect to have a single instance with no key set at all. | |
95 | // However, we'll also accept an instance with key 0 set as an alias | |
96 | // for it, in case the user has just deleted the "count" argument and | |
97 | // so wants to keep the first instance in the set. | |
98 | ||
99 | _, haveNoKey := haveKeys[addrs.NoKey] | |
100 | _, have0Key := haveKeys[addrs.IntKey(0)] | |
101 | keepKey := addrs.NoKey | |
102 | if have0Key && !haveNoKey { | |
103 | // If we don't have a no-key instance then we can use the 0-key instance | |
104 | // instead. | |
105 | keepKey = addrs.IntKey(0) | |
106 | } | |
107 | ||
108 | for key := range haveKeys { | |
109 | if key == keepKey { | |
bae9f6d2 JC |
110 | continue |
111 | } | |
112 | ||
107c1cdb | 113 | abstract := NewNodeAbstractResourceInstance(t.Addr.Instance(key)) |
bae9f6d2 JC |
114 | var node dag.Vertex = abstract |
115 | if f := t.Concrete; f != nil { | |
116 | node = f(abstract) | |
117 | } | |
107c1cdb | 118 | log.Printf("[TRACE] OrphanResourceCount(no-count): adding %s as %T", t.Addr, node) |
bae9f6d2 JC |
119 | g.Add(node) |
120 | } | |
121 | ||
122 | return nil | |
123 | } |