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