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