github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/states/state.go (about)

     1  package states
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  
     7  	"github.com/zclconf/go-cty/cty"
     8  
     9  	"github.com/hashicorp/terraform/internal/addrs"
    10  	"github.com/hashicorp/terraform/internal/getproviders"
    11  )
    12  
    13  // State is the top-level type of a Terraform state.
    14  //
    15  // A state should be mutated only via its accessor methods, to ensure that
    16  // invariants are preserved.
    17  //
    18  // Access to State and the nested values within it is not concurrency-safe,
    19  // so when accessing a State object concurrently it is the caller's
    20  // responsibility to ensure that only one write is in progress at a time
    21  // and that reads only occur when no write is in progress. The most common
    22  // way to achieve this is to wrap the State in a SyncState and use the
    23  // higher-level atomic operations supported by that type.
    24  type State struct {
    25  	// Modules contains the state for each module. The keys in this map are
    26  	// an implementation detail and must not be used by outside callers.
    27  	Modules map[string]*Module
    28  
    29  	// CheckResults contains a snapshot of the statuses of checks at the
    30  	// end of the most recent update to the state. Callers might compare
    31  	// checks between runs to see if e.g. a previously-failing check has
    32  	// been fixed since the last run, or similar.
    33  	//
    34  	// CheckResults can be nil to indicate that there are no check results
    35  	// from the previous run at all, which is subtly different than the
    36  	// previous run having affirmatively recorded that there are no checks
    37  	// to run. For example, if this object was created from a state snapshot
    38  	// created by a version of Terraform that didn't yet support checks
    39  	// then this field will be nil.
    40  	CheckResults *CheckResults
    41  }
    42  
    43  // NewState constructs a minimal empty state, containing an empty root module.
    44  func NewState() *State {
    45  	modules := map[string]*Module{}
    46  	modules[addrs.RootModuleInstance.String()] = NewModule(addrs.RootModuleInstance)
    47  	return &State{
    48  		Modules: modules,
    49  	}
    50  }
    51  
    52  // BuildState is a helper -- primarily intended for tests -- to build a state
    53  // using imperative code against the StateSync type while still acting as
    54  // an expression of type *State to assign into a containing struct.
    55  func BuildState(cb func(*SyncState)) *State {
    56  	s := NewState()
    57  	cb(s.SyncWrapper())
    58  	return s
    59  }
    60  
    61  // Empty returns true if there are no resources or populated output values
    62  // in the receiver. In other words, if this state could be safely replaced
    63  // with the return value of NewState and be functionally equivalent.
    64  func (s *State) Empty() bool {
    65  	if s == nil {
    66  		return true
    67  	}
    68  	for _, ms := range s.Modules {
    69  		if len(ms.Resources) != 0 {
    70  			return false
    71  		}
    72  		if len(ms.OutputValues) != 0 {
    73  			return false
    74  		}
    75  	}
    76  	return true
    77  }
    78  
    79  // Module returns the state for the module with the given address, or nil if
    80  // the requested module is not tracked in the state.
    81  func (s *State) Module(addr addrs.ModuleInstance) *Module {
    82  	if s == nil {
    83  		panic("State.Module on nil *State")
    84  	}
    85  	return s.Modules[addr.String()]
    86  }
    87  
    88  // ModuleInstances returns the set of Module states that matches the given path.
    89  func (s *State) ModuleInstances(addr addrs.Module) []*Module {
    90  	var ms []*Module
    91  	for _, m := range s.Modules {
    92  		if m.Addr.Module().Equal(addr) {
    93  			ms = append(ms, m)
    94  		}
    95  	}
    96  	return ms
    97  }
    98  
    99  // ModuleOutputs returns all outputs for the given module call under the
   100  // parentAddr instance.
   101  func (s *State) ModuleOutputs(parentAddr addrs.ModuleInstance, module addrs.ModuleCall) []*OutputValue {
   102  	var os []*OutputValue
   103  	for _, m := range s.Modules {
   104  		// can't get outputs from the root module
   105  		if m.Addr.IsRoot() {
   106  			continue
   107  		}
   108  
   109  		parent, call := m.Addr.Call()
   110  		// make sure this is a descendent in the correct path
   111  		if !parentAddr.Equal(parent) {
   112  			continue
   113  		}
   114  
   115  		// and check if this is the correct child
   116  		if call.Name != module.Name {
   117  			continue
   118  		}
   119  
   120  		for _, o := range m.OutputValues {
   121  			os = append(os, o)
   122  		}
   123  	}
   124  
   125  	return os
   126  }
   127  
   128  // RemoveModule removes the module with the given address from the state,
   129  // unless it is the root module. The root module cannot be deleted, and so
   130  // this method will panic if that is attempted.
   131  //
   132  // Removing a module implicitly discards all of the resources, outputs and
   133  // local values within it, and so this should usually be done only for empty
   134  // modules. For callers accessing the state through a SyncState wrapper, modules
   135  // are automatically pruned if they are empty after one of their contained
   136  // elements is removed.
   137  func (s *State) RemoveModule(addr addrs.ModuleInstance) {
   138  	if addr.IsRoot() {
   139  		panic("attempted to remove root module")
   140  	}
   141  
   142  	delete(s.Modules, addr.String())
   143  }
   144  
   145  // RootModule is a convenient alias for Module(addrs.RootModuleInstance).
   146  func (s *State) RootModule() *Module {
   147  	if s == nil {
   148  		panic("RootModule called on nil State")
   149  	}
   150  	return s.Modules[addrs.RootModuleInstance.String()]
   151  }
   152  
   153  // EnsureModule returns the state for the module with the given address,
   154  // creating and adding a new one if necessary.
   155  //
   156  // Since this might modify the state to add a new instance, it is considered
   157  // to be a write operation.
   158  func (s *State) EnsureModule(addr addrs.ModuleInstance) *Module {
   159  	ms := s.Module(addr)
   160  	if ms == nil {
   161  		ms = NewModule(addr)
   162  		s.Modules[addr.String()] = ms
   163  	}
   164  	return ms
   165  }
   166  
   167  // HasManagedResourceInstanceObjects returns true if there is at least one
   168  // resource instance object (current or deposed) associated with a managed
   169  // resource in the receiving state.
   170  //
   171  // A true result would suggest that just discarding this state without first
   172  // destroying these objects could leave "dangling" objects in remote systems,
   173  // no longer tracked by any Terraform state.
   174  func (s *State) HasManagedResourceInstanceObjects() bool {
   175  	if s == nil {
   176  		return false
   177  	}
   178  	for _, ms := range s.Modules {
   179  		for _, rs := range ms.Resources {
   180  			if rs.Addr.Resource.Mode != addrs.ManagedResourceMode {
   181  				continue
   182  			}
   183  			for _, is := range rs.Instances {
   184  				if is.Current != nil || len(is.Deposed) != 0 {
   185  					return true
   186  				}
   187  			}
   188  		}
   189  	}
   190  	return false
   191  }
   192  
   193  // Resource returns the state for the resource with the given address, or nil
   194  // if no such resource is tracked in the state.
   195  func (s *State) Resource(addr addrs.AbsResource) *Resource {
   196  	ms := s.Module(addr.Module)
   197  	if ms == nil {
   198  		return nil
   199  	}
   200  	return ms.Resource(addr.Resource)
   201  }
   202  
   203  // Resources returns the set of resources that match the given configuration path.
   204  func (s *State) Resources(addr addrs.ConfigResource) []*Resource {
   205  	var ret []*Resource
   206  	for _, m := range s.ModuleInstances(addr.Module) {
   207  		r := m.Resource(addr.Resource)
   208  		if r != nil {
   209  			ret = append(ret, r)
   210  		}
   211  	}
   212  	return ret
   213  }
   214  
   215  // AllManagedResourceInstanceObjectAddrs returns a set of addresses for all of
   216  // the leaf resource instance objects associated with managed resources that
   217  // are tracked in this state.
   218  //
   219  // This result is the set of objects that would be effectively "forgotten"
   220  // (like "terraform state rm") if this state were totally discarded, such as
   221  // by deleting a workspace. This function is intended only for reporting
   222  // context in error messages, such as when we reject deleting a "non-empty"
   223  // workspace as detected by s.HasManagedResourceInstanceObjects.
   224  //
   225  // The ordering of the result is meaningless but consistent. DeposedKey will
   226  // be NotDeposed (the zero value of DeposedKey) for any "current" objects.
   227  // This method is guaranteed to return at least one item if
   228  // s.HasManagedResourceInstanceObjects returns true for the same state, and
   229  // to return a zero-length slice if it returns false.
   230  func (s *State) AllResourceInstanceObjectAddrs() []struct {
   231  	Instance   addrs.AbsResourceInstance
   232  	DeposedKey DeposedKey
   233  } {
   234  	if s == nil {
   235  		return nil
   236  	}
   237  
   238  	// We use an unnamed return type here just because we currently have no
   239  	// general need to return pairs of instance address and deposed key aside
   240  	// from this method, and this method itself is only of marginal value
   241  	// when producing some error messages.
   242  	//
   243  	// If that need ends up arising more in future then it might make sense to
   244  	// name this as addrs.AbsResourceInstanceObject, although that would require
   245  	// moving DeposedKey into the addrs package too.
   246  	type ResourceInstanceObject = struct {
   247  		Instance   addrs.AbsResourceInstance
   248  		DeposedKey DeposedKey
   249  	}
   250  	var ret []ResourceInstanceObject
   251  
   252  	for _, ms := range s.Modules {
   253  		for _, rs := range ms.Resources {
   254  			if rs.Addr.Resource.Mode != addrs.ManagedResourceMode {
   255  				continue
   256  			}
   257  
   258  			for instKey, is := range rs.Instances {
   259  				instAddr := rs.Addr.Instance(instKey)
   260  				if is.Current != nil {
   261  					ret = append(ret, ResourceInstanceObject{instAddr, NotDeposed})
   262  				}
   263  				for deposedKey := range is.Deposed {
   264  					ret = append(ret, ResourceInstanceObject{instAddr, deposedKey})
   265  				}
   266  			}
   267  		}
   268  	}
   269  
   270  	sort.SliceStable(ret, func(i, j int) bool {
   271  		objI, objJ := ret[i], ret[j]
   272  		switch {
   273  		case !objI.Instance.Equal(objJ.Instance):
   274  			return objI.Instance.Less(objJ.Instance)
   275  		default:
   276  			return objI.DeposedKey < objJ.DeposedKey
   277  		}
   278  	})
   279  
   280  	return ret
   281  }
   282  
   283  // ResourceInstance returns the state for the resource instance with the given
   284  // address, or nil if no such resource is tracked in the state.
   285  func (s *State) ResourceInstance(addr addrs.AbsResourceInstance) *ResourceInstance {
   286  	if s == nil {
   287  		panic("State.ResourceInstance on nil *State")
   288  	}
   289  	ms := s.Module(addr.Module)
   290  	if ms == nil {
   291  		return nil
   292  	}
   293  	return ms.ResourceInstance(addr.Resource)
   294  }
   295  
   296  // OutputValue returns the state for the output value with the given address,
   297  // or nil if no such output value is tracked in the state.
   298  func (s *State) OutputValue(addr addrs.AbsOutputValue) *OutputValue {
   299  	ms := s.Module(addr.Module)
   300  	if ms == nil {
   301  		return nil
   302  	}
   303  	return ms.OutputValues[addr.OutputValue.Name]
   304  }
   305  
   306  // LocalValue returns the value of the named local value with the given address,
   307  // or cty.NilVal if no such value is tracked in the state.
   308  func (s *State) LocalValue(addr addrs.AbsLocalValue) cty.Value {
   309  	ms := s.Module(addr.Module)
   310  	if ms == nil {
   311  		return cty.NilVal
   312  	}
   313  	return ms.LocalValues[addr.LocalValue.Name]
   314  }
   315  
   316  // ProviderAddrs returns a list of all of the provider configuration addresses
   317  // referenced throughout the receiving state.
   318  //
   319  // The result is de-duplicated so that each distinct address appears only once.
   320  func (s *State) ProviderAddrs() []addrs.AbsProviderConfig {
   321  	if s == nil {
   322  		return nil
   323  	}
   324  
   325  	m := map[string]addrs.AbsProviderConfig{}
   326  	for _, ms := range s.Modules {
   327  		for _, rc := range ms.Resources {
   328  			m[rc.ProviderConfig.String()] = rc.ProviderConfig
   329  		}
   330  	}
   331  	if len(m) == 0 {
   332  		return nil
   333  	}
   334  
   335  	// This is mainly just so we'll get stable results for testing purposes.
   336  	keys := make([]string, 0, len(m))
   337  	for k := range m {
   338  		keys = append(keys, k)
   339  	}
   340  	sort.Strings(keys)
   341  
   342  	ret := make([]addrs.AbsProviderConfig, len(keys))
   343  	for i, key := range keys {
   344  		ret[i] = m[key]
   345  	}
   346  
   347  	return ret
   348  }
   349  
   350  // ProviderRequirements returns a description of all of the providers that
   351  // are required to work with the receiving state.
   352  //
   353  // Because the state does not track specific version information for providers,
   354  // the requirements returned by this method will always be unconstrained.
   355  // The result should usually be merged with a Requirements derived from the
   356  // current configuration in order to apply some constraints.
   357  func (s *State) ProviderRequirements() getproviders.Requirements {
   358  	configAddrs := s.ProviderAddrs()
   359  	ret := make(getproviders.Requirements, len(configAddrs))
   360  	for _, configAddr := range configAddrs {
   361  		ret[configAddr.Provider] = nil // unconstrained dependency
   362  	}
   363  	return ret
   364  }
   365  
   366  // PruneResourceHusks is a specialized method that will remove any Resource
   367  // objects that do not contain any instances, even if they have an EachMode.
   368  //
   369  // This should generally be used only after a "terraform destroy" operation,
   370  // to finalize the cleanup of the state. It is not correct to use this after
   371  // other operations because if a resource has "count = 0" or "for_each" over
   372  // an empty collection then we want to retain it in the state so that references
   373  // to it, particularly in "strange" contexts like "terraform console", can be
   374  // properly resolved.
   375  //
   376  // This method MUST NOT be called concurrently with other readers and writers
   377  // of the receiving state.
   378  func (s *State) PruneResourceHusks() {
   379  	for _, m := range s.Modules {
   380  		m.PruneResourceHusks()
   381  		if len(m.Resources) == 0 && !m.Addr.IsRoot() {
   382  			s.RemoveModule(m.Addr)
   383  		}
   384  	}
   385  }
   386  
   387  // SyncWrapper returns a SyncState object wrapping the receiver.
   388  func (s *State) SyncWrapper() *SyncState {
   389  	return &SyncState{
   390  		state: s,
   391  	}
   392  }
   393  
   394  // MoveAbsResource moves the given src AbsResource's current state to the new
   395  // dst address. This will panic if the src AbsResource does not exist in state,
   396  // or if there is already a resource at the dst address. It is the caller's
   397  // responsibility to verify the validity of the move (for example, that the src
   398  // and dst are compatible types).
   399  func (s *State) MoveAbsResource(src, dst addrs.AbsResource) {
   400  	// verify that the src address exists and the dst address does not
   401  	rs := s.Resource(src)
   402  	if rs == nil {
   403  		panic(fmt.Sprintf("no state for src address %s", src.String()))
   404  	}
   405  
   406  	ds := s.Resource(dst)
   407  	if ds != nil {
   408  		panic(fmt.Sprintf("dst resource %s already exists", dst.String()))
   409  	}
   410  
   411  	ms := s.Module(src.Module)
   412  	ms.RemoveResource(src.Resource)
   413  
   414  	// Remove the module if it is empty (and not root) after removing the
   415  	// resource.
   416  	if !ms.Addr.IsRoot() && ms.empty() {
   417  		s.RemoveModule(src.Module)
   418  	}
   419  
   420  	// Update the address before adding it to the state
   421  	rs.Addr = dst
   422  	s.EnsureModule(dst.Module).Resources[dst.Resource.String()] = rs
   423  }
   424  
   425  // MaybeMoveAbsResource moves the given src AbsResource's current state to the
   426  // new dst address. This function will succeed if both the src address does not
   427  // exist in state and the dst address does; the return value indicates whether
   428  // or not the move occurred. This function will panic if either the src does not
   429  // exist or the dst does exist (but not both).
   430  func (s *State) MaybeMoveAbsResource(src, dst addrs.AbsResource) bool {
   431  	// Get the source and destinatation addresses from state.
   432  	rs := s.Resource(src)
   433  	ds := s.Resource(dst)
   434  
   435  	// Normal case: the src exists in state, dst does not
   436  	if rs != nil && ds == nil {
   437  		s.MoveAbsResource(src, dst)
   438  		return true
   439  	}
   440  
   441  	if rs == nil && ds != nil {
   442  		// The source is not in state, the destination is. This is not
   443  		// guaranteed to be idempotent since we aren't tracking exact moves, but
   444  		// it's useful information for the caller.
   445  		return false
   446  	} else {
   447  		panic("invalid move")
   448  	}
   449  }
   450  
   451  // MoveAbsResourceInstance moves the given src AbsResourceInstance's current state to
   452  // the new dst address. This will panic if the src AbsResourceInstance does not
   453  // exist in state, or if there is already a resource at the dst address. It is
   454  // the caller's responsibility to verify the validity of the move (for example,
   455  // that the src and dst are compatible types).
   456  func (s *State) MoveAbsResourceInstance(src, dst addrs.AbsResourceInstance) {
   457  	srcInstanceState := s.ResourceInstance(src)
   458  	if srcInstanceState == nil {
   459  		panic(fmt.Sprintf("no state for src address %s", src.String()))
   460  	}
   461  
   462  	dstInstanceState := s.ResourceInstance(dst)
   463  	if dstInstanceState != nil {
   464  		panic(fmt.Sprintf("dst resource %s already exists", dst.String()))
   465  	}
   466  
   467  	srcResourceState := s.Resource(src.ContainingResource())
   468  	srcProviderAddr := srcResourceState.ProviderConfig
   469  	dstResourceAddr := dst.ContainingResource()
   470  
   471  	// Remove the source resource instance from the module's state, and then the
   472  	// module if empty.
   473  	ms := s.Module(src.Module)
   474  	ms.ForgetResourceInstanceAll(src.Resource)
   475  	if !ms.Addr.IsRoot() && ms.empty() {
   476  		s.RemoveModule(src.Module)
   477  	}
   478  
   479  	dstModule := s.EnsureModule(dst.Module)
   480  
   481  	// See if there is already a resource we can add this instance to.
   482  	dstResourceState := s.Resource(dstResourceAddr)
   483  	if dstResourceState == nil {
   484  		// If we're moving to an address without an index then that
   485  		// suggests the user's intent is to establish both the
   486  		// resource and the instance at the same time (since the
   487  		// address covers both). If there's an index in the
   488  		// target then allow creating the new instance here.
   489  		dstModule.SetResourceProvider(
   490  			dstResourceAddr.Resource,
   491  			srcProviderAddr, // in this case, we bring the provider along as if we were moving the whole resource
   492  		)
   493  		dstResourceState = dstModule.Resource(dstResourceAddr.Resource)
   494  	}
   495  
   496  	dstResourceState.Instances[dst.Resource.Key] = srcInstanceState
   497  }
   498  
   499  // MaybeMoveAbsResourceInstance moves the given src AbsResourceInstance's
   500  // current state to the new dst address. This function will succeed if both the
   501  // src address does not exist in state and the dst address does; the return
   502  // value indicates whether or not the move occured. This function will panic if
   503  // either the src does not exist or the dst does exist (but not both).
   504  func (s *State) MaybeMoveAbsResourceInstance(src, dst addrs.AbsResourceInstance) bool {
   505  	// get the src and dst resource instances from state
   506  	rs := s.ResourceInstance(src)
   507  	ds := s.ResourceInstance(dst)
   508  
   509  	// Normal case: the src exists in state, dst does not
   510  	if rs != nil && ds == nil {
   511  		s.MoveAbsResourceInstance(src, dst)
   512  		return true
   513  	}
   514  
   515  	if rs == nil && ds != nil {
   516  		// The source is not in state, the destination is. This is not
   517  		// guaranteed to be idempotent since we aren't tracking exact moves, but
   518  		// it's useful information.
   519  		return false
   520  	} else {
   521  		panic("invalid move")
   522  	}
   523  }
   524  
   525  // MoveModuleInstance moves the given src ModuleInstance's current state to the
   526  // new dst address. This will panic if the src ModuleInstance does not
   527  // exist in state, or if there is already a resource at the dst address. It is
   528  // the caller's responsibility to verify the validity of the move.
   529  func (s *State) MoveModuleInstance(src, dst addrs.ModuleInstance) {
   530  	if src.IsRoot() || dst.IsRoot() {
   531  		panic("cannot move to or from root module")
   532  	}
   533  
   534  	srcMod := s.Module(src)
   535  	if srcMod == nil {
   536  		panic(fmt.Sprintf("no state for src module %s", src.String()))
   537  	}
   538  
   539  	dstMod := s.Module(dst)
   540  	if dstMod != nil {
   541  		panic(fmt.Sprintf("dst module %s already exists in state", dst.String()))
   542  	}
   543  
   544  	s.RemoveModule(src)
   545  
   546  	srcMod.Addr = dst
   547  	s.EnsureModule(dst)
   548  	s.Modules[dst.String()] = srcMod
   549  
   550  	// Update any Resource's addresses.
   551  	if srcMod.Resources != nil {
   552  		for _, r := range srcMod.Resources {
   553  			r.Addr.Module = dst
   554  		}
   555  	}
   556  
   557  	// Update any OutputValues's addresses.
   558  	if srcMod.OutputValues != nil {
   559  		for _, ov := range srcMod.OutputValues {
   560  			ov.Addr.Module = dst
   561  		}
   562  	}
   563  }
   564  
   565  // MaybeMoveModuleInstance moves the given src ModuleInstance's current state to
   566  // the new dst address. This function will succeed if both the src address does
   567  // not exist in state and the dst address does; the return value indicates
   568  // whether or not the move occured. This function will panic if either the src
   569  // does not exist or the dst does exist (but not both).
   570  func (s *State) MaybeMoveModuleInstance(src, dst addrs.ModuleInstance) bool {
   571  	if src.IsRoot() || dst.IsRoot() {
   572  		panic("cannot move to or from root module")
   573  	}
   574  
   575  	srcMod := s.Module(src)
   576  	dstMod := s.Module(dst)
   577  
   578  	// Normal case: the src exists in state, dst does not
   579  	if srcMod != nil && dstMod == nil {
   580  		s.MoveModuleInstance(src, dst)
   581  		return true
   582  	}
   583  
   584  	if srcMod == nil || src.IsRoot() && dstMod != nil {
   585  		// The source is not in state, the destination is. This is not
   586  		// guaranteed to be idempotent since we aren't tracking exact moves, but
   587  		// it's useful information.
   588  		return false
   589  	} else {
   590  		panic("invalid move")
   591  	}
   592  }
   593  
   594  // MoveModule takes a source and destination addrs.Module address, and moves all
   595  // state Modules which are contained by the src address to the new address.
   596  func (s *State) MoveModule(src, dst addrs.AbsModuleCall) {
   597  	if src.Module.IsRoot() || dst.Module.IsRoot() {
   598  		panic("cannot move to or from root module")
   599  	}
   600  
   601  	// Modules only exist as ModuleInstances in state, so we need to check each
   602  	// state Module and see if it is contained by the src address to get a full
   603  	// list of modules to move.
   604  	var srcMIs []*Module
   605  	for _, module := range s.Modules {
   606  		if !module.Addr.IsRoot() {
   607  			if src.Module.TargetContains(module.Addr) {
   608  				srcMIs = append(srcMIs, module)
   609  			}
   610  		}
   611  	}
   612  
   613  	if len(srcMIs) == 0 {
   614  		panic(fmt.Sprintf("no matching module instances found for src module %s", src.String()))
   615  	}
   616  
   617  	for _, ms := range srcMIs {
   618  		newInst := make(addrs.ModuleInstance, len(ms.Addr))
   619  		copy(newInst, ms.Addr)
   620  		if ms.Addr.IsDeclaredByCall(src) {
   621  			// Easy case: we just need to update the last step with the new name
   622  			newInst[len(newInst)-1].Name = dst.Call.Name
   623  		} else {
   624  			// Trickier: this Module is a submodule. we need to find and update
   625  			// only that appropriate step
   626  			for s := range newInst {
   627  				if newInst[s].Name == src.Call.Name {
   628  					newInst[s].Name = dst.Call.Name
   629  				}
   630  			}
   631  		}
   632  		s.MoveModuleInstance(ms.Addr, newInst)
   633  	}
   634  }