aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/config/module/tree.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/config/module/tree.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/tree.go314
1 files changed, 233 insertions, 81 deletions
diff --git a/vendor/github.com/hashicorp/terraform/config/module/tree.go b/vendor/github.com/hashicorp/terraform/config/module/tree.go
index 4b0b153..f56d69b 100644
--- a/vendor/github.com/hashicorp/terraform/config/module/tree.go
+++ b/vendor/github.com/hashicorp/terraform/config/module/tree.go
@@ -4,11 +4,14 @@ import (
4 "bufio" 4 "bufio"
5 "bytes" 5 "bytes"
6 "fmt" 6 "fmt"
7 "log"
7 "path/filepath" 8 "path/filepath"
8 "strings" 9 "strings"
9 "sync" 10 "sync"
10 11
11 "github.com/hashicorp/go-getter" 12 "github.com/hashicorp/terraform/tfdiags"
13
14 getter "github.com/hashicorp/go-getter"
12 "github.com/hashicorp/terraform/config" 15 "github.com/hashicorp/terraform/config"
13) 16)
14 17
@@ -26,6 +29,17 @@ type Tree struct {
26 children map[string]*Tree 29 children map[string]*Tree
27 path []string 30 path []string
28 lock sync.RWMutex 31 lock sync.RWMutex
32
33 // version is the final version of the config loaded for the Tree's module
34 version string
35 // source is the "source" string used to load this module. It's possible
36 // for a module source to change, but the path remains the same, preventing
37 // it from being reloaded.
38 source string
39 // parent allows us to walk back up the tree and determine if there are any
40 // versioned ancestor modules which may effect the stored location of
41 // submodules
42 parent *Tree
29} 43}
30 44
31// NewTree returns a new Tree for the given config structure. 45// NewTree returns a new Tree for the given config structure.
@@ -40,7 +54,7 @@ func NewEmptyTree() *Tree {
40 // We do this dummy load so that the tree is marked as "loaded". It 54 // We do this dummy load so that the tree is marked as "loaded". It
41 // should never fail because this is just about a no-op. If it does fail 55 // should never fail because this is just about a no-op. If it does fail
42 // we panic so we can know its a bug. 56 // we panic so we can know its a bug.
43 if err := t.Load(nil, GetModeGet); err != nil { 57 if err := t.Load(&Storage{Mode: GetModeGet}); err != nil {
44 panic(err) 58 panic(err)
45 } 59 }
46 60
@@ -126,8 +140,10 @@ func (t *Tree) Modules() []*Module {
126 result := make([]*Module, len(t.config.Modules)) 140 result := make([]*Module, len(t.config.Modules))
127 for i, m := range t.config.Modules { 141 for i, m := range t.config.Modules {
128 result[i] = &Module{ 142 result[i] = &Module{
129 Name: m.Name, 143 Name: m.Name,
130 Source: m.Source, 144 Version: m.Version,
145 Source: m.Source,
146 Providers: m.Providers,
131 } 147 }
132 } 148 }
133 149
@@ -155,81 +171,178 @@ func (t *Tree) Name() string {
155// module trees inherently require the configuration to be in a reasonably 171// module trees inherently require the configuration to be in a reasonably
156// sane state: no circular dependencies, proper module sources, etc. A full 172// sane state: no circular dependencies, proper module sources, etc. A full
157// suite of validations can be done by running Validate (after loading). 173// suite of validations can be done by running Validate (after loading).
158func (t *Tree) Load(s getter.Storage, mode GetMode) error { 174func (t *Tree) Load(s *Storage) error {
159 t.lock.Lock() 175 t.lock.Lock()
160 defer t.lock.Unlock() 176 defer t.lock.Unlock()
161 177
162 // Reset the children if we have any 178 children, err := t.getChildren(s)
163 t.children = nil 179 if err != nil {
180 return err
181 }
182
183 // Go through all the children and load them.
184 for _, c := range children {
185 if err := c.Load(s); err != nil {
186 return err
187 }
188 }
189
190 // Set our tree up
191 t.children = children
164 192
165 modules := t.Modules() 193 return nil
194}
195
196func (t *Tree) getChildren(s *Storage) (map[string]*Tree, error) {
166 children := make(map[string]*Tree) 197 children := make(map[string]*Tree)
167 198
168 // Go through all the modules and get the directory for them. 199 // Go through all the modules and get the directory for them.
169 for _, m := range modules { 200 for _, m := range t.Modules() {
170 if _, ok := children[m.Name]; ok { 201 if _, ok := children[m.Name]; ok {
171 return fmt.Errorf( 202 return nil, fmt.Errorf(
172 "module %s: duplicated. module names must be unique", m.Name) 203 "module %s: duplicated. module names must be unique", m.Name)
173 } 204 }
174 205
175 // Determine the path to this child 206 // Determine the path to this child
176 path := make([]string, len(t.path), len(t.path)+1) 207 modPath := make([]string, len(t.path), len(t.path)+1)
177 copy(path, t.path) 208 copy(modPath, t.path)
178 path = append(path, m.Name) 209 modPath = append(modPath, m.Name)
179 210
180 // Split out the subdir if we have one 211 log.Printf("[TRACE] module source: %q", m.Source)
181 source, subDir := getter.SourceDirSubdir(m.Source)
182 212
183 source, err := getter.Detect(source, t.config.Dir, getter.Detectors) 213 // add the module path to help indicate where modules with relative
214 // paths are being loaded from
215 s.output(fmt.Sprintf("- module.%s", strings.Join(modPath, ".")))
216
217 // Lookup the local location of the module.
218 // dir is the local directory where the module is stored
219 mod, err := s.findRegistryModule(m.Source, m.Version)
184 if err != nil { 220 if err != nil {
185 return fmt.Errorf("module %s: %s", m.Name, err) 221 return nil, err
186 } 222 }
187 223
224 // The key is the string that will be used to uniquely id the Source in
225 // the local storage. The prefix digit can be incremented to
226 // invalidate the local module storage.
227 key := "1." + t.versionedPathKey(m)
228 if mod.Version != "" {
229 key += "." + mod.Version
230 }
231
232 // Check for the exact key if it's not a registry module
233 if !mod.registry {
234 mod.Dir, err = s.findModule(key)
235 if err != nil {
236 return nil, err
237 }
238 }
239
240 if mod.Dir != "" && s.Mode != GetModeUpdate {
241 // We found it locally, but in order to load the Tree we need to
242 // find out if there was another subDir stored from detection.
243 subDir, err := s.getModuleRoot(mod.Dir)
244 if err != nil {
245 // If there's a problem with the subdir record, we'll let the
246 // recordSubdir method fix it up. Any other filesystem errors
247 // will turn up again below.
248 log.Println("[WARN] error reading subdir record:", err)
249 }
250
251 fullDir := filepath.Join(mod.Dir, subDir)
252
253 child, err := NewTreeModule(m.Name, fullDir)
254 if err != nil {
255 return nil, fmt.Errorf("module %s: %s", m.Name, err)
256 }
257 child.path = modPath
258 child.parent = t
259 child.version = mod.Version
260 child.source = m.Source
261 children[m.Name] = child
262 continue
263 }
264
265 // Split out the subdir if we have one.
266 // Terraform keeps the entire requested tree, so that modules can
267 // reference sibling modules from the same archive or repo.
268 rawSource, subDir := getter.SourceDirSubdir(m.Source)
269
270 // we haven't found a source, so fallback to the go-getter detectors
271 source := mod.url
272 if source == "" {
273 source, err = getter.Detect(rawSource, t.config.Dir, getter.Detectors)
274 if err != nil {
275 return nil, fmt.Errorf("module %s: %s", m.Name, err)
276 }
277 }
278
279 log.Printf("[TRACE] detected module source %q", source)
280
188 // Check if the detector introduced something new. 281 // Check if the detector introduced something new.
189 source, subDir2 := getter.SourceDirSubdir(source) 282 // For example, the registry always adds a subdir of `//*`,
190 if subDir2 != "" { 283 // indicating that we need to strip off the first component from the
191 subDir = filepath.Join(subDir2, subDir) 284 // tar archive, though we may not yet know what it is called.
285 source, detectedSubDir := getter.SourceDirSubdir(source)
286 if detectedSubDir != "" {
287 subDir = filepath.Join(detectedSubDir, subDir)
288 }
289
290 output := ""
291 switch s.Mode {
292 case GetModeUpdate:
293 output = fmt.Sprintf(" Updating source %q", m.Source)
294 default:
295 output = fmt.Sprintf(" Getting source %q", m.Source)
192 } 296 }
297 s.output(output)
193 298
194 // Get the directory where this module is so we can load it 299 dir, ok, err := s.getStorage(key, source)
195 key := strings.Join(path, ".")
196 key = fmt.Sprintf("root.%s-%s", key, m.Source)
197 dir, ok, err := getStorage(s, key, source, mode)
198 if err != nil { 300 if err != nil {
199 return err 301 return nil, err
200 } 302 }
201 if !ok { 303 if !ok {
202 return fmt.Errorf( 304 return nil, fmt.Errorf("module %s: not found, may need to run 'terraform init'", m.Name)
203 "module %s: not found, may need to be downloaded using 'terraform get'", m.Name)
204 } 305 }
205 306
206 // If we have a subdirectory, then merge that in 307 log.Printf("[TRACE] %q stored in %q", source, dir)
308
309 // expand and record the subDir for later
310 fullDir := dir
207 if subDir != "" { 311 if subDir != "" {
208 dir = filepath.Join(dir, subDir) 312 fullDir, err = getter.SubdirGlob(dir, subDir)
209 } 313 if err != nil {
314 return nil, err
315 }
210 316
211 // Load the configurations.Dir(source) 317 // +1 to account for the pathsep
212 children[m.Name], err = NewTreeModule(m.Name, dir) 318 if len(dir)+1 > len(fullDir) {
213 if err != nil { 319 return nil, fmt.Errorf("invalid module storage path %q", fullDir)
214 return fmt.Errorf( 320 }
215 "module %s: %s", m.Name, err) 321 subDir = fullDir[len(dir)+1:]
216 } 322 }
217 323
218 // Set the path of this child 324 // add new info to the module record
219 children[m.Name].path = path 325 mod.Key = key
220 } 326 mod.Dir = dir
327 mod.Root = subDir
221 328
222 // Go through all the children and load them. 329 // record the module in our manifest
223 for _, c := range children { 330 if err := s.recordModule(mod); err != nil {
224 if err := c.Load(s, mode); err != nil { 331 return nil, err
225 return err
226 } 332 }
227 }
228 333
229 // Set our tree up 334 child, err := NewTreeModule(m.Name, fullDir)
230 t.children = children 335 if err != nil {
336 return nil, fmt.Errorf("module %s: %s", m.Name, err)
337 }
338 child.path = modPath
339 child.parent = t
340 child.version = mod.Version
341 child.source = m.Source
342 children[m.Name] = child
343 }
231 344
232 return nil 345 return children, nil
233} 346}
234 347
235// Path is the full path to this tree. 348// Path is the full path to this tree.
@@ -272,32 +385,35 @@ func (t *Tree) String() string {
272// as verifying things such as parameters/outputs between the various modules. 385// as verifying things such as parameters/outputs between the various modules.
273// 386//
274// Load must be called prior to calling Validate or an error will be returned. 387// Load must be called prior to calling Validate or an error will be returned.
275func (t *Tree) Validate() error { 388func (t *Tree) Validate() tfdiags.Diagnostics {
389 var diags tfdiags.Diagnostics
390
276 if !t.Loaded() { 391 if !t.Loaded() {
277 return fmt.Errorf("tree must be loaded before calling Validate") 392 diags = diags.Append(fmt.Errorf(
393 "tree must be loaded before calling Validate",
394 ))
395 return diags
278 } 396 }
279 397
280 // If something goes wrong, here is our error template
281 newErr := &treeError{Name: []string{t.Name()}}
282
283 // Terraform core does not handle root module children named "root". 398 // Terraform core does not handle root module children named "root".
284 // We plan to fix this in the future but this bug was brought up in 399 // We plan to fix this in the future but this bug was brought up in
285 // the middle of a release and we don't want to introduce wide-sweeping 400 // the middle of a release and we don't want to introduce wide-sweeping
286 // changes at that time. 401 // changes at that time.
287 if len(t.path) == 1 && t.name == "root" { 402 if len(t.path) == 1 && t.name == "root" {
288 return fmt.Errorf("root module cannot contain module named 'root'") 403 diags = diags.Append(fmt.Errorf(
404 "root module cannot contain module named 'root'",
405 ))
406 return diags
289 } 407 }
290 408
291 // Validate our configuration first. 409 // Validate our configuration first.
292 if err := t.config.Validate(); err != nil { 410 diags = diags.Append(t.config.Validate())
293 newErr.Add(err)
294 }
295 411
296 // If we're the root, we do extra validation. This validation usually 412 // If we're the root, we do extra validation. This validation usually
297 // requires the entire tree (since children don't have parent pointers). 413 // requires the entire tree (since children don't have parent pointers).
298 if len(t.path) == 0 { 414 if len(t.path) == 0 {
299 if err := t.validateProviderAlias(); err != nil { 415 if err := t.validateProviderAlias(); err != nil {
300 newErr.Add(err) 416 diags = diags.Append(err)
301 } 417 }
302 } 418 }
303 419
@@ -306,20 +422,11 @@ func (t *Tree) Validate() error {
306 422
307 // Validate all our children 423 // Validate all our children
308 for _, c := range children { 424 for _, c := range children {
309 err := c.Validate() 425 childDiags := c.Validate()
310 if err == nil { 426 diags = diags.Append(childDiags)
427 if diags.HasErrors() {
311 continue 428 continue
312 } 429 }
313
314 verr, ok := err.(*treeError)
315 if !ok {
316 // Unknown error, just return...
317 return err
318 }
319
320 // Append ourselves to the error and then return
321 verr.Name = append(verr.Name, t.Name())
322 newErr.AddChild(verr)
323 } 430 }
324 431
325 // Go over all the modules and verify that any parameters are valid 432 // Go over all the modules and verify that any parameters are valid
@@ -345,9 +452,10 @@ func (t *Tree) Validate() error {
345 // Compare to the keys in our raw config for the module 452 // Compare to the keys in our raw config for the module
346 for k, _ := range m.RawConfig.Raw { 453 for k, _ := range m.RawConfig.Raw {
347 if _, ok := varMap[k]; !ok { 454 if _, ok := varMap[k]; !ok {
348 newErr.Add(fmt.Errorf( 455 diags = diags.Append(fmt.Errorf(
349 "module %s: %s is not a valid parameter", 456 "module %q: %q is not a valid argument",
350 m.Name, k)) 457 m.Name, k,
458 ))
351 } 459 }
352 460
353 // Remove the required 461 // Remove the required
@@ -356,9 +464,10 @@ func (t *Tree) Validate() error {
356 464
357 // If we have any required left over, they aren't set. 465 // If we have any required left over, they aren't set.
358 for k, _ := range requiredMap { 466 for k, _ := range requiredMap {
359 newErr.Add(fmt.Errorf( 467 diags = diags.Append(fmt.Errorf(
360 "module %s: required variable %q not set", 468 "module %q: missing required argument %q",
361 m.Name, k)) 469 m.Name, k,
470 ))
362 } 471 }
363 } 472 }
364 473
@@ -373,9 +482,10 @@ func (t *Tree) Validate() error {
373 482
374 tree, ok := children[mv.Name] 483 tree, ok := children[mv.Name]
375 if !ok { 484 if !ok {
376 newErr.Add(fmt.Errorf( 485 diags = diags.Append(fmt.Errorf(
377 "%s: undefined module referenced %s", 486 "%s: reference to undefined module %q",
378 source, mv.Name)) 487 source, mv.Name,
488 ))
379 continue 489 continue
380 } 490 }
381 491
@@ -387,14 +497,56 @@ func (t *Tree) Validate() error {
387 } 497 }
388 } 498 }
389 if !found { 499 if !found {
390 newErr.Add(fmt.Errorf( 500 diags = diags.Append(fmt.Errorf(
391 "%s: %s is not a valid output for module %s", 501 "%s: %q is not a valid output for module %q",
392 source, mv.Field, mv.Name)) 502 source, mv.Field, mv.Name,
503 ))
393 } 504 }
394 } 505 }
395 } 506 }
396 507
397 return newErr.ErrOrNil() 508 return diags
509}
510
511// versionedPathKey returns a path string with every levels full name, version
512// and source encoded. This is to provide a unique key for our module storage,
513// since submodules need to know which versions of their ancestor modules they
514// are loaded from.
515// For example, if module A has a subdirectory B, if module A's source or
516// version is updated B's storage key must reflect this change in order for the
517// correct version of B's source to be loaded.
518func (t *Tree) versionedPathKey(m *Module) string {
519 path := make([]string, len(t.path)+1)
520 path[len(path)-1] = m.Name + ";" + m.Source
521 // We're going to load these in order for easier reading and debugging, but
522 // in practice they only need to be unique and consistent.
523
524 p := t
525 i := len(path) - 2
526 for ; i >= 0; i-- {
527 if p == nil {
528 break
529 }
530 // we may have been loaded under a blank Tree, so always check for a name
531 // too.
532 if p.name == "" {
533 break
534 }
535 seg := p.name
536 if p.version != "" {
537 seg += "#" + p.version
538 }
539
540 if p.source != "" {
541 seg += ";" + p.source
542 }
543
544 path[i] = seg
545 p = p.parent
546 }
547
548 key := strings.Join(path, "|")
549 return key
398} 550}
399 551
400// treeError is an error use by Tree.Validate to accumulates all 552// treeError is an error use by Tree.Validate to accumulates all