]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/states/sync.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / states / sync.go
1 package states
2
3 import (
4 "log"
5 "sync"
6
7 "github.com/hashicorp/terraform/addrs"
8 "github.com/zclconf/go-cty/cty"
9 )
10
11 // SyncState is a wrapper around State that provides concurrency-safe access to
12 // various common operations that occur during a Terraform graph walk, or other
13 // similar concurrent contexts.
14 //
15 // When a SyncState wrapper is in use, no concurrent direct access to the
16 // underlying objects is permitted unless the caller first acquires an explicit
17 // lock, using the Lock and Unlock methods. Most callers should _not_
18 // explicitly lock, and should instead use the other methods of this type that
19 // handle locking automatically.
20 //
21 // Since SyncState is able to safely consolidate multiple updates into a single
22 // atomic operation, many of its methods are at a higher level than those
23 // of the underlying types, and operate on the state as a whole rather than
24 // on individual sub-structures of the state.
25 //
26 // SyncState can only protect against races within its own methods. It cannot
27 // provide any guarantees about the order in which concurrent operations will
28 // be processed, so callers may still need to employ higher-level techniques
29 // for ensuring correct operation sequencing, such as building and walking
30 // a dependency graph.
31 type SyncState struct {
32 state *State
33 lock sync.RWMutex
34 }
35
36 // Module returns a snapshot of the state of the module instance with the given
37 // address, or nil if no such module is tracked.
38 //
39 // The return value is a pointer to a copy of the module state, which the
40 // caller may then freely access and mutate. However, since the module state
41 // tends to be a large data structure with many child objects, where possible
42 // callers should prefer to use a more granular accessor to access a child
43 // module directly, and thus reduce the amount of copying required.
44 func (s *SyncState) Module(addr addrs.ModuleInstance) *Module {
45 s.lock.RLock()
46 ret := s.state.Module(addr).DeepCopy()
47 s.lock.RUnlock()
48 return ret
49 }
50
51 // RemoveModule removes the entire state for the given module, taking with
52 // it any resources associated with the module. This should generally be
53 // called only for modules whose resources have all been destroyed, but
54 // that is not enforced by this method.
55 func (s *SyncState) RemoveModule(addr addrs.ModuleInstance) {
56 s.lock.Lock()
57 defer s.lock.Unlock()
58
59 s.state.RemoveModule(addr)
60 }
61
62 // OutputValue returns a snapshot of the state of the output value with the
63 // given address, or nil if no such output value is tracked.
64 //
65 // The return value is a pointer to a copy of the output value state, which the
66 // caller may then freely access and mutate.
67 func (s *SyncState) OutputValue(addr addrs.AbsOutputValue) *OutputValue {
68 s.lock.RLock()
69 ret := s.state.OutputValue(addr).DeepCopy()
70 s.lock.RUnlock()
71 return ret
72 }
73
74 // SetOutputValue writes a given output value into the state, overwriting
75 // any existing value of the same name.
76 //
77 // If the module containing the output is not yet tracked in state then it
78 // be added as a side-effect.
79 func (s *SyncState) SetOutputValue(addr addrs.AbsOutputValue, value cty.Value, sensitive bool) {
80 s.lock.Lock()
81 defer s.lock.Unlock()
82
83 ms := s.state.EnsureModule(addr.Module)
84 ms.SetOutputValue(addr.OutputValue.Name, value, sensitive)
85 }
86
87 // RemoveOutputValue removes the stored value for the output value with the
88 // given address.
89 //
90 // If this results in its containing module being empty, the module will be
91 // pruned from the state as a side-effect.
92 func (s *SyncState) RemoveOutputValue(addr addrs.AbsOutputValue) {
93 s.lock.Lock()
94 defer s.lock.Unlock()
95
96 ms := s.state.Module(addr.Module)
97 if ms == nil {
98 return
99 }
100 ms.RemoveOutputValue(addr.OutputValue.Name)
101 s.maybePruneModule(addr.Module)
102 }
103
104 // LocalValue returns the current value associated with the given local value
105 // address.
106 func (s *SyncState) LocalValue(addr addrs.AbsLocalValue) cty.Value {
107 s.lock.RLock()
108 // cty.Value is immutable, so we don't need any extra copying here.
109 ret := s.state.LocalValue(addr)
110 s.lock.RUnlock()
111 return ret
112 }
113
114 // SetLocalValue writes a given output value into the state, overwriting
115 // any existing value of the same name.
116 //
117 // If the module containing the local value is not yet tracked in state then it
118 // will be added as a side-effect.
119 func (s *SyncState) SetLocalValue(addr addrs.AbsLocalValue, value cty.Value) {
120 s.lock.Lock()
121 defer s.lock.Unlock()
122
123 ms := s.state.EnsureModule(addr.Module)
124 ms.SetLocalValue(addr.LocalValue.Name, value)
125 }
126
127 // RemoveLocalValue removes the stored value for the local value with the
128 // given address.
129 //
130 // If this results in its containing module being empty, the module will be
131 // pruned from the state as a side-effect.
132 func (s *SyncState) RemoveLocalValue(addr addrs.AbsLocalValue) {
133 s.lock.Lock()
134 defer s.lock.Unlock()
135
136 ms := s.state.Module(addr.Module)
137 if ms == nil {
138 return
139 }
140 ms.RemoveLocalValue(addr.LocalValue.Name)
141 s.maybePruneModule(addr.Module)
142 }
143
144 // Resource returns a snapshot of the state of the resource with the given
145 // address, or nil if no such resource is tracked.
146 //
147 // The return value is a pointer to a copy of the resource state, which the
148 // caller may then freely access and mutate.
149 func (s *SyncState) Resource(addr addrs.AbsResource) *Resource {
150 s.lock.RLock()
151 ret := s.state.Resource(addr).DeepCopy()
152 s.lock.RUnlock()
153 return ret
154 }
155
156 // ResourceInstance returns a snapshot of the state the resource instance with
157 // the given address, or nil if no such instance is tracked.
158 //
159 // The return value is a pointer to a copy of the instance state, which the
160 // caller may then freely access and mutate.
161 func (s *SyncState) ResourceInstance(addr addrs.AbsResourceInstance) *ResourceInstance {
162 s.lock.RLock()
163 ret := s.state.ResourceInstance(addr).DeepCopy()
164 s.lock.RUnlock()
165 return ret
166 }
167
168 // ResourceInstanceObject returns a snapshot of the current instance object
169 // of the given generation belonging to the instance with the given address,
170 // or nil if no such object is tracked..
171 //
172 // The return value is a pointer to a copy of the object, which the caller may
173 // then freely access and mutate.
174 func (s *SyncState) ResourceInstanceObject(addr addrs.AbsResourceInstance, gen Generation) *ResourceInstanceObjectSrc {
175 s.lock.RLock()
176 defer s.lock.RUnlock()
177
178 inst := s.state.ResourceInstance(addr)
179 if inst == nil {
180 return nil
181 }
182 return inst.GetGeneration(gen).DeepCopy()
183 }
184
185 // SetResourceMeta updates the resource-level metadata for the resource at
186 // the given address, creating the containing module state and resource state
187 // as a side-effect if not already present.
188 func (s *SyncState) SetResourceMeta(addr addrs.AbsResource, eachMode EachMode, provider addrs.AbsProviderConfig) {
189 s.lock.Lock()
190 defer s.lock.Unlock()
191
192 ms := s.state.EnsureModule(addr.Module)
193 ms.SetResourceMeta(addr.Resource, eachMode, provider)
194 }
195
196 // RemoveResource removes the entire state for the given resource, taking with
197 // it any instances associated with the resource. This should generally be
198 // called only for resource objects whose instances have all been destroyed,
199 // but that is not enforced by this method. (Use RemoveResourceIfEmpty instead
200 // to safely check first.)
201 func (s *SyncState) RemoveResource(addr addrs.AbsResource) {
202 s.lock.Lock()
203 defer s.lock.Unlock()
204
205 ms := s.state.EnsureModule(addr.Module)
206 ms.RemoveResource(addr.Resource)
207 s.maybePruneModule(addr.Module)
208 }
209
210 // RemoveResourceIfEmpty is similar to RemoveResource but first checks to
211 // make sure there are no instances or objects left in the resource.
212 //
213 // Returns true if the resource was removed, or false if remaining child
214 // objects prevented its removal. Returns true also if the resource was
215 // already absent, and thus no action needed to be taken.
216 func (s *SyncState) RemoveResourceIfEmpty(addr addrs.AbsResource) bool {
217 s.lock.Lock()
218 defer s.lock.Unlock()
219
220 ms := s.state.Module(addr.Module)
221 if ms == nil {
222 return true // nothing to do
223 }
224 rs := ms.Resource(addr.Resource)
225 if rs == nil {
226 return true // nothing to do
227 }
228 if len(rs.Instances) != 0 {
229 // We don't check here for the possibility of instances that exist
230 // but don't have any objects because it's the responsibility of the
231 // instance-mutation methods to prune those away automatically.
232 return false
233 }
234 ms.RemoveResource(addr.Resource)
235 s.maybePruneModule(addr.Module)
236 return true
237 }
238
239 // MaybeFixUpResourceInstanceAddressForCount deals with the situation where a
240 // resource has changed from having "count" set to not set, or vice-versa, and
241 // so we need to rename the zeroth instance key to no key at all, or vice-versa.
242 //
243 // Set countEnabled to true if the resource has count set in its new
244 // configuration, or false if it does not.
245 //
246 // The state is modified in-place if necessary, moving a resource instance
247 // between the two addresses. The return value is true if a change was made,
248 // and false otherwise.
249 func (s *SyncState) MaybeFixUpResourceInstanceAddressForCount(addr addrs.AbsResource, countEnabled bool) bool {
250 s.lock.Lock()
251 defer s.lock.Unlock()
252
253 ms := s.state.Module(addr.Module)
254 if ms == nil {
255 return false
256 }
257
258 relAddr := addr.Resource
259 rs := ms.Resource(relAddr)
260 if rs == nil {
261 return false
262 }
263 huntKey := addrs.NoKey
264 replaceKey := addrs.InstanceKey(addrs.IntKey(0))
265 if !countEnabled {
266 huntKey, replaceKey = replaceKey, huntKey
267 }
268
269 is, exists := rs.Instances[huntKey]
270 if !exists {
271 return false
272 }
273
274 if _, exists := rs.Instances[replaceKey]; exists {
275 // If the replacement key also exists then we'll do nothing and keep both.
276 return false
277 }
278
279 // If we get here then we need to "rename" from hunt to replace
280 rs.Instances[replaceKey] = is
281 delete(rs.Instances, huntKey)
282 return true
283 }
284
285 // SetResourceInstanceCurrent saves the given instance object as the current
286 // generation of the resource instance with the given address, simulataneously
287 // updating the recorded provider configuration address, dependencies, and
288 // resource EachMode.
289 //
290 // Any existing current instance object for the given resource is overwritten.
291 // Set obj to nil to remove the primary generation object altogether. If there
292 // are no deposed objects then the instance as a whole will be removed, which
293 // may in turn also remove the containing module if it becomes empty.
294 //
295 // The caller must ensure that the given ResourceInstanceObject is not
296 // concurrently mutated during this call, but may be freely used again once
297 // this function returns.
298 //
299 // The provider address and "each mode" are resource-wide settings and so they
300 // are updated for all other instances of the same resource as a side-effect of
301 // this call.
302 //
303 // If the containing module for this resource or the resource itself are not
304 // already tracked in state then they will be added as a side-effect.
305 func (s *SyncState) SetResourceInstanceCurrent(addr addrs.AbsResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
306 s.lock.Lock()
307 defer s.lock.Unlock()
308
309 ms := s.state.EnsureModule(addr.Module)
310 ms.SetResourceInstanceCurrent(addr.Resource, obj.DeepCopy(), provider)
311 s.maybePruneModule(addr.Module)
312 }
313
314 // SetResourceInstanceDeposed saves the given instance object as a deposed
315 // generation of the resource instance with the given address and deposed key.
316 //
317 // Call this method only for pre-existing deposed objects that already have
318 // a known DeposedKey. For example, this method is useful if reloading objects
319 // that were persisted to a state file. To mark the current object as deposed,
320 // use DeposeResourceInstanceObject instead.
321 //
322 // The caller must ensure that the given ResourceInstanceObject is not
323 // concurrently mutated during this call, but may be freely used again once
324 // this function returns.
325 //
326 // The resource that contains the given instance must already exist in the
327 // state, or this method will panic. Use Resource to check first if its
328 // presence is not already guaranteed.
329 //
330 // Any existing current instance object for the given resource and deposed key
331 // is overwritten. Set obj to nil to remove the deposed object altogether. If
332 // the instance is left with no objects after this operation then it will
333 // be removed from its containing resource altogether.
334 //
335 // If the containing module for this resource or the resource itself are not
336 // already tracked in state then they will be added as a side-effect.
337 func (s *SyncState) SetResourceInstanceDeposed(addr addrs.AbsResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
338 s.lock.Lock()
339 defer s.lock.Unlock()
340
341 ms := s.state.EnsureModule(addr.Module)
342 ms.SetResourceInstanceDeposed(addr.Resource, key, obj.DeepCopy(), provider)
343 s.maybePruneModule(addr.Module)
344 }
345
346 // DeposeResourceInstanceObject moves the current instance object for the
347 // given resource instance address into the deposed set, leaving the instance
348 // without a current object.
349 //
350 // The return value is the newly-allocated deposed key, or NotDeposed if the
351 // given instance is already lacking a current object.
352 //
353 // If the containing module for this resource or the resource itself are not
354 // already tracked in state then there cannot be a current object for the
355 // given instance, and so NotDeposed will be returned without modifying the
356 // state at all.
357 func (s *SyncState) DeposeResourceInstanceObject(addr addrs.AbsResourceInstance) DeposedKey {
358 s.lock.Lock()
359 defer s.lock.Unlock()
360
361 ms := s.state.Module(addr.Module)
362 if ms == nil {
363 return NotDeposed
364 }
365
366 return ms.deposeResourceInstanceObject(addr.Resource, NotDeposed)
367 }
368
369 // DeposeResourceInstanceObjectForceKey is like DeposeResourceInstanceObject
370 // but uses a pre-allocated key. It's the caller's responsibility to ensure
371 // that there aren't any races to use a particular key; this method will panic
372 // if the given key is already in use.
373 func (s *SyncState) DeposeResourceInstanceObjectForceKey(addr addrs.AbsResourceInstance, forcedKey DeposedKey) {
374 s.lock.Lock()
375 defer s.lock.Unlock()
376
377 if forcedKey == NotDeposed {
378 // Usage error: should use DeposeResourceInstanceObject in this case
379 panic("DeposeResourceInstanceObjectForceKey called without forced key")
380 }
381
382 ms := s.state.Module(addr.Module)
383 if ms == nil {
384 return // Nothing to do, since there can't be any current object either.
385 }
386
387 ms.deposeResourceInstanceObject(addr.Resource, forcedKey)
388 }
389
390 // ForgetResourceInstanceAll removes the record of all objects associated with
391 // the specified resource instance, if present. If not present, this is a no-op.
392 func (s *SyncState) ForgetResourceInstanceAll(addr addrs.AbsResourceInstance) {
393 s.lock.Lock()
394 defer s.lock.Unlock()
395
396 ms := s.state.Module(addr.Module)
397 if ms == nil {
398 return
399 }
400 ms.ForgetResourceInstanceAll(addr.Resource)
401 s.maybePruneModule(addr.Module)
402 }
403
404 // ForgetResourceInstanceDeposed removes the record of the deposed object with
405 // the given address and key, if present. If not present, this is a no-op.
406 func (s *SyncState) ForgetResourceInstanceDeposed(addr addrs.AbsResourceInstance, key DeposedKey) {
407 s.lock.Lock()
408 defer s.lock.Unlock()
409
410 ms := s.state.Module(addr.Module)
411 if ms == nil {
412 return
413 }
414 ms.ForgetResourceInstanceDeposed(addr.Resource, key)
415 s.maybePruneModule(addr.Module)
416 }
417
418 // MaybeRestoreResourceInstanceDeposed will restore the deposed object with the
419 // given key on the specified resource as the current object for that instance
420 // if and only if that would not cause us to forget an existing current
421 // object for that instance.
422 //
423 // Returns true if the object was restored to current, or false if no change
424 // was made at all.
425 func (s *SyncState) MaybeRestoreResourceInstanceDeposed(addr addrs.AbsResourceInstance, key DeposedKey) bool {
426 s.lock.Lock()
427 defer s.lock.Unlock()
428
429 if key == NotDeposed {
430 panic("MaybeRestoreResourceInstanceDeposed called without DeposedKey")
431 }
432
433 ms := s.state.Module(addr.Module)
434 if ms == nil {
435 // Nothing to do, since the specified deposed object cannot exist.
436 return false
437 }
438
439 return ms.maybeRestoreResourceInstanceDeposed(addr.Resource, key)
440 }
441
442 // RemovePlannedResourceInstanceObjects removes from the state any resource
443 // instance objects that have the status ObjectPlanned, indiciating that they
444 // are just transient placeholders created during planning.
445 //
446 // Note that this does not restore any "ready" or "tainted" object that might
447 // have been present before the planned object was written. The only real use
448 // for this method is in preparing the state created during a refresh walk,
449 // where we run the planning step for certain instances just to create enough
450 // information to allow correct expression evaluation within provider and
451 // data resource blocks. Discarding planned instances in that case is okay
452 // because the refresh phase only creates planned objects to stand in for
453 // objects that don't exist yet, and thus the planned object must have been
454 // absent before by definition.
455 func (s *SyncState) RemovePlannedResourceInstanceObjects() {
456 // TODO: Merge together the refresh and plan phases into a single walk,
457 // so we can remove the need to create this "partial plan" during refresh
458 // that we then need to clean up before proceeding.
459
460 s.lock.Lock()
461 defer s.lock.Unlock()
462
463 for _, ms := range s.state.Modules {
464 moduleAddr := ms.Addr
465
466 for _, rs := range ms.Resources {
467 resAddr := rs.Addr
468
469 for ik, is := range rs.Instances {
470 instAddr := resAddr.Instance(ik)
471
472 if is.Current != nil && is.Current.Status == ObjectPlanned {
473 // Setting the current instance to nil removes it from the
474 // state altogether if there are not also deposed instances.
475 ms.SetResourceInstanceCurrent(instAddr, nil, rs.ProviderConfig)
476 }
477
478 for dk, obj := range is.Deposed {
479 // Deposed objects should never be "planned", but we'll
480 // do this anyway for the sake of completeness.
481 if obj.Status == ObjectPlanned {
482 ms.ForgetResourceInstanceDeposed(instAddr, dk)
483 }
484 }
485 }
486 }
487
488 // We may have deleted some objects, which means that we may have
489 // left a module empty, and so we must prune to preserve the invariant
490 // that only the root module is allowed to be empty.
491 s.maybePruneModule(moduleAddr)
492 }
493 }
494
495 // Lock acquires an explicit lock on the state, allowing direct read and write
496 // access to the returned state object. The caller must call Unlock once
497 // access is no longer needed, and then immediately discard the state pointer
498 // pointer.
499 //
500 // Most callers should not use this. Instead, use the concurrency-safe
501 // accessors and mutators provided directly on SyncState.
502 func (s *SyncState) Lock() *State {
503 s.lock.Lock()
504 return s.state
505 }
506
507 // Unlock releases a lock previously acquired by Lock, at which point the
508 // caller must cease all use of the state pointer that was returned.
509 //
510 // Do not call this method except to end an explicit lock acquired by
511 // Lock. If a caller calls Unlock without first holding the lock, behavior
512 // is undefined.
513 func (s *SyncState) Unlock() {
514 s.lock.Unlock()
515 }
516
517 // maybePruneModule will remove a module from the state altogether if it is
518 // empty, unless it's the root module which must always be present.
519 //
520 // This helper method is not concurrency-safe on its own, so must only be
521 // called while the caller is already holding the lock for writing.
522 func (s *SyncState) maybePruneModule(addr addrs.ModuleInstance) {
523 if addr.IsRoot() {
524 // We never prune the root.
525 return
526 }
527
528 ms := s.state.Module(addr)
529 if ms == nil {
530 return
531 }
532
533 if ms.empty() {
534 log.Printf("[TRACE] states.SyncState: pruning %s because it is empty", addr)
535 s.state.RemoveModule(addr)
536 }
537 }