addrs: new package for representing addresses

This package is intended to contain all the functionality for parsing,
representing, and formatting addresses of objects within Terraform.

It will eventually subsume the responsibilities of both the
InterpolatedVariable and ResourceAddress types in the "terraform" package,
but for the moment is just a set of types for representing these things,
lacking any way to parse or format them. The remaining functionality
will follow in subsequent commits.
This commit is contained in:
Martin Atkins 2018-03-30 19:58:57 -07:00
parent 4ed06a9227
commit b9d84f2944
15 changed files with 403 additions and 0 deletions

8
addrs/count_attr.go Normal file
View File

@ -0,0 +1,8 @@
package addrs
// CountAttr is the address of an attribute of the "count" object in
// the interpolation scope, like "count.index".
type CountAttr struct {
referenceable
Name string
}

17
addrs/doc.go Normal file
View File

@ -0,0 +1,17 @@
// Package addrs contains types that represent "addresses", which are
// references to specific objects within a Terraform configuration or
// state.
//
// All addresses have string representations based on HCL traversal syntax
// which should be used in the user-interface, and also in-memory
// representations that can be used internally.
//
// For object types that exist within Terraform modules a pair of types is
// used. The "local" part of the address is represented by a type, and then
// an absolute path to that object in the context of its module is represented
// by a type of the same name with an "Abs" prefix added, for "absolute".
//
// All types within this package should be treated as immutable, even if this
// is not enforced by the Go compiler. It is always an implementation error
// to modify an address object in-place after it is initially constructed.
package addrs

7
addrs/input_variable.go Normal file
View File

@ -0,0 +1,7 @@
package addrs
// InputVariable is the address of an input variable.
type InputVariable struct {
referenceable
Name string
}

59
addrs/instance_key.go Normal file
View File

@ -0,0 +1,59 @@
package addrs
import (
"fmt"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/gocty"
)
// InstanceKey represents the key of an instance within an object that
// contains multiple instances due to using "count" or "for_each" arguments
// in configuration.
//
// IntKey and StringKey are the two implementations of this type. No other
// implementations are allowed. The single instance of an object that _isn't_
// using "count" or "for_each" is represented by NoKey, which is a nil
// InstanceKey.
type InstanceKey interface {
instanceKeySigil()
}
// ParseInstanceKey returns the instance key corresponding to the given value,
// which must be known and non-null.
//
// If an unknown or null value is provided then this function will panic. This
// function is intended to deal with the values that would naturally be found
// in a hcl.TraverseIndex, which (when parsed from source, at least) can never
// contain unknown or null values.
func ParseInstanceKey(key cty.Value) (InstanceKey, error) {
switch key.Type() {
case cty.String:
return StringKey(key.AsString()), nil
case cty.Number:
var idx int
err := gocty.FromCtyValue(key, &idx)
return IntKey(idx), err
default:
return NoKey, fmt.Errorf("either a string or an integer is required")
}
}
// NoKey represents the absense of an InstanceKey, for the single instance
// of a configuration object that does not use "count" or "for_each" at all.
var NoKey InstanceKey
// IntKey is the InstanceKey representation representing integer indices, as
// used when the "count" argument is specified or if for_each is used with
// a sequence type.
type IntKey int
func (k IntKey) instanceKeySigil() {
}
// StringKey is the InstanceKey representation representing string indices, as
// used when the "for_each" argument is specified with a map or object type.
type StringKey string
func (k StringKey) instanceKeySigil() {
}

7
addrs/local_value.go Normal file
View File

@ -0,0 +1,7 @@
package addrs
// LocalValue is the address of a local value.
type LocalValue struct {
referenceable
Name string
}

37
addrs/module.go Normal file
View File

@ -0,0 +1,37 @@
package addrs
// Module is an address for a module call within configuration. This is
// the static counterpart of ModuleInstance, representing a traversal through
// the static module call tree in configuration and does not take into account
// the potentially-multiple instances of a module that might be created by
// "count" and "for_each" arguments within those calls.
//
// This type should be used only in very specialized cases when working with
// the static module call tree. Type ModuleInstance is appropriate in more cases.
//
// Although Module is a slice, it should be treated as immutable after creation.
type Module []string
// RootModule is the module address representing the root of the static module
// call tree, which is also the zero value of Module.
//
// Note that this is not the root of the dynamic module tree, which is instead
// represented by RootModuleInstance.
var RootModule Module
// Child returns the address of a child call in the receiver, identified by the
// given name.
func (m Module) Child(name string) Module {
ret := make(Module, 0, len(m)+1)
ret = append(ret, m...)
return append(ret, name)
}
// Parent returns the address of the parent module of the receiver, or the
// receiver itself if there is no parent (if it's the root module address).
func (m Module) Parent() Module {
if len(m) == 0 {
return m
}
return m[:len(m)-1]
}

46
addrs/module_call.go Normal file
View File

