]>
Commit | Line | Data |
---|---|---|
107c1cdb ND |
1 | package configs |
2 | ||
3 | import ( | |
4 | "sort" | |
5 | ||
6 | version "github.com/hashicorp/go-version" | |
7 | "github.com/hashicorp/hcl2/hcl" | |
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] = struct{}{} | |
195 | } | |
196 | for _, rc := range c.Module.DataResources { | |
197 | providerAddr := rc.ProviderConfigAddr() | |
198 | m[providerAddr.Type] = struct{}{} | |
199 | } | |
200 | ||
201 | // Must also visit our child modules, recursively. | |
202 | for _, cc := range c.Children { | |
203 | cc.gatherProviderTypes(m) | |
204 | } | |
205 | } |