github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/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.String() == o.String()
    33  }
    34  
    35  // Instance produces the address for a specific instance of the receiver
    36  // that is idenfied by the given key.
    37  func (r Resource) Instance(key InstanceKey) ResourceInstance {
    38  	return ResourceInstance{
    39  		Resource: r,
    40  		Key:      key,
    41  	}
    42  }
    43  
    44  // Absolute returns an AbsResource from the receiver and the given module
    45  // instance address.
    46  func (r Resource) Absolute(module ModuleInstance) AbsResource {
    47  	return AbsResource{
    48  		Module:   module,
    49  		Resource: r,
    50  	}
    51  }
    52  
    53  // DefaultProviderConfig returns the address of the provider configuration
    54  // that should be used for the resource identified by the reciever if it
    55  // does not have a provider configuration address explicitly set in
    56  // configuration.
    57  //
    58  // This method is not able to verify that such a configuration exists, nor
    59  // represent the behavior of automatically inheriting certain provider
    60  // configurations from parent modules. It just does a static analysis of the
    61  // receiving address and returns an address to start from, relative to the
    62  // same module that contains the resource.
    63  func (r Resource) DefaultProviderConfig() ProviderConfig {
    64  	typeName := r.Type
    65  	if under := strings.Index(typeName, "_"); under != -1 {
    66  		typeName = typeName[:under]
    67  	}
    68  
    69  	return ProviderConfig{
    70  		Type: NewLegacyProvider(typeName),
    71  	}
    72  }
    73  
    74  // ResourceInstance is an address for a specific instance of a resource.
    75  // When a resource is defined in configuration with "count" or "for_each" it
    76  // produces zero or more instances, which can be addressed using this type.
    77  type ResourceInstance struct {
    78  	referenceable
    79  	Resource Resource
    80  	Key      InstanceKey
    81  }
    82  
    83  func (r ResourceInstance) ContainingResource() Resource {
    84  	return r.Resource
    85  }
    86  
    87  func (r ResourceInstance) String() string {
    88  	if r.Key == NoKey {
    89  		return r.Resource.String()
    90  	}
    91  	return r.Resource.String() + r.Key.String()
    92  }
    93  
    94  func (r ResourceInstance) Equal(o ResourceInstance) bool {
    95  	return r.String() == o.String()
    96  }
    97  
    98  // Absolute returns an AbsResourceInstance from the receiver and the given module
    99  // instance address.
   100  func (r ResourceInstance) Absolute(module ModuleInstance) AbsResourceInstance {
   101  	return AbsResourceInstance{
   102  		Module:   module,
   103  		Resource: r,
   104  	}
   105  }
   106  
   107  // AbsResource is an absolute address for a resource under a given module path.
   108  type AbsResource struct {
   109  	targetable
   110  	Module   ModuleInstance
   111  	Resource Resource
   112  }
   113  
   114  // Resource returns the address of a particular resource within the receiver.
   115  func (m ModuleInstance) Resource(mode ResourceMode, typeName string, name string) AbsResource {
   116  	return AbsResource{
   117  		Module: m,
   118  		Resource: Resource{
   119  			Mode: mode,
   120  			Type: typeName,
   121  			Name: name,
   122  		},
   123  	}
   124  }
   125  
   126  // Instance produces the address for a specific instance of the receiver
   127  // that is idenfied by the given key.
   128  func (r AbsResource) Instance(key InstanceKey) AbsResourceInstance {
   129  	return AbsResourceInstance{
   130  		Module:   r.Module,
   131  		Resource: r.Resource.Instance(key),
   132  	}
   133  }
   134  
   135  // TargetContains implements Targetable by returning true if the given other
   136  // address is either equal to the receiver or is an instance of the
   137  // receiver.
   138  func (r AbsResource) TargetContains(other Targetable) bool {
   139  	switch to := other.(type) {
   140  
   141  	case AbsResource:
   142  		// We'll use our stringification as a cheat-ish way to test for equality.
   143  		return to.String() == r.String()
   144  
   145  	case AbsResourceInstance:
   146  		return r.TargetContains(to.ContainingResource())
   147  
   148  	default:
   149  		return false
   150  
   151  	}
   152  }
   153  
   154  func (r AbsResource) String() string {
   155  	if len(r.Module) == 0 {
   156  		return r.Resource.String()
   157  	}
   158  	return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String())
   159  }
   160  
   161  func (r AbsResource) Equal(o AbsResource) bool {
   162  	return r.String() == o.String()
   163  }
   164  
   165  // AbsResourceInstance is an absolute address for a resource instance under a
   166  // given module path.
   167  type AbsResourceInstance struct {
   168  	targetable
   169  	Module   ModuleInstance
   170  	Resource ResourceInstance
   171  }
   172  
   173  // ResourceInstance returns the address of a particular resource instance within the receiver.
   174  func (m ModuleInstance) ResourceInstance(mode ResourceMode, typeName string, name string, key InstanceKey) AbsResourceInstance {
   175  	return AbsResourceInstance{
   176  		Module: m,
   177  		Resource: ResourceInstance{
   178  			Resource: Resource{
   179  				Mode: mode,
   180  				Type: typeName,
   181  				Name: name,
   182  			},
   183  			Key: key,
   184  		},
   185  	}
   186  }
   187  
   188  // ContainingResource returns the address of the resource that contains the
   189  // receving resource instance. In other words, it discards the key portion
   190  // of the address to produce an AbsResource value.
   191  func (r AbsResourceInstance) ContainingResource() AbsResource {
   192  	return AbsResource{
   193  		Module:   r.Module,
   194  		Resource: r.Resource.ContainingResource(),
   195  	}
   196  }
   197  
   198  // TargetContains implements Targetable by returning true if the given other
   199  // address is equal to the receiver.
   200  func (r AbsResourceInstance) TargetContains(other Targetable) bool {
   201  	switch to := other.(type) {
   202  
   203  	case AbsResourceInstance:
   204  		// We'll use our stringification as a cheat-ish way to test for equality.
   205  		return to.String() == r.String()
   206  
   207  	default:
   208  		return false
   209  
   210  	}
   211  }
   212  
   213  func (r AbsResourceInstance) String() string {
   214  	if len(r.Module) == 0 {
   215  		return r.Resource.String()
   216  	}
   217  	return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String())
   218  }
   219  
   220  func (r AbsResourceInstance) Equal(o AbsResourceInstance) bool {
   221  	return r.String() == o.String()
   222  }
   223  
   224  // Less returns true if the receiver should sort before the given other value
   225  // in a sorted list of addresses.
   226  func (r AbsResourceInstance) Less(o AbsResourceInstance) bool {
   227  	switch {
   228  
   229  	case len(r.Module) != len(o.Module):
   230  		return len(r.Module) < len(o.Module)
   231  
   232  	case r.Module.String() != o.Module.String():
   233  		return r.Module.Less(o.Module)
   234  
   235  	case r.Resource.Resource.Mode != o.Resource.Resource.Mode:
   236  		return r.Resource.Resource.Mode == DataResourceMode
   237  
   238  	case r.Resource.Resource.Type != o.Resource.Resource.Type:
   239  		return r.Resource.Resource.Type < o.Resource.Resource.Type
   240  
   241  	case r.Resource.Resource.Name != o.Resource.Resource.Name:
   242  		return r.Resource.Resource.Name < o.Resource.Resource.Name
   243  
   244  	case r.Resource.Key != o.Resource.Key:
   245  		return InstanceKeyLess(r.Resource.Key, o.Resource.Key)
   246  
   247  	default:
   248  		return false
   249  
   250  	}
   251  }
   252  
   253  // ResourceMode defines which lifecycle applies to a given resource. Each
   254  // resource lifecycle has a slightly different address format.
   255  type ResourceMode rune
   256  
   257  //go:generate go run golang.org/x/tools/cmd/stringer -type ResourceMode
   258  
   259  const (
   260  	// InvalidResourceMode is the zero value of ResourceMode and is not
   261  	// a valid resource mode.
   262  	InvalidResourceMode ResourceMode = 0
   263  
   264  	// ManagedResourceMode indicates a managed resource, as defined by
   265  	// "resource" blocks in configuration.
   266  	ManagedResourceMode ResourceMode = 'M'
   267  
   268  	// DataResourceMode indicates a data resource, as defined by
   269  	// "data" blocks in configuration.
   270  	DataResourceMode ResourceMode = 'D'
   271  )