github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/configs/config.go (about)

     1  package configs
     2  
     3  import (
     4  	"sort"
     5  
     6  	version "github.com/hashicorp/go-version"
     7  	"github.com/hashicorp/hcl/v2"
     8  	"github.com/hashicorp/terraform/addrs"
     9  )
    10  
    11  // A Config is a node in the tree of modules within a configuration.
    12  //
    13  // The module tree is constructed by following ModuleCall instances recursively
    14  // through the root module transitively into descendent modules.
    15  //
    16  // A module tree described in *this* package represents the static tree
    17  // represented by configuration. During evaluation a static ModuleNode may
    18  // expand into zero or more module instances depending on the use of count and
    19  // for_each configuration attributes within each call.
    20  type Config struct {
    21  	// RootModule points to the Config for the root module within the same
    22  	// module tree as this module. If this module _is_ the root module then
    23  	// this is self-referential.
    24  	Root *Config
    25  
    26  	// ParentModule points to the Config for the module that directly calls
    27  	// this module. If this is the root module then this field is nil.
    28  	Parent *Config
    29  
    30  	// Path is a sequence of module logical names that traverse from the root
    31  	// module to this config. Path is empty for the root module.
    32  	//
    33  	// This should only be used to display paths to the end-user in rare cases
    34  	// where we are talking about the static module tree, before module calls
    35  	// have been resolved. In most cases, an addrs.ModuleInstance describing
    36  	// a node in the dynamic module tree is better, since it will then include
    37  	// any keys resulting from evaluating "count" and "for_each" arguments.
    38  	Path addrs.Module
    39  
    40  	// ChildModules points to the Config for each of the direct child modules
    41  	// called from this module. The keys in this map match the keys in
    42  	// Module.ModuleCalls.
    43  	Children map[string]*Config
    44  
    45  	// Module points to the object describing the configuration for the
    46  	// various elements (variables, resources, etc) defined by this module.
    47  	Module *Module
    48  
    49  	// CallRange is the source range for the header of the module block that
    50  	// requested this module.
    51  	//
    52  	// This field is meaningless for the root module, where its contents are undefined.
    53  	CallRange hcl.Range
    54  
    55  	// SourceAddr is the source address that the referenced module was requested
    56  	// from, as specified in configuration.
    57  	//
    58  	// This field is meaningless for the root module, where its contents are undefined.
    59  	SourceAddr string
    60  
    61  	// SourceAddrRange is the location in the configuration source where the
    62  	// SourceAddr value was set, for use in diagnostic messages.
    63  	//
    64  	// This field is meaningless for the root module, where its contents are undefined.
    65  	SourceAddrRange hcl.Range
    66  
    67  	// Version is the specific version that was selected for this module,
    68  	// based on version constraints given in configuration.
    69  	//
    70  	// This field is nil if the module was loaded from a non-registry source,
    71  	// since versions are not supported for other sources.
    72  	//
    73  	// This field is meaningless for the root module, where it will always
    74  	// be nil.
    75  	Version *version.Version
    76  }
    77  
    78  // NewEmptyConfig constructs a single-node configuration tree with an empty
    79  // root module. This is generally a pretty useless thing to do, so most callers
    80  // should instead use BuildConfig.
    81  func NewEmptyConfig() *Config {
    82  	ret := &Config{}
    83  	ret.Root = ret
    84  	ret.Children = make(map[string]*Config)
    85  	ret.Module = &Module{}
    86  	return ret
    87  }
    88  
    89  // Depth returns the number of "hops" the receiver is from the root of its
    90  // module tree, with the root module having a depth of zero.
    91  func (c *Config) Depth() int {
    92  	ret := 0
    93  	this := c
    94  	for this.Parent != nil {
    95  		ret++
    96  		this = this.Parent
    97  	}
    98  	return ret
    99  }
   100  
   101  // DeepEach calls the given function once for each module in the tree, starting
   102  // with the receiver.
   103  //
   104  // A parent is always called before its children and children of a particular
   105  // node are visited in lexicographic order by their names.
   106  func (c *Config) DeepEach(cb func(c *Config)) {
   107  	cb(c)
   108  
   109  	names := make([]string, 0, len(c.Children))
   110  	for name := range c.Children {
   111  		names = append(names, name)
   112  	}
   113  
   114  	for _, name := range names {
   115  		c.Children[name].DeepEach(cb)
   116  	}
   117  }
   118  
   119  // AllModules returns a slice of all the receiver and all of its descendent
   120  // nodes in the module tree, in the same order they would be visited by
   121  // DeepEach.
   122  func (c *Config) AllModules() []*Config {
   123  	var ret []*Config
   124  	c.DeepEach(func(c *Config) {
   125  		ret = append(ret, c)
   126  	})
   127  	return ret
   128  }
   129  
   130  // Descendent returns the descendent config that has the given path beneath
   131  // the receiver, or nil if there is no such module.
   132  //
   133  // The path traverses the static module tree, prior to any expansion to handle
   134  // count and for_each arguments.
   135  //
   136  // An empty path will just return the receiver, and is therefore pointless.
   137  func (c *Config) Descendent(path addrs.Module) *Config {
   138  	current := c
   139  	for _, name := range path {
   140  		current = current.Children[name]
   141  		if current == nil {
   142  			return nil
   143  		}
   144  	}
   145  	return current
   146  }
   147  
   148  // DescendentForInstance is like Descendent except that it accepts a path
   149  // to a particular module instance in the dynamic module graph, returning
   150  // the node from the static module graph that corresponds to it.
   151  //
   152  // All instances created by a particular module call share the same
   153  // configuration, so the keys within the given path are disregarded.
   154  func (c *Config) DescendentForInstance(path addrs.ModuleInstance) *Config {
   155  	current := c
   156  	for _, step := range path {
   157  		current = current.Children[step.Name]
   158  		if current == nil {
   159  			return nil
   160  		}
   161  	}
   162  	return current
   163  }
   164  
   165  // ProviderTypes returns the names of each distinct provider type referenced
   166  // in the receiving configuration.
   167  //
   168  // This is a helper for easily determining which provider types are required
   169  // to fully interpret the configuration, though it does not include version
   170  // information and so callers are expected to have already dealt with
   171  // provider version selection in an earlier step and have identified suitable
   172  // versions for each provider.
   173  func (c *Config) ProviderTypes() []string {
   174  	m := make(map[string]struct{})
   175  	c.gatherProviderTypes(m)
   176  
   177  	ret := make([]string, 0, len(m))
   178  	for k := range m {
   179  		ret = append(ret, k)
   180  	}
   181  	sort.Strings(ret)
   182  	return ret
   183  }
   184  func (c *Config) gatherProviderTypes(m map[string]struct{}) {
   185  	if c == nil {
   186  		return
   187  	}
   188  
   189  	for _, pc := range c.Module.ProviderConfigs {
   190  		m[pc.Name] = struct{}{}
   191  	}
   192  	for _, rc := range c.Module.ManagedResources {
   193  		providerAddr := rc.ProviderConfigAddr()
   194  		m[providerAddr.Type.LegacyString()] = struct{}{}
   195  	}
   196  	for _, rc := range c.Module.DataResources {
   197  		providerAddr := rc.ProviderConfigAddr()
   198  		m[providerAddr.Type.LegacyString()] = struct{}{}
   199  	}
   200  
   201  	// Must also visit our child modules, recursively.
   202  	for _, cc := range c.Children {
   203  		cc.gatherProviderTypes(m)
   204  	}
   205  }