aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/config/module
diff options
context:
space:
mode:
authorJake Champlin <jake.champlin.27@gmail.com>2017-06-06 12:40:07 -0400
committerJake Champlin <jake.champlin.27@gmail.com>2017-06-06 12:40:07 -0400
commitbae9f6d2fd5eb5bc80929bd393932b23f14d7c93 (patch)
treeca9ab12a7d78b1fc27a8f734729081357ce6d252 /vendor/github.com/hashicorp/terraform/config/module
parent254c495b6bebab3fb72a243c4bce858d79e6ee99 (diff)
downloadterraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.gz
terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.zst
terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.zip
Initial transfer of provider code
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/config/module')
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/copy_dir.go114
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/get.go71
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/inode.go21
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/inode_freebsd.go21
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/inode_windows.go8
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/module.go7
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/testing.go38
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/tree.go428
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/tree_gob.go57
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/validate_provider_alias.go118
10 files changed, 883 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/config/module/copy_dir.go b/vendor/github.com/hashicorp/terraform/config/module/copy_dir.go
new file mode 100644
index 0000000..095f61d
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/copy_dir.go
@@ -0,0 +1,114 @@
1package module
2
3import (
4 "io"
5 "os"
6 "path/filepath"
7 "strings"
8)
9
10// copyDir copies the src directory contents into dst. Both directories
11// should already exist.
12func copyDir(dst, src string) error {
13 src, err := filepath.EvalSymlinks(src)
14 if err != nil {
15 return err
16 }
17
18 walkFn := func(path string, info os.FileInfo, err error) error {
19 if err != nil {
20 return err
21 }
22
23 if path == src {
24 return nil
25 }
26
27 if strings.HasPrefix(filepath.Base(path), ".") {
28 // Skip any dot files
29 if info.IsDir() {
30 return filepath.SkipDir
31 } else {
32 return nil
33 }
34 }
35
36 // The "path" has the src prefixed to it. We need to join our
37 // destination with the path without the src on it.
38 dstPath := filepath.Join(dst, path[len(src):])
39
40 // we don't want to try and copy the same file over itself.
41 if eq, err := sameFile(path, dstPath); eq {
42 return nil
43 } else if err != nil {
44 return err
45 }
46
47 // If we have a directory, make that subdirectory, then continue
48 // the walk.
49 if info.IsDir() {
50 if path == filepath.Join(src, dst) {
51 // dst is in src; don't walk it.
52 return nil
53 }
54
55 if err := os.MkdirAll(dstPath, 0755); err != nil {
56 return err
57 }
58
59 return nil
60 }
61
62 // If we have a file, copy the contents.
63 srcF, err := os.Open(path)
64 if err != nil {
65 return err
66 }
67 defer srcF.Close()
68
69 dstF, err := os.Create(dstPath)
70 if err != nil {
71 return err
72 }
73 defer dstF.Close()
74
75 if _, err := io.Copy(dstF, srcF); err != nil {
76 return err
77 }
78
79 // Chmod it
80 return os.Chmod(dstPath, info.Mode())
81 }
82
83 return filepath.Walk(src, walkFn)
84}
85
86// sameFile tried to determine if to paths are the same file.
87// If the paths don't match, we lookup the inode on supported systems.
88func sameFile(a, b string) (bool, error) {
89 if a == b {
90 return true, nil
91 }
92
93 aIno, err := inode(a)
94 if err != nil {
95 if os.IsNotExist(err) {
96 return false, nil
97 }
98 return false, err
99 }
100
101 bIno, err := inode(b)
102 if err != nil {
103 if os.IsNotExist(err) {
104 return false, nil
105 }
106 return false, err
107 }
108
109 if aIno > 0 && aIno == bIno {
110 return true, nil
111 }
112
113 return false, nil
114}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/get.go b/vendor/github.com/hashicorp/terraform/config/module/get.go
new file mode 100644
index 0000000..96b4a63
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/get.go
@@ -0,0 +1,71 @@
1package module
2
3import (
4 "io/ioutil"
5 "os"
6
7 "github.com/hashicorp/go-getter"
8)
9
10// GetMode is an enum that describes how modules are loaded.
11//
12// GetModeLoad says that modules will not be downloaded or updated, they will
13// only be loaded from the storage.
14//
15// GetModeGet says that modules can be initially downloaded if they don't
16// exist, but otherwise to just load from the current version in storage.
17//
18// GetModeUpdate says that modules should be checked for updates and
19// downloaded prior to loading. If there are no updates, we load the version
20// from disk, otherwise we download first and then load.
21type GetMode byte
22
23const (
24 GetModeNone GetMode = iota
25 GetModeGet
26 GetModeUpdate
27)
28
29// GetCopy is the same as Get except that it downloads a copy of the
30// module represented by source.
31//
32// This copy will omit and dot-prefixed files (such as .git/, .hg/) and
33// can't be updated on its own.
34func GetCopy(dst, src string) error {
35 // Create the temporary directory to do the real Get to
36 tmpDir, err := ioutil.TempDir("", "tf")
37 if err != nil {
38 return err
39 }
40 // FIXME: This isn't completely safe. Creating and removing our temp path
41 // exposes where to race to inject files.
42 if err := os.RemoveAll(tmpDir); err != nil {
43 return err
44 }
45 defer os.RemoveAll(tmpDir)
46
47 // Get to that temporary dir
48 if err := getter.Get(tmpDir, src); err != nil {
49 return err
50 }
51
52 // Make sure the destination exists
53 if err := os.MkdirAll(dst, 0755); err != nil {
54 return err
55 }
56
57 // Copy to the final location
58 return copyDir(dst, tmpDir)
59}
60
61func getStorage(s getter.Storage, key string, src string, mode GetMode) (string, bool, error) {
62 // Get the module with the level specified if we were told to.
63 if mode > GetModeNone {
64 if err := s.Get(key, src, mode == GetModeUpdate); err != nil {
65 return "", false, err
66 }
67 }
68
69 // Get the directory where the module is.
70 return s.Dir(key)
71}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/inode.go b/vendor/github.com/hashicorp/terraform/config/module/inode.go
new file mode 100644
index 0000000..8603ee2
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/inode.go
@@ -0,0 +1,21 @@
1// +build linux darwin openbsd netbsd solaris
2
3package module
4
5import (
6 "fmt"
7 "os"
8 "syscall"
9)
10
11// lookup the inode of a file on posix systems
12func inode(path string) (uint64, error) {
13 stat, err := os.Stat(path)
14 if err != nil {
15 return 0, err
16 }
17 if st, ok := stat.Sys().(*syscall.Stat_t); ok {
18 return st.Ino, nil
19 }
20 return 0, fmt.Errorf("could not determine file inode")
21}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/inode_freebsd.go b/vendor/github.com/hashicorp/terraform/config/module/inode_freebsd.go
new file mode 100644
index 0000000..0d95730
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/inode_freebsd.go
@@ -0,0 +1,21 @@
1// +build freebsd
2
3package module
4
5import (
6 "fmt"
7 "os"
8 "syscall"
9)
10
11// lookup the inode of a file on posix systems
12func inode(path string) (uint64, error) {
13 stat, err := os.Stat(path)
14 if err != nil {
15 return 0, err
16 }
17 if st, ok := stat.Sys().(*syscall.Stat_t); ok {
18 return uint64(st.Ino), nil
19 }
20 return 0, fmt.Errorf("could not determine file inode")
21}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/inode_windows.go b/vendor/github.com/hashicorp/terraform/config/module/inode_windows.go
new file mode 100644
index 0000000..c0cf455
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/inode_windows.go
@@ -0,0 +1,8 @@
1// +build windows
2
3package module
4
5// no syscall.Stat_t on windows, return 0 for inodes
6func inode(path string) (uint64, error) {
7 return 0, nil
8}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/module.go b/vendor/github.com/hashicorp/terraform/config/module/module.go
new file mode 100644
index 0000000..f8649f6
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/module.go
@@ -0,0 +1,7 @@
1package module
2
3// Module represents the metadata for a single module.
4type Module struct {
5 Name string
6 Source string
7}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/testing.go b/vendor/github.com/hashicorp/terraform/config/module/testing.go
new file mode 100644
index 0000000..fc9e733
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/testing.go
@@ -0,0 +1,38 @@
1package module
2
3import (
4 "io/ioutil"
5 "os"
6 "testing"
7
8 "github.com/hashicorp/go-getter"
9)
10
11// TestTree loads a module at the given path and returns the tree as well
12// as a function that should be deferred to clean up resources.
13func TestTree(t *testing.T, path string) (*Tree, func()) {
14 // Create a temporary directory for module storage
15 dir, err := ioutil.TempDir("", "tf")
16 if err != nil {
17 t.Fatalf("err: %s", err)
18 return nil, nil
19 }
20
21 // Load the module
22 mod, err := NewTreeModule("", path)
23 if err != nil {
24 t.Fatalf("err: %s", err)
25 return nil, nil
26 }
27
28 // Get the child modules
29 s := &getter.FolderStorage{StorageDir: dir}
30 if err := mod.Load(s, GetModeGet); err != nil {
31 t.Fatalf("err: %s", err)
32 return nil, nil
33 }
34
35 return mod, func() {
36 os.RemoveAll(dir)
37 }
38}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/tree.go b/vendor/github.com/hashicorp/terraform/config/module/tree.go
new file mode 100644
index 0000000..b6f90fd
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/tree.go
@@ -0,0 +1,428 @@
1package module
2
3import (
4 "bufio"
5 "bytes"
6 "fmt"
7 "path/filepath"
8 "strings"
9 "sync"
10
11 "github.com/hashicorp/go-getter"
12 "github.com/hashicorp/terraform/config"
13)
14
15// RootName is the name of the root tree.
16const RootName = "root"
17
18// Tree represents the module import tree of configurations.
19//
20// This Tree structure can be used to get (download) new modules, load
21// all the modules without getting, flatten the tree into something
22// Terraform can use, etc.
23type Tree struct {
24 name string
25 config *config.Config
26 children map[string]*Tree
27 path []string
28 lock sync.RWMutex
29}
30
31// NewTree returns a new Tree for the given config structure.
32func NewTree(name string, c *config.Config) *Tree {
33 return &Tree{config: c, name: name}
34}
35
36// NewEmptyTree returns a new tree that is empty (contains no configuration).
37func NewEmptyTree() *Tree {
38 t := &Tree{config: &config.Config{}}
39
40 // 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
42 // we panic so we can know its a bug.
43 if err := t.Load(nil, GetModeGet); err != nil {
44 panic(err)
45 }
46
47 return t
48}
49
50// NewTreeModule is like NewTree except it parses the configuration in
51// the directory and gives it a specific name. Use a blank name "" to specify
52// the root module.
53func NewTreeModule(name, dir string) (*Tree, error) {
54 c, err := config.LoadDir(dir)
55 if err != nil {
56 return nil, err
57 }
58
59 return NewTree(name, c), nil
60}
61
62// Config returns the configuration for this module.
63func (t *Tree) Config() *config.Config {
64 return t.config
65}
66
67// Child returns the child with the given path (by name).
68func (t *Tree) Child(path []string) *Tree {
69 if t == nil {
70 return nil
71 }
72
73 if len(path) == 0 {
74 return t
75 }
76
77 c := t.Children()[path[0]]
78 if c == nil {
79 return nil
80 }
81
82 return c.Child(path[1:])
83}
84
85// Children returns the children of this tree (the modules that are
86// imported by this root).
87//
88// This will only return a non-nil value after Load is called.
89func (t *Tree) Children() map[string]*Tree {
90 t.lock.RLock()
91 defer t.lock.RUnlock()
92 return t.children
93}
94
95// Loaded says whether or not this tree has been loaded or not yet.
96func (t *Tree) Loaded() bool {
97 t.lock.RLock()
98 defer t.lock.RUnlock()
99 return t.children != nil
100}
101
102// Modules returns the list of modules that this tree imports.
103//
104// This is only the imports of _this_ level of the tree. To retrieve the
105// full nested imports, you'll have to traverse the tree.
106func (t *Tree) Modules() []*Module {
107 result := make([]*Module, len(t.config.Modules))
108 for i, m := range t.config.Modules {
109 result[i] = &Module{
110 Name: m.Name,
111 Source: m.Source,
112 }
113 }
114
115 return result
116}
117
118// Name returns the name of the tree. This will be "<root>" for the root
119// tree and then the module name given for any children.
120func (t *Tree) Name() string {
121 if t.name == "" {
122 return RootName
123 }
124
125 return t.name
126}
127
128// Load loads the configuration of the entire tree.
129//
130// The parameters are used to tell the tree where to find modules and
131// whether it can download/update modules along the way.
132//
133// Calling this multiple times will reload the tree.
134//
135// Various semantic-like checks are made along the way of loading since
136// module trees inherently require the configuration to be in a reasonably
137// sane state: no circular dependencies, proper module sources, etc. A full
138// suite of validations can be done by running Validate (after loading).
139func (t *Tree) Load(s getter.Storage, mode GetMode) error {
140 t.lock.Lock()
141 defer t.lock.Unlock()
142
143 // Reset the children if we have any
144 t.children = nil
145
146 modules := t.Modules()
147 children := make(map[string]*Tree)
148
149 // Go through all the modules and get the directory for them.
150 for _, m := range modules {
151 if _, ok := children[m.Name]; ok {
152 return fmt.Errorf(
153 "module %s: duplicated. module names must be unique", m.Name)
154 }
155
156 // Determine the path to this child
157 path := make([]string, len(t.path), len(t.path)+1)
158 copy(path, t.path)
159 path = append(path, m.Name)
160
161 // Split out the subdir if we have one
162 source, subDir := getter.SourceDirSubdir(m.Source)
163
164 source, err := getter.Detect(source, t.config.Dir, getter.Detectors)
165 if err != nil {
166 return fmt.Errorf("module %s: %s", m.Name, err)
167 }
168
169 // Check if the detector introduced something new.
170 source, subDir2 := getter.SourceDirSubdir(source)
171 if subDir2 != "" {
172 subDir = filepath.Join(subDir2, subDir)
173 }
174
175 // Get the directory where this module is so we can load it
176 key := strings.Join(path, ".")
177 key = fmt.Sprintf("root.%s-%s", key, m.Source)
178 dir, ok, err := getStorage(s, key, source, mode)
179 if err != nil {
180 return err
181 }
182 if !ok {
183 return fmt.Errorf(
184 "module %s: not found, may need to be downloaded using 'terraform get'", m.Name)
185 }
186
187 // If we have a subdirectory, then merge that in
188 if subDir != "" {
189 dir = filepath.Join(dir, subDir)
190 }
191
192 // Load the configurations.Dir(source)
193 children[m.Name], err = NewTreeModule(m.Name, dir)
194 if err != nil {
195 return fmt.Errorf(
196 "module %s: %s", m.Name, err)
197 }
198
199 // Set the path of this child
200 children[m.Name].path = path
201 }
202
203 // Go through all the children and load them.
204 for _, c := range children {
205 if err := c.Load(s, mode); err != nil {
206 return err
207 }
208 }
209
210 // Set our tree up
211 t.children = children
212
213 return nil
214}
215
216// Path is the full path to this tree.
217func (t *Tree) Path() []string {
218 return t.path
219}
220
221// String gives a nice output to describe the tree.
222func (t *Tree) String() string {
223 var result bytes.Buffer
224 path := strings.Join(t.path, ", ")
225 if path != "" {
226 path = fmt.Sprintf(" (path: %s)", path)
227 }
228 result.WriteString(t.Name() + path + "\n")
229
230 cs := t.Children()
231 if cs == nil {
232 result.WriteString(" not loaded")
233 } else {
234 // Go through each child and get its string value, then indent it
235 // by two.
236 for _, c := range cs {
237 r := strings.NewReader(c.String())
238 scanner := bufio.NewScanner(r)
239 for scanner.Scan() {
240 result.WriteString(" ")
241 result.WriteString(scanner.Text())
242 result.WriteString("\n")
243 }
244 }
245 }
246
247 return result.String()
248}
249
250// Validate does semantic checks on the entire tree of configurations.
251//
252// This will call the respective config.Config.Validate() functions as well
253// as verifying things such as parameters/outputs between the various modules.
254//
255// Load must be called prior to calling Validate or an error will be returned.
256func (t *Tree) Validate() error {
257 if !t.Loaded() {
258 return fmt.Errorf("tree must be loaded before calling Validate")
259 }
260
261 // If something goes wrong, here is our error template
262 newErr := &treeError{Name: []string{t.Name()}}
263
264 // Terraform core does not handle root module children named "root".
265 // We plan to fix this in the future but this bug was brought up in
266 // the middle of a release and we don't want to introduce wide-sweeping
267 // changes at that time.
268 if len(t.path) == 1 && t.name == "root" {
269 return fmt.Errorf("root module cannot contain module named 'root'")
270 }
271
272 // Validate our configuration first.
273 if err := t.config.Validate(); err != nil {
274 newErr.Add(err)
275 }
276
277 // If we're the root, we do extra validation. This validation usually
278 // requires the entire tree (since children don't have parent pointers).
279 if len(t.path) == 0 {
280 if err := t.validateProviderAlias(); err != nil {
281 newErr.Add(err)
282 }
283 }
284
285 // Get the child trees
286 children := t.Children()
287
288 // Validate all our children
289 for _, c := range children {
290 err := c.Validate()
291 if err == nil {
292 continue
293 }
294
295 verr, ok := err.(*treeError)
296 if !ok {
297 // Unknown error, just return...
298 return err
299 }
300
301 // Append ourselves to the error and then return
302 verr.Name = append(verr.Name, t.Name())
303 newErr.AddChild(verr)
304 }
305
306 // Go over all the modules and verify that any parameters are valid
307 // variables into the module in question.
308 for _, m := range t.config.Modules {
309 tree, ok := children[m.Name]
310 if !ok {
311 // This should never happen because Load watches us
312 panic("module not found in children: " + m.Name)
313 }
314
315 // Build the variables that the module defines
316 requiredMap := make(map[string]struct{})
317 varMap := make(map[string]struct{})
318 for _, v := range tree.config.Variables {
319 varMap[v.Name] = struct{}{}
320
321 if v.Required() {
322 requiredMap[v.Name] = struct{}{}
323 }
324 }
325
326 // Compare to the keys in our raw config for the module
327 for k, _ := range m.RawConfig.Raw {
328 if _, ok := varMap[k]; !ok {
329 newErr.Add(fmt.Errorf(
330 "module %s: %s is not a valid parameter",
331 m.Name, k))
332 }
333
334 // Remove the required
335 delete(requiredMap, k)
336 }
337
338 // If we have any required left over, they aren't set.
339 for k, _ := range requiredMap {
340 newErr.Add(fmt.Errorf(
341 "module %s: required variable %q not set",
342 m.Name, k))
343 }
344 }
345
346 // Go over all the variables used and make sure that any module
347 // variables represent outputs properly.
348 for source, vs := range t.config.InterpolatedVariables() {
349 for _, v := range vs {
350 mv, ok := v.(*config.ModuleVariable)
351 if !ok {
352 continue
353 }
354
355 tree, ok := children[mv.Name]
356 if !ok {
357 newErr.Add(fmt.Errorf(
358 "%s: undefined module referenced %s",
359 source, mv.Name))
360 continue
361 }
362
363 found := false
364 for _, o := range tree.config.Outputs {
365 if o.Name == mv.Field {
366 found = true
367 break
368 }
369 }
370 if !found {
371 newErr.Add(fmt.Errorf(
372 "%s: %s is not a valid output for module %s",
373 source, mv.Field, mv.Name))
374 }
375 }
376 }
377
378 return newErr.ErrOrNil()
379}
380
381// treeError is an error use by Tree.Validate to accumulates all
382// validation errors.
383type treeError struct {
384 Name []string
385 Errs []error
386 Children []*treeError
387}
388
389func (e *treeError) Add(err error) {
390 e.Errs = append(e.Errs, err)
391}
392
393func (e *treeError) AddChild(err *treeError) {
394 e.Children = append(e.Children, err)
395}
396
397func (e *treeError) ErrOrNil() error {
398 if len(e.Errs) > 0 || len(e.Children) > 0 {
399 return e
400 }
401 return nil
402}
403
404func (e *treeError) Error() string {
405 name := strings.Join(e.Name, ".")
406 var out bytes.Buffer
407 fmt.Fprintf(&out, "module %s: ", name)
408
409 if len(e.Errs) == 1 {
410 // single like error
411 out.WriteString(e.Errs[0].Error())
412 } else {
413 // multi-line error
414 for _, err := range e.Errs {
415 fmt.Fprintf(&out, "\n %s", err)
416 }
417 }
418
419 if len(e.Children) > 0 {
420 // start the next error on a new line
421 out.WriteString("\n ")
422 }
423 for _, child := range e.Children {
424 out.WriteString(child.Error())
425 }
426
427 return out.String()
428}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/tree_gob.go b/vendor/github.com/hashicorp/terraform/config/module/tree_gob.go
new file mode 100644
index 0000000..fcd37f4
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/tree_gob.go
@@ -0,0 +1,57 @@
1package module
2
3import (
4 "bytes"
5 "encoding/gob"
6
7 "github.com/hashicorp/terraform/config"
8)
9
10func (t *Tree) GobDecode(bs []byte) error {
11 t.lock.Lock()
12 defer t.lock.Unlock()
13
14 // Decode the gob data
15 var data treeGob
16 dec := gob.NewDecoder(bytes.NewReader(bs))
17 if err := dec.Decode(&data); err != nil {
18 return err
19 }
20
21 // Set the fields
22 t.name = data.Name
23 t.config = data.Config
24 t.children = data.Children
25 t.path = data.Path
26
27 return nil
28}
29
30func (t *Tree) GobEncode() ([]byte, error) {
31 data := &treeGob{
32 Config: t.config,
33 Children: t.children,
34 Name: t.name,
35 Path: t.path,
36 }
37
38 var buf bytes.Buffer
39 enc := gob.NewEncoder(&buf)
40 if err := enc.Encode(data); err != nil {
41 return nil, err
42 }
43
44 return buf.Bytes(), nil
45}
46
47// treeGob is used as a structure to Gob encode a tree.
48//
49// This structure is private so it can't be referenced but the fields are
50// public, allowing Gob to properly encode this. When we decode this, we are
51// able to turn it into a Tree.
52type treeGob struct {
53 Config *config.Config
54 Children map[string]*Tree
55 Name string
56 Path []string
57}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/validate_provider_alias.go b/vendor/github.com/hashicorp/terraform/config/module/validate_provider_alias.go
new file mode 100644
index 0000000..090d4f7
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/module/validate_provider_alias.go
@@ -0,0 +1,118 @@
1package module
2
3import (
4 "fmt"
5 "strings"
6
7 "github.com/hashicorp/go-multierror"
8 "github.com/hashicorp/terraform/dag"
9)
10
11// validateProviderAlias validates that all provider alias references are
12// defined at some point in the parent tree. This improves UX by catching
13// alias typos at the slight cost of requiring a declaration of usage. This
14// is usually a good tradeoff since not many aliases are used.
15func (t *Tree) validateProviderAlias() error {
16 // If we're not the root, don't perform this validation. We must be the
17 // root since we require full tree visibilty.
18 if len(t.path) != 0 {
19 return nil
20 }
21
22 // We'll use a graph to keep track of defined aliases at each level.
23 // As long as a parent defines an alias, it is okay.
24 var g dag.AcyclicGraph
25 t.buildProviderAliasGraph(&g, nil)
26
27 // Go through the graph and check that the usage is all good.
28 var err error
29 for _, v := range g.Vertices() {
30 pv, ok := v.(*providerAliasVertex)
31 if !ok {
32 // This shouldn't happen, just ignore it.
33 continue
34 }
35
36 // If we're not using any aliases, fast track and just continue
37 if len(pv.Used) == 0 {
38 continue
39 }
40
41 // Grab the ancestors since we're going to have to check if our
42 // parents define any of our aliases.
43 var parents []*providerAliasVertex
44 ancestors, _ := g.Ancestors(v)
45 for _, raw := range ancestors.List() {
46 if pv, ok := raw.(*providerAliasVertex); ok {
47 parents = append(parents, pv)
48 }
49 }
50 for k, _ := range pv.Used {
51 // Check if we define this
52 if _, ok := pv.Defined[k]; ok {
53 continue
54 }
55
56 // Check for a parent
57 found := false
58 for _, parent := range parents {
59 _, found = parent.Defined[k]
60 if found {
61 break
62 }
63 }
64 if found {
65 continue
66 }
67
68 // We didn't find the alias, error!
69 err = multierror.Append(err, fmt.Errorf(
70 "module %s: provider alias must be defined by the module or a parent: %s",
71 strings.Join(pv.Path, "."), k))
72 }
73 }
74
75 return err
76}
77
78func (t *Tree) buildProviderAliasGraph(g *dag.AcyclicGraph, parent dag.Vertex) {
79 // Add all our defined aliases
80 defined := make(map[string]struct{})
81 for _, p := range t.config.ProviderConfigs {
82 defined[p.FullName()] = struct{}{}
83 }
84
85 // Add all our used aliases
86 used := make(map[string]struct{})
87 for _, r := range t.config.Resources {
88 if r.Provider != "" {
89 used[r.Provider] = struct{}{}
90 }
91 }
92
93 // Add it to the graph
94 vertex := &providerAliasVertex{
95 Path: t.Path(),
96 Defined: defined,
97 Used: used,
98 }
99 g.Add(vertex)
100
101 // Connect to our parent if we have one
102 if parent != nil {
103 g.Connect(dag.BasicEdge(vertex, parent))
104 }
105
106 // Build all our children
107 for _, c := range t.Children() {
108 c.buildProviderAliasGraph(g, vertex)
109 }
110}
111
112// providerAliasVertex is the vertex for the graph that keeps track of
113// defined provider aliases.
114type providerAliasVertex struct {
115 Path []string
116 Defined map[string]struct{}
117 Used map[string]struct{}
118}