| package addrs |
| |
| import ( |
| "fmt" |
| "strings" |
| ) |
| |
| // Resource is an address for a resource block within configuration, which |
| // contains potentially-multiple resource instances if that configuration |
| // block uses "count" or "for_each". |
| type Resource struct { |
| referenceable |
| Mode ResourceMode |
| Type string |
| Name string |
| } |
| |
| func (r Resource) String() string { |
| switch r.Mode { |
| case ManagedResourceMode: |
| return fmt.Sprintf("%s.%s", r.Type, r.Name) |
| case DataResourceMode: |
| return fmt.Sprintf("data.%s.%s", r.Type, r.Name) |
| default: |
| // Should never happen, but we'll return a string here rather than |
| // crashing just in case it does. |
| return fmt.Sprintf("<invalid>.%s.%s", r.Type, r.Name) |
| } |
| } |
| |
| func (r Resource) Equal(o Resource) bool { |
| return r.Mode == o.Mode && r.Name == o.Name && r.Type == o.Type |
| } |
| |
| func (r Resource) Less(o Resource) bool { |
| switch { |
| case r.Mode != o.Mode: |
| return r.Mode == DataResourceMode |
| |
| case r.Type != o.Type: |
| return r.Type < o.Type |
| |
| case r.Name != o.Name: |
| return r.Name < o.Name |
| |
| default: |
| return false |
| } |
| } |
| |
| func (r Resource) UniqueKey() UniqueKey { |
| return r // A Resource is its own UniqueKey |
| } |
| |
| func (r Resource) uniqueKeySigil() {} |
| |
| // Instance produces the address for a specific instance of the receiver |
| // that is idenfied by the given key. |
| func (r Resource) Instance(key InstanceKey) ResourceInstance { |
| return ResourceInstance{ |
| Resource: r, |
| Key: key, |
| } |
| } |
| |
| // Absolute returns an AbsResource from the receiver and the given module |
| // instance address. |
| func (r Resource) Absolute(module ModuleInstance) AbsResource { |
| return AbsResource{ |
| Module: module, |
| Resource: r, |
| } |
| } |
| |
| // InModule returns a ConfigResource from the receiver and the given module |
| // address. |
| func (r Resource) InModule(module Module) ConfigResource { |
| return ConfigResource{ |
| Module: module, |
| Resource: r, |
| } |
| } |
| |
| // ImpliedProvider returns the implied provider type name, for e.g. the "aws" in |
| // "aws_instance" |
| func (r Resource) ImpliedProvider() string { |
| typeName := r.Type |
| if under := strings.Index(typeName, "_"); under != -1 { |
| typeName = typeName[:under] |
| } |
| |
| return typeName |
| } |
| |
| // ResourceInstance is an address for a specific instance of a resource. |
| // When a resource is defined in configuration with "count" or "for_each" it |
| // produces zero or more instances, which can be addressed using this type. |
| type ResourceInstance struct { |
| referenceable |
| Resource Resource |
| Key InstanceKey |
| } |
| |
| func (r ResourceInstance) ContainingResource() Resource { |
| return r.Resource |
| } |
| |
| func (r ResourceInstance) String() string { |
| if r.Key == NoKey { |
| return r.Resource.String() |
| } |
| return r.Resource.String() + r.Key.String() |
| } |
| |
| func (r ResourceInstance) Equal(o ResourceInstance) bool { |
| return r.Key == o.Key && r.Resource.Equal(o.Resource) |
| } |
| |
| func (r ResourceInstance) Less(o ResourceInstance) bool { |
| if !r.Resource.Equal(o.Resource) { |
| return r.Resource.Less(o.Resource) |
| } |
| |
| if r.Key != o.Key { |
| return InstanceKeyLess(r.Key, o.Key) |
| } |
| |
| return false |
| } |
| |
| func (r ResourceInstance) UniqueKey() UniqueKey { |
| return r // A ResourceInstance is its own UniqueKey |
| } |
| |
| func (r ResourceInstance) uniqueKeySigil() {} |
| |
| // Absolute returns an AbsResourceInstance from the receiver and the given module |
| // instance address. |
| func (r ResourceInstance) Absolute(module ModuleInstance) AbsResourceInstance { |
| return AbsResourceInstance{ |
| Module: module, |
| Resource: r, |
| } |
| } |
| |
| // AbsResource is an absolute address for a resource under a given module path. |
| type AbsResource struct { |
| targetable |
| Module ModuleInstance |
| Resource Resource |
| } |
| |
| // Resource returns the address of a particular resource within the receiver. |
| func (m ModuleInstance) Resource(mode ResourceMode, typeName string, name string) AbsResource { |
| return AbsResource{ |
| Module: m, |
| Resource: Resource{ |
| Mode: mode, |
| Type: typeName, |
| Name: name, |
| }, |
| } |
| } |
| |
| // Instance produces the address for a specific instance of the receiver |
| // that is idenfied by the given key. |
| func (r AbsResource) Instance(key InstanceKey) AbsResourceInstance { |
| return AbsResourceInstance{ |
| Module: r.Module, |
| Resource: r.Resource.Instance(key), |
| } |
| } |
| |
| // Config returns the unexpanded ConfigResource for this AbsResource. |
| func (r AbsResource) Config() ConfigResource { |
| return ConfigResource{ |
| Module: r.Module.Module(), |
| Resource: r.Resource, |
| } |
| } |
| |
| // TargetContains implements Targetable by returning true if the given other |
| // address is either equal to the receiver or is an instance of the |
| // receiver. |
| func (r AbsResource) TargetContains(other Targetable) bool { |
| switch to := other.(type) { |
| |
| case AbsResource: |
| // We'll use our stringification as a cheat-ish way to test for equality. |
| return to.String() == r.String() |
| |
| case ConfigResource: |
| // if an absolute resource from parsing a target address contains a |
| // ConfigResource, the string representation will match |
| return to.String() == r.String() |
| |
| case AbsResourceInstance: |
| return r.TargetContains(to.ContainingResource()) |
| |
| default: |
| return false |
| |
| } |
| } |
| |
| func (r AbsResource) AddrType() TargetableAddrType { |
| return AbsResourceAddrType |
| } |
| |
| func (r AbsResource) String() string { |
| if len(r.Module) == 0 { |
| return r.Resource.String() |
| } |
| return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String()) |
| } |
| |
| // AffectedAbsResource returns the AbsResource. |
| func (r AbsResource) AffectedAbsResource() AbsResource { |
| return r |
| } |
| |
| func (r AbsResource) Equal(o AbsResource) bool { |
| return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource) |
| } |
| |
| func (r AbsResource) Less(o AbsResource) bool { |
| if !r.Module.Equal(o.Module) { |
| return r.Module.Less(o.Module) |
| } |
| |
| if !r.Resource.Equal(o.Resource) { |
| return r.Resource.Less(o.Resource) |
| } |
| |
| return false |
| } |
| |
| func (r AbsResource) absMoveableSigil() { |
| // AbsResource is moveable |
| } |
| |
| type absResourceKey string |
| |
| func (r absResourceKey) uniqueKeySigil() {} |
| |
| func (r AbsResource) UniqueKey() UniqueKey { |
| return absResourceKey(r.String()) |
| } |
| |
| // AbsResourceInstance is an absolute address for a resource instance under a |
| // given module path. |
| type AbsResourceInstance struct { |
| targetable |
| Module ModuleInstance |
| Resource ResourceInstance |
| } |
| |
| // ResourceInstance returns the address of a particular resource instance within the receiver. |
| func (m ModuleInstance) ResourceInstance(mode ResourceMode, typeName string, name string, key InstanceKey) AbsResourceInstance { |
| return AbsResourceInstance{ |
| Module: m, |
| Resource: ResourceInstance{ |
| Resource: Resource{ |
| Mode: mode, |
| Type: typeName, |
| Name: name, |
| }, |
| Key: key, |
| }, |
| } |
| } |
| |
| // ContainingResource returns the address of the resource that contains the |
| // receving resource instance. In other words, it discards the key portion |
| // of the address to produce an AbsResource value. |
| func (r AbsResourceInstance) ContainingResource() AbsResource { |
| return AbsResource{ |
| Module: r.Module, |
| Resource: r.Resource.ContainingResource(), |
| } |
| } |
| |
| // ConfigResource returns the address of the configuration block that declared |
| // this instance. |
| func (r AbsResourceInstance) ConfigResource() ConfigResource { |
| return ConfigResource{ |
| Module: r.Module.Module(), |
| Resource: r.Resource.Resource, |
| } |
| } |
| |
| // TargetContains implements Targetable by returning true if the given other |
| // address is equal to the receiver. |
| func (r AbsResourceInstance) TargetContains(other Targetable) bool { |
| switch to := other.(type) { |
| |
| // while we currently don't start with an AbsResourceInstance as a target |
| // address, check all resource types for consistency. |
| case AbsResourceInstance: |
| // We'll use our stringification as a cheat-ish way to test for equality. |
| return to.String() == r.String() |
| case ConfigResource: |
| return to.String() == r.String() |
| case AbsResource: |
| return to.String() == r.String() |
| |
| default: |
| return false |
| |
| } |
| } |
| |
| func (r AbsResourceInstance) AddrType() TargetableAddrType { |
| return AbsResourceInstanceAddrType |
| } |
| |
| func (r AbsResourceInstance) String() string { |
| if len(r.Module) == 0 { |
| return r.Resource.String() |
| } |
| return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String()) |
| } |
| |
| // AffectedAbsResource returns the AbsResource for the instance. |
| func (r AbsResourceInstance) AffectedAbsResource() AbsResource { |
| return AbsResource{ |
| Module: r.Module, |
| Resource: r.Resource.Resource, |
| } |
| } |
| |
| func (r AbsResourceInstance) Check(t CheckType, i int) Check { |
| return Check{ |
| Container: r, |
| Type: t, |
| Index: i, |
| } |
| } |
| |
| func (v AbsResourceInstance) CheckableKind() CheckableKind { |
| return CheckableResource |
| } |
| |
| func (r AbsResourceInstance) Equal(o AbsResourceInstance) bool { |
| return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource) |
| } |
| |
| // Less returns true if the receiver should sort before the given other value |
| // in a sorted list of addresses. |
| func (r AbsResourceInstance) Less(o AbsResourceInstance) bool { |
| if !r.Module.Equal(o.Module) { |
| return r.Module.Less(o.Module) |
| } |
| |
| if !r.Resource.Equal(o.Resource) { |
| return r.Resource.Less(o.Resource) |
| } |
| |
| return false |
| } |
| |
| // AbsResourceInstance is a Checkable |
| func (r AbsResourceInstance) checkableSigil() {} |
| |
| func (r AbsResourceInstance) ConfigCheckable() ConfigCheckable { |
| // The ConfigCheckable for an AbsResourceInstance is its ConfigResource. |
| return r.ConfigResource() |
| } |
| |
| type absResourceInstanceKey string |
| |
| func (r AbsResourceInstance) UniqueKey() UniqueKey { |
| return absResourceInstanceKey(r.String()) |
| } |
| |
| func (r absResourceInstanceKey) uniqueKeySigil() {} |
| |
| func (r AbsResourceInstance) absMoveableSigil() { |
| // AbsResourceInstance is moveable |
| } |
| |
| // ConfigResource is an address for a resource within a configuration. |
| type ConfigResource struct { |
| targetable |
| Module Module |
| Resource Resource |
| } |
| |
| // Resource returns the address of a particular resource within the module. |
| func (m Module) Resource(mode ResourceMode, typeName string, name string) ConfigResource { |
| return ConfigResource{ |
| Module: m, |
| Resource: Resource{ |
| Mode: mode, |
| Type: typeName, |
| Name: name, |
| }, |
| } |
| } |
| |
| // Absolute produces the address for the receiver within a specific module instance. |
| func (r ConfigResource) Absolute(module ModuleInstance) AbsResource { |
| return AbsResource{ |
| Module: module, |
| Resource: r.Resource, |
| } |
| } |
| |
| // TargetContains implements Targetable by returning true if the given other |
| // address is either equal to the receiver or is an instance of the |
| // receiver. |
| func (r ConfigResource) TargetContains(other Targetable) bool { |
| switch to := other.(type) { |
| case ConfigResource: |
| // We'll use our stringification as a cheat-ish way to test for equality. |
| return to.String() == r.String() |
| case AbsResource: |
| return r.TargetContains(to.Config()) |
| case AbsResourceInstance: |
| return r.TargetContains(to.ContainingResource()) |
| default: |
| return false |
| } |
| } |
| |
| func (r ConfigResource) AddrType() TargetableAddrType { |
| return ConfigResourceAddrType |
| } |
| |
| func (r ConfigResource) String() string { |
| if len(r.Module) == 0 { |
| return r.Resource.String() |
| } |
| return fmt.Sprintf("%s.%s", r.Module.String(), r.Resource.String()) |
| } |
| |
| func (r ConfigResource) Equal(o ConfigResource) bool { |
| return r.Module.Equal(o.Module) && r.Resource.Equal(o.Resource) |
| } |
| |
| func (r ConfigResource) UniqueKey() UniqueKey { |
| return configResourceKey(r.String()) |
| } |
| |
| func (r ConfigResource) configMoveableSigil() { |
| // ConfigResource is moveable |
| } |
| |
| func (r ConfigResource) configCheckableSigil() { |
| // ConfigResource represents a configuration object that declares checkable objects |
| } |
| |
| func (v ConfigResource) CheckableKind() CheckableKind { |
| return CheckableResource |
| } |
| |
| type configResourceKey string |
| |
| func (k configResourceKey) uniqueKeySigil() {} |
| |
| // ResourceMode defines which lifecycle applies to a given resource. Each |
| // resource lifecycle has a slightly different address format. |
| type ResourceMode rune |
| |
| //go:generate go run golang.org/x/tools/cmd/stringer -type ResourceMode |
| |
| const ( |
| // InvalidResourceMode is the zero value of ResourceMode and is not |
| // a valid resource mode. |
| InvalidResourceMode ResourceMode = 0 |
| |
| // ManagedResourceMode indicates a managed resource, as defined by |
| // "resource" blocks in configuration. |
| ManagedResourceMode ResourceMode = 'M' |
| |
| // DataResourceMode indicates a data resource, as defined by |
| // "data" blocks in configuration. |
| DataResourceMode ResourceMode = 'D' |
| ) |