aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/states/resource.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/states/resource.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/states/resource.go239
1 files changed, 239 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/states/resource.go b/vendor/github.com/hashicorp/terraform/states/resource.go
new file mode 100644
index 0000000..e2a2b85
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/states/resource.go
@@ -0,0 +1,239 @@
1package states
2
3import (
4 "fmt"
5 "math/rand"
6 "time"
7
8 "github.com/hashicorp/terraform/addrs"
9)
10
11// Resource represents the state of a resource.
12type Resource struct {
13 // Addr is the module-relative address for the resource this state object
14 // belongs to.
15 Addr addrs.Resource
16
17 // EachMode is the multi-instance mode currently in use for this resource,
18 // or NoEach if this is a single-instance resource. This dictates what
19 // type of value is returned when accessing this resource via expressions
20 // in the Terraform language.
21 EachMode EachMode
22
23 // Instances contains the potentially-multiple instances associated with
24 // this resource. This map can contain a mixture of different key types,
25 // but only the ones of InstanceKeyType are considered current.
26 Instances map[addrs.InstanceKey]*ResourceInstance
27
28 // ProviderConfig is the absolute address for the provider configuration that
29 // most recently managed this resource. This is used to connect a resource
30 // with a provider configuration when the resource configuration block is
31 // not available, such as if it has been removed from configuration
32 // altogether.
33 ProviderConfig addrs.AbsProviderConfig
34}
35
36// Instance returns the state for the instance with the given key, or nil
37// if no such instance is tracked within the state.
38func (rs *Resource) Instance(key addrs.InstanceKey) *ResourceInstance {
39 return rs.Instances[key]
40}
41
42// EnsureInstance returns the state for the instance with the given key,
43// creating a new empty state for it if one doesn't already exist.
44//
45// Because this may create and save a new state, it is considered to be
46// a write operation.
47func (rs *Resource) EnsureInstance(key addrs.InstanceKey) *ResourceInstance {
48 ret := rs.Instance(key)
49 if ret == nil {
50 ret = NewResourceInstance()
51 rs.Instances[key] = ret
52 }
53 return ret
54}
55
56// ResourceInstance represents the state of a particular instance of a resource.
57type ResourceInstance struct {
58 // Current, if non-nil, is the remote object that is currently represented
59 // by the corresponding resource instance.
60 Current *ResourceInstanceObjectSrc
61
62 // Deposed, if len > 0, contains any remote objects that were previously
63 // represented by the corresponding resource instance but have been
64 // replaced and are pending destruction due to the create_before_destroy
65 // lifecycle mode.
66 Deposed map[DeposedKey]*ResourceInstanceObjectSrc
67}
68
69// NewResourceInstance constructs and returns a new ResourceInstance, ready to
70// use.
71func NewResourceInstance() *ResourceInstance {
72 return &ResourceInstance{
73 Deposed: map[DeposedKey]*ResourceInstanceObjectSrc{},
74 }
75}
76
77// HasCurrent returns true if this resource instance has a "current"-generation
78// object. Most instances do, but this can briefly be false during a
79// create-before-destroy replace operation when the current has been deposed
80// but its replacement has not yet been created.
81func (i *ResourceInstance) HasCurrent() bool {
82 return i != nil && i.Current != nil
83}
84
85// HasDeposed returns true if this resource instance has a deposed object
86// with the given key.
87func (i *ResourceInstance) HasDeposed(key DeposedKey) bool {
88 return i != nil && i.Deposed[key] != nil
89}
90
91// HasAnyDeposed returns true if this resource instance has one or more
92// deposed objects.
93func (i *ResourceInstance) HasAnyDeposed() bool {
94 return i != nil && len(i.Deposed) > 0
95}
96
97// HasObjects returns true if this resource has any objects at all, whether
98// current or deposed.
99func (i *ResourceInstance) HasObjects() bool {
100 return i.Current != nil || len(i.Deposed) != 0
101}
102
103// deposeCurrentObject is part of the real implementation of
104// SyncState.DeposeResourceInstanceObject. The exported method uses a lock
105// to ensure that we can safely allocate an unused deposed key without
106// collision.
107func (i *ResourceInstance) deposeCurrentObject(forceKey DeposedKey) DeposedKey {
108 if !i.HasCurrent() {
109 return NotDeposed
110 }
111
112 key := forceKey
113 if key == NotDeposed {
114 key = i.findUnusedDeposedKey()
115 } else {
116 if _, exists := i.Deposed[key]; exists {
117 panic(fmt.Sprintf("forced key %s is already in use", forceKey))
118 }
119 }
120 i.Deposed[key] = i.Current
121 i.Current = nil
122 return key
123}
124
125// GetGeneration retrieves the object of the given generation from the
126// ResourceInstance, or returns nil if there is no such object.
127//
128// If the given generation is nil or invalid, this method will panic.
129func (i *ResourceInstance) GetGeneration(gen Generation) *ResourceInstanceObjectSrc {
130 if gen == CurrentGen {
131 return i.Current
132 }
133 if dk, ok := gen.(DeposedKey); ok {
134 return i.Deposed[dk]
135 }
136 if gen == nil {
137 panic(fmt.Sprintf("get with nil Generation"))
138 }
139 // Should never fall out here, since the above covers all possible
140 // Generation values.
141 panic(fmt.Sprintf("get invalid Generation %#v", gen))
142}
143
144// FindUnusedDeposedKey generates a unique DeposedKey that is guaranteed not to
145// already be in use for this instance at the time of the call.
146//
147// Note that the validity of this result may change if new deposed keys are
148// allocated before it is used. To avoid this risk, instead use the
149// DeposeResourceInstanceObject method on the SyncState wrapper type, which
150// allocates a key and uses it atomically.
151func (i *ResourceInstance) FindUnusedDeposedKey() DeposedKey {
152 return i.findUnusedDeposedKey()
153}
154
155// findUnusedDeposedKey generates a unique DeposedKey that is guaranteed not to
156// already be in use for this instance.
157func (i *ResourceInstance) findUnusedDeposedKey() DeposedKey {
158 for {
159 key := NewDeposedKey()
160 if _, exists := i.Deposed[key]; !exists {
161 return key
162 }
163 // Spin until we find a unique one. This shouldn't take long, because
164 // we have a 32-bit keyspace and there's rarely more than one deposed
165 // instance.
166 }
167}
168
169// EachMode specifies the multi-instance mode for a resource.
170type EachMode rune
171
172const (
173 NoEach EachMode = 0
174 EachList EachMode = 'L'
175 EachMap EachMode = 'M'
176)
177
178//go:generate stringer -type EachMode
179
180func eachModeForInstanceKey(key addrs.InstanceKey) EachMode {
181 switch key.(type) {
182 case addrs.IntKey:
183 return EachList
184 case addrs.StringKey:
185 return EachMap
186 default:
187 if key == addrs.NoKey {
188 return NoEach
189 }
190 panic(fmt.Sprintf("don't know an each mode for instance key %#v", key))
191 }
192}
193
194// DeposedKey is a 8-character hex string used to uniquely identify deposed
195// instance objects in the state.
196type DeposedKey string
197
198// NotDeposed is a special invalid value of DeposedKey that is used to represent
199// the absense of a deposed key. It must not be used as an actual deposed key.
200const NotDeposed = DeposedKey("")
201
202var deposedKeyRand = rand.New(rand.NewSource(time.Now().UnixNano()))
203
204// NewDeposedKey generates a pseudo-random deposed key. Because of the short
205// length of these keys, uniqueness is not a natural consequence and so the
206// caller should test to see if the generated key is already in use and generate
207// another if so, until a unique key is found.
208func NewDeposedKey() DeposedKey {
209 v := deposedKeyRand.Uint32()
210 return DeposedKey(fmt.Sprintf("%08x", v))
211}
212
213func (k DeposedKey) String() string {
214 return string(k)
215}
216
217func (k DeposedKey) GoString() string {
218 ks := string(k)
219 switch {
220 case ks == "":
221 return "states.NotDeposed"
222 default:
223 return fmt.Sprintf("states.DeposedKey(%s)", ks)
224 }
225}
226
227// Generation is a helper method to convert a DeposedKey into a Generation.
228// If the reciever is anything other than NotDeposed then the result is
229// just the same value as a Generation. If the receiver is NotDeposed then
230// the result is CurrentGen.
231func (k DeposedKey) Generation() Generation {
232 if k == NotDeposed {
233 return CurrentGen
234 }
235 return k
236}
237
238// generation is an implementation of Generation.
239func (k DeposedKey) generation() {}