github.com/cycloidio/terraform@v1.1.10-0.20220513142504-76d5c768dc63/addrs/resource.go (about)

     1  package addrs
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  )
     7  
     8  // Resource is an address for a resource block within configuration, which
     9  // contains potentially-multiple resource instances if that configuration
    10  // block uses "count" or "for_each".
    11  type Resource struct {
    12  	referenceable
    13  	Mode ResourceMode
    14  	Type string
    15  	Name string
    16  }
    17  
    18  func (r Resource) String() string {
    19  	switch r.Mode {
    20  	case ManagedResourceMode:
    21  		return fmt.Sprintf("%s.%s", r.Type, r.Name)
    22  	case DataResourceMode:
    23  		return fmt.Sprintf("data.%s.%s", r.Type, r.Name)
    24  	default:
    25  		// Should never happen, but we'll return a string here rather than
    26  		// crashing just in case it does.
    27  		return fmt.Sprintf("<invalid>.%s.%s", r.Type, r.Name)
    28  	}
    29  }
    30  
    31  func (r Resource) Equal(o Resource) bool {
    32  	return r.Mode == o.Mode && r.Name == o.Name && r.Type == o.Type
    33  }
    34  
    35  func (r Resource) UniqueKey() UniqueKey {
    36  	return r // A Resource is its own UniqueKey
    37  }
    38  
    39  func (r Resource) uniqueKeySigil() {}
    40  
    41  // Instance produces the address for a specific instance of the receiver
    42  // that is idenfied by the given key.
    43  func (r Resource) Instance(key InstanceKey) ResourceInstance {
    44  	return ResourceInstance{
    45  		Resource: r,
    46  		Key:      key,
    47  	}
    48  }
    49  
    50  // Absolute returns an AbsResource from the receiver and the given module
    51  // instance address.
    52  func (r Resource) Absolute(module ModuleInstance) AbsResource {
    53  	return AbsResource{
    54  		Module:   module,
    55  		Resource: r,
    56  	}
    57  }
    58  
    59  // InModule returns a ConfigResource from the receiver and the given module
    60  // address.
    61  func (r Resource) InModule(module Module) ConfigResource {
    62  	return ConfigResource{
    63  		Module:   module,
    64  		Resource: r,
    65  	}
    66  }
    67  
    68  // ImpliedProvider returns the implied provider type name, for e.g. the "aws" in
    69  // "aws_instance"
    70  func (r Resource) ImpliedProvider() string {
    71  	typeName := r.Type
    72  	if under := strings.Index(typeName, "_"); under != -1 {
    73  		typeName = typeName[:under]
    74  	}
    75  
    76  	return typeName
    77  }
    78  
    79  // ResourceInstance is an address for a specific instance of a resource.
    80  // When a resource is defined in configuration with "count" or "for_each" it
    81  // produces zero or more instances, which can be addressed using this type.
    82  type ResourceInstance struct {
    83  	referenceable
    84  	Resource Resource
    85  	Key      InstanceKey
    86  }
    87  
    88  func (r ResourceInstance) ContainingResource() Resource {
    89  	return r.Resource
    90  }
    91  
    92  func (r ResourceInstance) String() string {
    93  	if r.Key == NoKey {
    94  		return r.Resource.String()
    95  	}
    96  	return r.Resource.String() + r.Key.String()
    97  }
    98  
    99  func (r ResourceInstance) Equal(o ResourceInstance) bool {
   100  	return r.Key == o.Key && r.Resource.Equal(o.Resource)
   101  }
   102  
   103  func (r ResourceInstance) UniqueKey() UniqueKey {
   104  	return r // A ResourceInstance is its own UniqueKey
   105  }
   106  
   107  func (r ResourceInstance) uniqueKeySigil() {}
   108  
   109  // Absolute returns an AbsResourceInstance from the receiver and the given module
   110  // instance address.
   111  func (r ResourceInstance) Absolute(module ModuleInstance) AbsResourceInstance {
   112  	return AbsResourceInstance{
   113  		Module:   module,
   114  		Resource: r,
   115  	}
   116  }
   117  
   118  // AbsResource is an absolute address for a resource under a given module path.
   119  type AbsResource struct {
   120  	targetable
   121  	Module   ModuleInstance
   122  	Resource Resource
   123  }
   124  
   125  // Resource returns the address of a particular resource within the receiver.
   126  func (m ModuleInstance) Resource(mode ResourceMode, typeName string, name string) AbsResource {
   127  	return AbsResource{
   128  		Module: m,
   129  		Resource: Resource{
   130  			Mode: mode,
   131  			Type: typeName,
   132  			Name: name,
   133  		},
   134  	}
   135  }
   136  
   137  // Instance produces the address for a specific instance of the receiver
   138  // that is idenfied by the given key.
   139  func (r AbsResource) Instance(key InstanceKey) AbsResourceInstance {
   140  	return AbsResourceInstance{
   141  		Module:   r.Module,
   142  		Resource: r.Resource.Instance(key),
   143  	}
   144  }
   145  
   146  // Config returns the unexpanded ConfigResource for this AbsResource.
   147  func (r AbsResource) Config() ConfigResource {
   148  	return ConfigResource{
   149  		Module:   r.Module.Module(),
   150  		Resource: r.Resource,
   151  	}
   152  }
   153  
   154  // TargetContains implements Targetable by returning true if the given other
   155  // address is either equal to the receiver or is an instance of the
   156  // receiver.
   157  func (r AbsResource) TargetContains(other Targetable) bool {
   158  	switch to := other.(type) {
   159  
   160  	case AbsResource:
   161  		// We'll use our stringification as a cheat-ish way to test for equality.
   162  		return to.String() == r.String()
   163  
   164  	case ConfigResource:
   165  		// if an absolute resource from parsing a target address contains a
   166  		// ConfigResource, the string representation will match
   167  		return to.String() == r.String()
   168  
   169  	case AbsResourceInstance:
   170  		return r.TargetContains(to.ContainingResource())
   171  
   172  	default:
   173  		return false
   174  
   175  	}
   176  }
   177  
   178  func (r AbsResource) AddrType() TargetableAddrType {
   179  	return AbsResourceAddrType
   180  }
   181  
   182  func (r AbsResource) String() string {
   183  	if len(r.Module) == 0 {
   184  		return r.Resource.String()
   185  	}
   186  	return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String())
   187  }
   188  
   189  // AffectedAbsResource returns the AbsResource.
   190  func (r AbsResource) AffectedAbsResource() AbsResource {
   191  	return r
   192  }
   193  
   194  func (r AbsResource) Equal(o AbsResource) bool {
   195  	return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource)
   196  }
   197  
   198  func (r AbsResource) absMoveableSigil() {
   199  	// AbsResource is moveable
   200  }
   201  
   202  type absResourceKey string
   203  
   204  func (r absResourceKey) uniqueKeySigil() {}
   205  
   206  func (r AbsResource) UniqueKey() UniqueKey {
   207  	return absResourceKey(r.String())
   208  }
   209  
   210  // AbsResourceInstance is an absolute address for a resource instance under a
   211  // given module path.
   212  type AbsResourceInstance struct {
   213  	targetable
   214  	Module   ModuleInstance
   215  	Resource ResourceInstance
   216  }
   217  
   218  // ResourceInstance returns the address of a particular resource instance within the receiver.
   219  func (m ModuleInstance) ResourceInstance(mode ResourceMode, typeName string, name string, key InstanceKey) AbsResourceInstance {
   220  	return AbsResourceInstance{
   221  		Module: m,
   222  		Resource: ResourceInstance{
   223  			Resource: Resource{
   224  				Mode: mode,
   225  				Type: typeName,
   226  				Name: name,
   227  			},
   228  			Key: key,
   229  		},
   230  	}
   231  }
   232  
   233  // ContainingResource returns the address of the resource that contains the
   234  // receving resource instance. In other words, it discards the key portion
   235  // of the address to produce an AbsResource value.
   236  func (r AbsResourceInstance) ContainingResource() AbsResource {
   237  	return AbsResource{
   238  		Module:   r.Module,
   239  		Resource: r.Resource.ContainingResource(),
   240  	}
   241  }
   242  
   243  // TargetContains implements Targetable by returning true if the given other
   244  // address is equal to the receiver.
   245  func (r AbsResourceInstance) TargetContains(other Targetable) bool {
   246  	switch to := other.(type) {
   247  
   248  	// while we currently don't start with an AbsResourceInstance as a target
   249  	// address, check all resource types for consistency.
   250  	case AbsResourceInstance:
   251  		// We'll use our stringification as a cheat-ish way to test for equality.
   252  		return to.String() == r.String()
   253  	case ConfigResource:
   254  		return to.String() == r.String()
   255  	case AbsResource:
   256  		return to.String() == r.String()
   257  
   258  	default:
   259  		return false
   260  
   261  	}
   262  }
   263  
   264  func (r AbsResourceInstance) AddrType() TargetableAddrType {
   265  	return AbsResourceInstanceAddrType
   266  }
   267  
   268  func (r AbsResourceInstance) String() string {
   269  	if len(r.Module) == 0 {
   270  		return r.Resource.String()
   271  	}
   272  	return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String())
   273  }
   274  
   275  // AffectedAbsResource returns the AbsResource for the instance.
   276  func (r AbsResourceInstance) AffectedAbsResource() AbsResource {
   277  	return AbsResource{
   278  		Module:   r.Module,
   279  		Resource: r.Resource.Resource,
   280  	}
   281  }
   282  
   283  func (r AbsResourceInstance) Equal(o AbsResourceInstance) bool {
   284  	return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource)
   285  }
   286  
   287  // Less returns true if the receiver should sort before the given other value
   288  // in a sorted list of addresses.
   289  func (r AbsResourceInstance) Less(o AbsResourceInstance) bool {
   290  	switch {
   291  
   292  	case len(r.Module) != len(o.Module):
   293  		return len(r.Module) < len(o.Module)
   294  
   295  	case r.Module.String() != o.Module.String():
   296  		return r.Module.Less(o.Module)
   297  
   298  	case r.Resource.Resource.Mode != o.Resource.Resource.Mode:
   299  		return r.Resource.Resource.Mode == DataResourceMode
   300  
   301  	case r.Resource.Resource.Type != o.Resource.Resource.Type:
   302  		return r.Resource.Resource.Type < o.Resource.Resource.Type
   303  
   304  	case r.Resource.Resource.Name != o.Resource.Resource.Name:
   305  		return r.Resource.Resource.Name < o.Resource.Resource.Name
   306  
   307  	case r.Resource.Key != o.Resource.Key:
   308  		return InstanceKeyLess(r.Resource.Key, o.Resource.Key)
   309  
   310  	default:
   311  		return false
   312  
   313  	}
   314  }
   315  
   316  type absResourceInstanceKey string
   317  
   318  func (r AbsResourceInstance) UniqueKey() UniqueKey {
   319  	return absResourceInstanceKey(r.String())
   320  }
   321  
   322  func (r absResourceInstanceKey) uniqueKeySigil() {}
   323  
   324  func (r AbsResourceInstance) absMoveableSigil() {
   325  	// AbsResourceInstance is moveable
   326  }
   327  
   328  // ConfigResource is an address for a resource within a configuration.
   329  type ConfigResource struct {
   330  	targetable
   331  	Module   Module
   332  	Resource Resource
   333  }
   334  
   335  // Resource returns the address of a particular resource within the module.
   336  func (m Module) Resource(mode ResourceMode, typeName string, name string) ConfigResource {
   337  	return ConfigResource{
   338  		Module: m,
   339  		Resource: Resource{
   340  			Mode: mode,
   341  			Type: typeName,
   342  			Name: name,
   343  		},
   344  	}
   345  }
   346  
   347  // Absolute produces the address for the receiver within a specific module instance.
   348  func (r ConfigResource) Absolute(module ModuleInstance) AbsResource {
   349  	return AbsResource{
   350  		Module:   module,
   351  		Resource: r.Resource,
   352  	}
   353  }
   354  
   355  // TargetContains implements Targetable by returning true if the given other
   356  // address is either equal to the receiver or is an instance of the
   357  // receiver.
   358  func (r ConfigResource) TargetContains(other Targetable) bool {
   359  	switch to := other.(type) {
   360  	case ConfigResource:
   361  		// We'll use our stringification as a cheat-ish way to test for equality.
   362  		return to.String() == r.String()
   363  	case AbsResource:
   364  		return r.TargetContains(to.Config())
   365  	case AbsResourceInstance:
   366  		return r.TargetContains(to.ContainingResource())
   367  	default:
   368  		return false
   369  	}
   370  }
   371  
   372  func (r ConfigResource) AddrType() TargetableAddrType {
   373  	return ConfigResourceAddrType
   374  }
   375  
   376  func (r ConfigResource) String() string {
   377  	if len(r.Module) == 0 {
   378  		return r.Resource.String()
   379  	}
   380  	return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String())
   381  }
   382  
   383  func (r ConfigResource) Equal(o ConfigResource) bool {
   384  	return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource)
   385  }
   386  
   387  func (r ConfigResource) configMoveableSigil() {
   388  	// AbsResource is moveable
   389  }
   390  
   391  // ResourceMode defines which lifecycle applies to a given resource. Each
   392  // resource lifecycle has a slightly different address format.
   393  type ResourceMode rune
   394  
   395  //go:generate go run golang.org/x/tools/cmd/stringer -type ResourceMode
   396  
   397  const (
   398  	// InvalidResourceMode is the zero value of ResourceMode and is not
   399  	// a valid resource mode.
   400  	InvalidResourceMode ResourceMode = 0
   401  
   402  	// ManagedResourceMode indicates a managed resource, as defined by
   403  	// "resource" blocks in configuration.
   404  	ManagedResourceMode ResourceMode = 'M'
   405  
   406  	// DataResourceMode indicates a data resource, as defined by
   407  	// "data" blocks in configuration.
   408  	DataResourceMode ResourceMode = 'D'
   409  )