configs: Start using the new "addrs" package types for modules

We initially just mimicked our old practice of using []string for module
paths here, but the addrs package now gives us a pair of types that better
capture the two different kinds of module addresses we are dealing with:
static addresses (nodes in the configuration tree) and dynamic/instance
addresses (which can represent the situation where multiple instances are
created from a single module call).

This distinction still remains rather artificial since we don't yet have
support for count or for_each on module calls, but this is intended to lay
the foundations for that to be added later, and in the mean time just
gives us some handy helper functions for parsing and formatting these
address types.
This commit is contained in:
Martin Atkins 2018-04-06 11:10:21 -07:00
parent a16ca2ec53
commit cd51864d84
3 changed files with 57 additions and 8 deletions

View File

@ -1,5 +1,9 @@
package addrs package addrs
import (
"strings"
)
// Module is an address for a module call within configuration. This is // Module is an address for a module call within configuration. This is
// the static counterpart of ModuleInstance, representing a traversal through // the static counterpart of ModuleInstance, representing a traversal through
// the static module call tree in configuration and does not take into account // the static module call tree in configuration and does not take into account
@ -19,6 +23,13 @@ type Module []string
// represented by RootModuleInstance. // represented by RootModuleInstance.
var RootModule Module var RootModule Module
func (m Module) String() string {
if len(m) == 0 {
return ""
}
return strings.Join([]string(m), ".")
}
// Child returns the address of a child call in the receiver, identified by the // Child returns the address of a child call in the receiver, identified by the
// given name. // given name.
func (m Module) Child(name string) Module { func (m Module) Child(name string) Module {

View File

@ -1,5 +1,7 @@
package addrs package addrs
import "bytes"
// ModuleInstance is an address for a particular module instance within the // ModuleInstance is an address for a particular module instance within the
// dynamic module tree. This is an extension of the static traversals // dynamic module tree. This is an extension of the static traversals
// represented by type Module that deals with the possibility of a single // represented by type Module that deals with the possibility of a single
@ -40,3 +42,22 @@ func (m ModuleInstance) Parent() ModuleInstance {
} }
return m[:len(m)-1] return m[:len(m)-1]
} }
// String returns a string representation of the receiver, in the format used
// within e.g. user-provided resource addresses.
//
// The address of the root module has the empty string as its representation.
func (m ModuleInstance) String() string {
var buf bytes.Buffer
sep := ""
for _, step := range m {
buf.WriteString(sep)
buf.WriteString("module.")
buf.WriteString(step.Name)
if step.InstanceKey != NoKey {
buf.WriteString(step.InstanceKey.String())
}
sep = "."
}
return buf.String()
}

View File

@ -3,6 +3,7 @@ package configs
import ( import (
version "github.com/hashicorp/go-version" version "github.com/hashicorp/go-version"
"github.com/hashicorp/hcl2/hcl" "github.com/hashicorp/hcl2/hcl"
"github.com/hashicorp/terraform/addrs"
) )
// A Config is a node in the tree of modules within a configuration. // A Config is a node in the tree of modules within a configuration.
@ -27,13 +28,12 @@ type Config struct {
// Path is a sequence of module logical names that traverse from the root // Path is a sequence of module logical names that traverse from the root
// module to this config. Path is empty for the root module. // module to this config. Path is empty for the root module.
// //
// This should not be used to display a path to the end-user, since // This should only be used to display paths to the end-user in rare cases
// our UI conventions call for us to return a module address string in that // where we are talking about the static module tree, before module calls
// case, and a module address string ought to be built from the dynamic // have been resolved. In most cases, a addrs.ModuleInstance describing
// module tree (resulting from evaluating "count" and "for_each" arguments // a node in the dynamic module tree is better, since it will then include
// on our calls to produce potentially multiple child instances per call) // any keys resulting from evaluating "count" and "for_each" arguments.
// rather than from our static module tree. Path addrs.Module
Path []string
// ChildModules points to the Config for each of the direct child modules // ChildModules points to the Config for each of the direct child modules
// called from this module. The keys in this map match the keys in // called from this module. The keys in this map match the keys in
@ -121,7 +121,7 @@ func (c *Config) AllModules() []*Config {
// count and for_each arguments. // count and for_each arguments.
// //
// An empty path will just return the receiver, and is therefore pointless. // An empty path will just return the receiver, and is therefore pointless.
func (c *Config) Descendent(path []string) *Config { func (c *Config) Descendent(path addrs.Module) *Config {
current := c current := c
for _, name := range path { for _, name := range path {
current = current.Children[name] current = current.Children[name]
@ -131,3 +131,20 @@ func (c *Config) Descendent(path []string) *Config {
} }
return current return current
} }
// DescendentForInstance is like Descendent except that it accepts a path
// to a particular module instance in the dynamic module graph, returning
// the node from the static module graph that corresponds to it.
//
// All instances created by a particular module call share the same
// configuration, so the keys within the given path are disregarded.
func (c *Config) DescendentForInstance(path addrs.ModuleInstance) *Config {
current := c
for _, step := range path {
current = current.Children[step.Name]
if current == nil {
return nil
}
}
return current
}