@ -0,0 +1,46 @@
package addrs
// ModuleCall is the address of a call from the current module to a child
// module.
//
// There is no "Abs" version of ModuleCall because an absolute module path
// is represented by ModuleInstance.
type ModuleCall struct {
referenceable
Name string
}
// Instance returns the address of an instance of the receiver identified by
// the given key.
func (c ModuleCall) Instance(key InstanceKey) ModuleCallInstance {
return ModuleCallInstance{
Call: c,
Key: key,
}
}
// ModuleCallInstance is the address of one instance of a module created from
// a module call, which might create multiple instances using "count" or
// "for_each" arguments.
type ModuleCallInstance struct {
referenceable
Call ModuleCall
Key InstanceKey
}
// Output returns the address of an output of the receiver identified by its
// name.
func (c ModuleCallInstance) Output(name string) ModuleCallOutput {
return ModuleCallOutput{
Call: c,
Name: name,
}
}
// ModuleCallOutput is the address of a particular named output produced by
// an instance of a module call.
type ModuleCallOutput struct {
referenceable
Call ModuleCallInstance
Name string
}

42
addrs/module_instance.go Normal file
View File

@ -0,0 +1,42 @@
package addrs
// ModuleInstance is an address for a particular module instance within the
// dynamic module tree. This is an extension of the static traversals
// represented by type Module that deals with the possibility of a single
// module call producing multiple instances via the "count" and "for_each"
// arguments.
//
// Although ModuleInstance is a slice, it should be treated as immutable after
// creation.
type ModuleInstance []ModuleInstanceStep
// ModuleInstanceStep is a single traversal step through the dynamic module
// tree. It is used only as part of ModuleInstance.
type ModuleInstanceStep struct {
Name string
InstanceKey InstanceKey
}
// RootModuleInstance is the module instance address representing the root
// module, which is also the zero value of ModuleInstance.
var RootModuleInstance ModuleInstance
// Child returns the address of a child module instance of the receiver,
// identified by the given name and key.
func (m ModuleInstance) Child(name string, key InstanceKey) ModuleInstance {
ret := make(ModuleInstance, 0, len(m)+1)
ret = append(ret, m...)
return append(ret, ModuleInstanceStep{
Name: name,
InstanceKey: key,
})
}
// Parent returns the address of the parent module instance of the receiver, or
// the receiver itself if there is no parent (if it's the root module address).
func (m ModuleInstance) Parent() ModuleInstance {
if len(m) == 0 {
return m
}
return m[:len(m)-1]
}

8
addrs/path_attr.go Normal file
View File

@ -0,0 +1,8 @@
package addrs
// PathAttr is the address of an attribute of the "path" object in
// the interpolation scope, like "path.module".
type PathAttr struct {
referenceable
Name string
}

10
addrs/provider_config.go Normal file
View File

@ -0,0 +1,10 @@
package addrs
// ProviderConfig is the address of a provider configuration.
type ProviderConfig struct {
Type string
// If not empty, Alias identifies which non-default (aliased) provider
// configuration this address refers to.
Alias string
}

13
addrs/referenceable.go Normal file
View File

@ -0,0 +1,13 @@
package addrs
// Referenceable is an interface implemented by all address types that can
// appear as references in configuration language expressions.
type Referenceable interface {
referenceableSigil()
}
type referenceable struct {
}
func (r referenceable) referenceableSigil() {
}

107
addrs/resource.go Normal file
View File

@ -0,0 +1,107 @@
package addrs
// 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
}
// 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,
}
}
// 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
}
// 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,
}
}
// 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,
},
}
}
// AbsResource is an absolute address for a resource under a given module path.
type AbsResource struct {
Module ModuleInstance
Resource Resource
}
// AbsResourceInstance is an absolute address for a resource instance under a
// given module path.
type AbsResourceInstance struct {
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,
},
}
}
// ResourceMode defines which lifecycle applies to a given resource. Each
// resource lifecycle has a slightly different address format.
type ResourceMode rune
//go:generate 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'
)

View File

@ -0,0 +1,24 @@
// Code generated by "stringer -type ResourceMode"; DO NOT EDIT.
package addrs
import "strconv"
const (
_ResourceMode_name_0 = "InvalidResourceMode"
_ResourceMode_name_1 = "DataResourceMode"
_ResourceMode_name_2 = "ManagedResourceMode"
)
func (i ResourceMode) String() string {
switch {
case i == 0:
return _ResourceMode_name_0
case i == 68:
return _ResourceMode_name_1
case i == 77:
return _ResourceMode_name_2
default:
return "ResourceMode(" + strconv.FormatInt(int64(i), 10) + ")"
}
}

10
addrs/self.go Normal file
View File

@ -0,0 +1,10 @@
package addrs
// Self is the address of the special object "self" that behaves as an alias
// for a containing object currently in scope.
const Self selfT = 0
type selfT int
func (s selfT) referenceableSigil() {
}

8
addrs/terraform_attr.go Normal file
View File

@ -0,0 +1,8 @@
package addrs
// TerraformAttr is the address of an attribute of the "terraform" object in
// the interpolation scope, like "terraform.workspace".
type TerraformAttr struct {
referenceable
Name string
}