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 }