aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform
diff options
context:
space:
mode:
authorRadek Simko <radek.simko@gmail.com>2017-08-10 14:38:14 +0200
committerRadek Simko <radek.simko@gmail.com>2017-08-10 14:38:14 +0200
commitc680a8e1622ed0f18751d9d167c836ee24f5e897 (patch)
tree864f925049d422033dd25a73bafce32b361c8827 /vendor/github.com/hashicorp/terraform
parent38f8880ac81bfabc6d7f82e4dc89661f20fc559e (diff)
downloadterraform-provider-statuscake-c680a8e1622ed0f18751d9d167c836ee24f5e897.tar.gz
terraform-provider-statuscake-c680a8e1622ed0f18751d9d167c836ee24f5e897.tar.zst
terraform-provider-statuscake-c680a8e1622ed0f18751d9d167c836ee24f5e897.zip
vendor: github.com/hashicorp/terraform/...@v0.10.0
Diffstat (limited to 'vendor/github.com/hashicorp/terraform')
-rw-r--r--vendor/github.com/hashicorp/terraform/config/config.go42
-rw-r--r--vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go17
-rw-r--r--vendor/github.com/hashicorp/terraform/config/loader.go6
-rw-r--r--vendor/github.com/hashicorp/terraform/config/loader_hcl.go28
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/tree.go19
-rw-r--r--vendor/github.com/hashicorp/terraform/config/providers.go103
-rw-r--r--vendor/github.com/hashicorp/terraform/flatmap/expand.go7
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/resource/id.go33
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/resource/testing.go44
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/provider.go17
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go52
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/resource.go23
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/schema.go14
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/shadow/closer.go21
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/shadow/value.go8
-rw-r--r--vendor/github.com/hashicorp/terraform/moduledeps/dependencies.go43
-rw-r--r--vendor/github.com/hashicorp/terraform/moduledeps/doc.go7
-rw-r--r--vendor/github.com/hashicorp/terraform/moduledeps/module.go204
-rw-r--r--vendor/github.com/hashicorp/terraform/moduledeps/provider.go30
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/client.go24
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/error.go30
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/find.go168
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/get.go424
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/meta.go41
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go195
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go105
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go53
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/version.go72
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go84
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/context.go32
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/diff.go6
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/eval_diff.go36
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/graph_builder_plan.go10
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/graph_builder_refresh.go10
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/interpolate.go8
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/module_dependencies.go156
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go95
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/plan.go51
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/resource_address.go176
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/resource_provider.go81
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/state.go66
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/test_failure9
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/transform_resource_refresh_plannable.go55
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/transform_targets.go13
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/util.go20
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/version.go4
46 files changed, 2538 insertions, 204 deletions
diff --git a/vendor/github.com/hashicorp/terraform/config/config.go b/vendor/github.com/hashicorp/terraform/config/config.go
index a157824..3f756dc 100644
--- a/vendor/github.com/hashicorp/terraform/config/config.go
+++ b/vendor/github.com/hashicorp/terraform/config/config.go
@@ -12,6 +12,7 @@ import (
12 "github.com/hashicorp/hil" 12 "github.com/hashicorp/hil"
13 "github.com/hashicorp/hil/ast" 13 "github.com/hashicorp/hil/ast"
14 "github.com/hashicorp/terraform/helper/hilmapstructure" 14 "github.com/hashicorp/terraform/helper/hilmapstructure"
15 "github.com/hashicorp/terraform/plugin/discovery"
15 "github.com/mitchellh/reflectwalk" 16 "github.com/mitchellh/reflectwalk"
16) 17)
17 18
@@ -64,6 +65,7 @@ type Module struct {
64type ProviderConfig struct { 65type ProviderConfig struct {
65 Name string 66 Name string
66 Alias string 67 Alias string
68 Version string
67 RawConfig *RawConfig 69 RawConfig *RawConfig
68} 70}
69 71
@@ -238,6 +240,33 @@ func (r *Resource) Id() string {
238 } 240 }
239} 241}
240 242
243// ProviderFullName returns the full name of the provider for this resource,
244// which may either be specified explicitly using the "provider" meta-argument
245// or implied by the prefix on the resource type name.
246func (r *Resource) ProviderFullName() string {
247 return ResourceProviderFullName(r.Type, r.Provider)
248}
249
250// ResourceProviderFullName returns the full (dependable) name of the
251// provider for a hypothetical resource with the given resource type and
252// explicit provider string. If the explicit provider string is empty then
253// the provider name is inferred from the resource type name.
254func ResourceProviderFullName(resourceType, explicitProvider string) string {
255 if explicitProvider != "" {
256 return explicitProvider
257 }
258
259 idx := strings.IndexRune(resourceType, '_')
260 if idx == -1 {
261 // If no underscores, the resource name is assumed to be
262 // also the provider name, e.g. if the provider exposes
263 // only a single resource of each type.
264 return resourceType
265 }
266
267 return resourceType[:idx]
268}
269
241// Validate does some basic semantic checking of the configuration. 270// Validate does some basic semantic checking of the configuration.
242func (c *Config) Validate() error { 271func (c *Config) Validate() error {
243 if c == nil { 272 if c == nil {
@@ -349,7 +378,8 @@ func (c *Config) Validate() error {
349 } 378 }
350 } 379 }
351 380
352 // Check that providers aren't declared multiple times. 381 // Check that providers aren't declared multiple times and that their
382 // version constraints, where present, are syntactically valid.
353 providerSet := make(map[string]struct{}) 383 providerSet := make(map[string]struct{})
354 for _, p := range c.ProviderConfigs { 384 for _, p := range c.ProviderConfigs {
355 name := p.FullName() 385 name := p.FullName()
@@ -360,6 +390,16 @@ func (c *Config) Validate() error {
360 continue 390 continue
361 } 391 }
362 392
393 if p.Version != "" {
394 _, err := discovery.ConstraintStr(p.Version).Parse()
395 if err != nil {
396 errs = append(errs, fmt.Errorf(
397 "provider.%s: invalid version constraint %q: %s",
398 name, p.Version, err,
399 ))
400 }
401 }
402
363 providerSet[name] = struct{}{} 403 providerSet[name] = struct{}{}
364 } 404 }
365 405
diff --git a/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go b/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go
index 7b7b3f2..a298cf2 100644
--- a/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go
+++ b/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go
@@ -70,6 +70,7 @@ func Funcs() map[string]ast.Function {
70 "coalescelist": interpolationFuncCoalesceList(), 70 "coalescelist": interpolationFuncCoalesceList(),
71 "compact": interpolationFuncCompact(), 71 "compact": interpolationFuncCompact(),
72 "concat": interpolationFuncConcat(), 72 "concat": interpolationFuncConcat(),
73 "contains": interpolationFuncContains(),
73 "dirname": interpolationFuncDirname(), 74 "dirname": interpolationFuncDirname(),
74 "distinct": interpolationFuncDistinct(), 75 "distinct": interpolationFuncDistinct(),
75 "element": interpolationFuncElement(), 76 "element": interpolationFuncElement(),
@@ -356,6 +357,22 @@ func interpolationFuncCoalesceList() ast.Function {
356 } 357 }
357} 358}
358 359
360// interpolationFuncContains returns true if an element is in the list
361// and return false otherwise
362func interpolationFuncContains() ast.Function {
363 return ast.Function{
364 ArgTypes: []ast.Type{ast.TypeList, ast.TypeString},
365 ReturnType: ast.TypeBool,
366 Callback: func(args []interface{}) (interface{}, error) {
367 _, err := interpolationFuncIndex().Callback(args)
368 if err != nil {
369 return false, nil
370 }
371 return true, nil
372 },
373 }
374}
375
359// interpolationFuncConcat implements the "concat" function that concatenates 376// interpolationFuncConcat implements the "concat" function that concatenates
360// multiple lists. 377// multiple lists.
361func interpolationFuncConcat() ast.Function { 378func interpolationFuncConcat() ast.Function {
diff --git a/vendor/github.com/hashicorp/terraform/config/loader.go b/vendor/github.com/hashicorp/terraform/config/loader.go
index 0bfa89c..5dd7d46 100644
--- a/vendor/github.com/hashicorp/terraform/config/loader.go
+++ b/vendor/github.com/hashicorp/terraform/config/loader.go
@@ -194,7 +194,7 @@ func dirFiles(dir string) ([]string, []string, error) {
194 // Only care about files that are valid to load 194 // Only care about files that are valid to load
195 name := fi.Name() 195 name := fi.Name()
196 extValue := ext(name) 196 extValue := ext(name)
197 if extValue == "" || isIgnoredFile(name) { 197 if extValue == "" || IsIgnoredFile(name) {
198 continue 198 continue
199 } 199 }
200 200
@@ -215,9 +215,9 @@ func dirFiles(dir string) ([]string, []string, error) {
215 return files, overrides, nil 215 return files, overrides, nil
216} 216}
217 217
218// isIgnoredFile returns true or false depending on whether the 218// IsIgnoredFile returns true or false depending on whether the
219// provided file name is a file that should be ignored. 219// provided file name is a file that should be ignored.
220func isIgnoredFile(name string) bool { 220func IsIgnoredFile(name string) bool {
221 return strings.HasPrefix(name, ".") || // Unix-like hidden files 221 return strings.HasPrefix(name, ".") || // Unix-like hidden files
222 strings.HasSuffix(name, "~") || // vim 222 strings.HasSuffix(name, "~") || // vim
223 strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#") // emacs 223 strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#") // emacs
diff --git a/vendor/github.com/hashicorp/terraform/config/loader_hcl.go b/vendor/github.com/hashicorp/terraform/config/loader_hcl.go
index 9abb196..e85e493 100644
--- a/vendor/github.com/hashicorp/terraform/config/loader_hcl.go
+++ b/vendor/github.com/hashicorp/terraform/config/loader_hcl.go
@@ -17,6 +17,20 @@ type hclConfigurable struct {
17 Root *ast.File 17 Root *ast.File
18} 18}
19 19
20var ReservedResourceFields = []string{
21 "connection",
22 "count",
23 "depends_on",
24 "lifecycle",
25 "provider",
26 "provisioner",
27}
28
29var ReservedProviderFields = []string{
30 "alias",
31 "version",
32}
33
20func (t *hclConfigurable) Config() (*Config, error) { 34func (t *hclConfigurable) Config() (*Config, error) {
21 validKeys := map[string]struct{}{ 35 validKeys := map[string]struct{}{
22 "atlas": struct{}{}, 36 "atlas": struct{}{},
@@ -562,6 +576,7 @@ func loadProvidersHcl(list *ast.ObjectList) ([]*ProviderConfig, error) {
562 } 576 }
563 577
564 delete(config, "alias") 578 delete(config, "alias")
579 delete(config, "version")
565 580
566 rawConfig, err := NewRawConfig(config) 581 rawConfig, err := NewRawConfig(config)
567 if err != nil { 582 if err != nil {
@@ -583,9 +598,22 @@ func loadProvidersHcl(list *ast.ObjectList) ([]*ProviderConfig, error) {
583 } 598 }
584 } 599 }
585 600
601 // If we have a version field then extract it
602 var version string
603 if a := listVal.Filter("version"); len(a.Items) > 0 {
604 err := hcl.DecodeObject(&version, a.Items[0].Val)
605 if err != nil {
606 return nil, fmt.Errorf(
607 "Error reading version for provider[%s]: %s",
608 n,
609 err)
610 }
611 }
612
586 result = append(result, &ProviderConfig{ 613 result = append(result, &ProviderConfig{
587 Name: n, 614 Name: n,
588 Alias: alias, 615 Alias: alias,
616 Version: version,
589 RawConfig: rawConfig, 617 RawConfig: rawConfig,
590 }) 618 })
591 } 619 }
diff --git a/vendor/github.com/hashicorp/terraform/config/module/tree.go b/vendor/github.com/hashicorp/terraform/config/module/tree.go
index b6f90fd..4b0b153 100644
--- a/vendor/github.com/hashicorp/terraform/config/module/tree.go
+++ b/vendor/github.com/hashicorp/terraform/config/module/tree.go
@@ -92,6 +92,25 @@ func (t *Tree) Children() map[string]*Tree {
92 return t.children 92 return t.children
93} 93}
94 94
95// DeepEach calls the provided callback for the receiver and then all of
96// its descendents in the tree, allowing an operation to be performed on
97// all modules in the tree.
98//
99// Parents will be visited before their children but otherwise the order is
100// not defined.
101func (t *Tree) DeepEach(cb func(*Tree)) {
102 t.lock.RLock()
103 defer t.lock.RUnlock()
104 t.deepEach(cb)
105}
106
107func (t *Tree) deepEach(cb func(*Tree)) {
108 cb(t)
109 for _, c := range t.children {
110 c.deepEach(cb)
111 }
112}
113
95// Loaded says whether or not this tree has been loaded or not yet. 114// Loaded says whether or not this tree has been loaded or not yet.
96func (t *Tree) Loaded() bool { 115func (t *Tree) Loaded() bool {
97 t.lock.RLock() 116 t.lock.RLock()
diff --git a/vendor/github.com/hashicorp/terraform/config/providers.go b/vendor/github.com/hashicorp/terraform/config/providers.go
new file mode 100644
index 0000000..7a50782
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/providers.go
@@ -0,0 +1,103 @@
1package config
2
3import "github.com/blang/semver"
4
5// ProviderVersionConstraint presents a constraint for a particular
6// provider, identified by its full name.
7type ProviderVersionConstraint struct {
8 Constraint string
9 ProviderType string
10}
11
12// ProviderVersionConstraints is a map from provider full name to its associated
13// ProviderVersionConstraint, as produced by Config.RequiredProviders.
14type ProviderVersionConstraints map[string]ProviderVersionConstraint
15
16// RequiredProviders returns the ProviderVersionConstraints for this
17// module.
18//
19// This includes both providers that are explicitly requested by provider
20// blocks and those that are used implicitly by instantiating one of their
21// resource types. In the latter case, the returned semver Range will
22// accept any version of the provider.
23func (c *Config) RequiredProviders() ProviderVersionConstraints {
24 ret := make(ProviderVersionConstraints, len(c.ProviderConfigs))
25
26 configs := c.ProviderConfigsByFullName()
27
28 // In order to find the *implied* dependencies (those without explicit
29 // "provider" blocks) we need to walk over all of the resources and
30 // cross-reference with the provider configs.
31 for _, rc := range c.Resources {
32 providerName := rc.ProviderFullName()
33 var providerType string
34
35 // Default to (effectively) no constraint whatsoever, but we might
36 // override if there's an explicit constraint in config.
37 constraint := ">=0.0.0"
38
39 config, ok := configs[providerName]
40 if ok {
41 if config.Version != "" {
42 constraint = config.Version
43 }
44 providerType = config.Name
45 } else {
46 providerType = providerName
47 }
48
49 ret[providerName] = ProviderVersionConstraint{
50 ProviderType: providerType,
51 Constraint: constraint,
52 }
53 }
54
55 return ret
56}
57
58// RequiredRanges returns a semver.Range for each distinct provider type in
59// the constraint map. If the same provider type appears more than once
60// (e.g. because aliases are in use) then their respective constraints are
61// combined such that they must *all* apply.
62//
63// The result of this method can be passed to the
64// PluginMetaSet.ConstrainVersions method within the plugin/discovery
65// package in order to filter down the available plugins to those which
66// satisfy the given constraints.
67//
68// This function will panic if any of the constraints within cannot be
69// parsed as semver ranges. This is guaranteed to never happen for a
70// constraint set that was built from a configuration that passed validation.
71func (cons ProviderVersionConstraints) RequiredRanges() map[string]semver.Range {
72 ret := make(map[string]semver.Range, len(cons))
73
74 for _, con := range cons {
75 spec := semver.MustParseRange(con.Constraint)
76 if existing, exists := ret[con.ProviderType]; exists {
77 ret[con.ProviderType] = existing.AND(spec)
78 } else {
79 ret[con.ProviderType] = spec
80 }
81 }
82
83 return ret
84}
85
86// ProviderConfigsByFullName returns a map from provider full names (as
87// returned by ProviderConfig.FullName()) to the corresponding provider
88// configs.
89//
90// This function returns no new information than what's already in
91// c.ProviderConfigs, but returns it in a more convenient shape. If there
92// is more than one provider config with the same full name then the result
93// is undefined, but that is guaranteed not to happen for any config that
94// has passed validation.
95func (c *Config) ProviderConfigsByFullName() map[string]*ProviderConfig {
96 ret := make(map[string]*ProviderConfig, len(c.ProviderConfigs))
97
98 for _, pc := range c.ProviderConfigs {
99 ret[pc.FullName()] = pc
100 }
101
102 return ret
103}
diff --git a/vendor/github.com/hashicorp/terraform/flatmap/expand.go b/vendor/github.com/hashicorp/terraform/flatmap/expand.go
index e0b81b6..1449065 100644
--- a/vendor/github.com/hashicorp/terraform/flatmap/expand.go
+++ b/vendor/github.com/hashicorp/terraform/flatmap/expand.go
@@ -60,6 +60,11 @@ func expandArray(m map[string]string, prefix string) []interface{} {
60 return []interface{}{} 60 return []interface{}{}
61 } 61 }
62 62
63 // NOTE: "num" is not necessarily accurate, e.g. if a user tampers
64 // with state, so the following code should not crash when given a
65 // number of items more or less than what's given in num. The
66 // num key is mainly just a hint that this is a list or set.
67
63 // The Schema "Set" type stores its values in an array format, but 68 // The Schema "Set" type stores its values in an array format, but
64 // using numeric hash values instead of ordinal keys. Take the set 69 // using numeric hash values instead of ordinal keys. Take the set
65 // of keys regardless of value, and expand them in numeric order. 70 // of keys regardless of value, and expand them in numeric order.
@@ -101,7 +106,7 @@ func expandArray(m map[string]string, prefix string) []interface{} {
101 } 106 }
102 sort.Ints(keysList) 107 sort.Ints(keysList)
103 108
104 result := make([]interface{}, num) 109 result := make([]interface{}, len(keysList))
105 for i, key := range keysList { 110 for i, key := range keysList {
106 keyString := strconv.Itoa(key) 111 keyString := strconv.Itoa(key)
107 if computed[keyString] { 112 if computed[keyString] {
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/id.go b/vendor/github.com/hashicorp/terraform/helper/resource/id.go
index 629582b..1cde67c 100644
--- a/vendor/github.com/hashicorp/terraform/helper/resource/id.go
+++ b/vendor/github.com/hashicorp/terraform/helper/resource/id.go
@@ -1,21 +1,17 @@
1package resource 1package resource
2 2
3import ( 3import (
4 "crypto/rand"
5 "fmt" 4 "fmt"
6 "math/big" 5 "strings"
7 "sync" 6 "sync"
7 "time"
8) 8)
9 9
10const UniqueIdPrefix = `terraform-` 10const UniqueIdPrefix = `terraform-`
11 11
12// idCounter is a randomly seeded monotonic counter for generating ordered 12// idCounter is a monotonic counter for generating ordered unique ids.
13// unique ids. It uses a big.Int so we can easily increment a long numeric
14// string. The max possible hex value here with 12 random bytes is
15// "01000000000000000000000000", so there's no chance of rollover during
16// operation.
17var idMutex sync.Mutex 13var idMutex sync.Mutex
18var idCounter = big.NewInt(0).SetBytes(randomBytes(12)) 14var idCounter uint32
19 15
20// Helper for a resource to generate a unique identifier w/ default prefix 16// Helper for a resource to generate a unique identifier w/ default prefix
21func UniqueId() string { 17func UniqueId() string {
@@ -25,15 +21,20 @@ func UniqueId() string {
25// Helper for a resource to generate a unique identifier w/ given prefix 21// Helper for a resource to generate a unique identifier w/ given prefix
26// 22//
27// After the prefix, the ID consists of an incrementing 26 digit value (to match 23// After the prefix, the ID consists of an incrementing 26 digit value (to match
28// previous timestamp output). 24// previous timestamp output). After the prefix, the ID consists of a timestamp
25// and an incrementing 8 hex digit value The timestamp means that multiple IDs
26// created with the same prefix will sort in the order of their creation, even
27// across multiple terraform executions, as long as the clock is not turned back
28// between calls, and as long as any given terraform execution generates fewer
29// than 4 billion IDs.
29func PrefixedUniqueId(prefix string) string { 30func PrefixedUniqueId(prefix string) string {
31 // Be precise to 4 digits of fractional seconds, but remove the dot before the
32 // fractional seconds.
33 timestamp := strings.Replace(
34 time.Now().UTC().Format("20060102150405.0000"), ".", "", 1)
35
30 idMutex.Lock() 36 idMutex.Lock()
31 defer idMutex.Unlock() 37 defer idMutex.Unlock()
32 return fmt.Sprintf("%s%026x", prefix, idCounter.Add(idCounter, big.NewInt(1))) 38 idCounter++
33} 39 return fmt.Sprintf("%s%s%08x", prefix, timestamp, idCounter)
34
35func randomBytes(n int) []byte {
36 b := make([]byte, n)
37 rand.Read(b)
38 return b
39} 40}
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/testing.go b/vendor/github.com/hashicorp/terraform/helper/resource/testing.go
index ebdbde2..d7de1a0 100644
--- a/vendor/github.com/hashicorp/terraform/helper/resource/testing.go
+++ b/vendor/github.com/hashicorp/terraform/helper/resource/testing.go
@@ -383,11 +383,11 @@ func Test(t TestT, c TestCase) {
383 c.PreCheck() 383 c.PreCheck()
384 } 384 }
385 385
386 ctxProviders, err := testProviderFactories(c) 386 providerResolver, err := testProviderResolver(c)
387 if err != nil { 387 if err != nil {
388 t.Fatal(err) 388 t.Fatal(err)
389 } 389 }
390 opts := terraform.ContextOpts{Providers: ctxProviders} 390 opts := terraform.ContextOpts{ProviderResolver: providerResolver}
391 391
392 // A single state variable to track the lifecycle, starting with no state 392 // A single state variable to track the lifecycle, starting with no state
393 var state *terraform.State 393 var state *terraform.State
@@ -400,15 +400,22 @@ func Test(t TestT, c TestCase) {
400 var err error 400 var err error
401 log.Printf("[WARN] Test: Executing step %d", i) 401 log.Printf("[WARN] Test: Executing step %d", i)
402 402
403 // Determine the test mode to execute 403 if step.Config == "" && !step.ImportState {
404 if step.Config != "" {
405 state, err = testStepConfig(opts, state, step)
406 } else if step.ImportState {
407 state, err = testStepImportState(opts, state, step)
408 } else {
409 err = fmt.Errorf( 404 err = fmt.Errorf(
410 "unknown test mode for step. Please see TestStep docs\n\n%#v", 405 "unknown test mode for step. Please see TestStep docs\n\n%#v",
411 step) 406 step)
407 } else {
408 if step.ImportState {
409 if step.Config == "" {
410 step.Config = testProviderConfig(c)
411 }
412
413 // Can optionally set step.Config in addition to
414 // step.ImportState, to provide config for the import.
415 state, err = testStepImportState(opts, state, step)
416 } else {
417 state, err = testStepConfig(opts, state, step)
418 }
412 } 419 }
413 420
414 // If there was an error, exit 421 // If there was an error, exit
@@ -496,16 +503,29 @@ func Test(t TestT, c TestCase) {
496 } 503 }
497} 504}
498 505
499// testProviderFactories is a helper to build the ResourceProviderFactory map 506// testProviderConfig takes the list of Providers in a TestCase and returns a
507// config with only empty provider blocks. This is useful for Import, where no
508// config is provided, but the providers must be defined.
509func testProviderConfig(c TestCase) string {
510 var lines []string
511 for p := range c.Providers {
512 lines = append(lines, fmt.Sprintf("provider %q {}\n", p))
513 }
514
515 return strings.Join(lines, "")
516}
517
518// testProviderResolver is a helper to build a ResourceProviderResolver
500// with pre instantiated ResourceProviders, so that we can reset them for the 519// with pre instantiated ResourceProviders, so that we can reset them for the
501// test, while only calling the factory function once. 520// test, while only calling the factory function once.
502// Any errors are stored so that they can be returned by the factory in 521// Any errors are stored so that they can be returned by the factory in
503// terraform to match non-test behavior. 522// terraform to match non-test behavior.
504func testProviderFactories(c TestCase) (map[string]terraform.ResourceProviderFactory, error) { 523func testProviderResolver(c TestCase) (terraform.ResourceProviderResolver, error) {
505 ctxProviders := c.ProviderFactories // make(map[string]terraform.ResourceProviderFactory) 524 ctxProviders := c.ProviderFactories
506 if ctxProviders == nil { 525 if ctxProviders == nil {
507 ctxProviders = make(map[string]terraform.ResourceProviderFactory) 526 ctxProviders = make(map[string]terraform.ResourceProviderFactory)
508 } 527 }
528
509 // add any fixed providers 529 // add any fixed providers
510 for k, p := range c.Providers { 530 for k, p := range c.Providers {
511 ctxProviders[k] = terraform.ResourceProviderFactoryFixed(p) 531 ctxProviders[k] = terraform.ResourceProviderFactoryFixed(p)
@@ -527,7 +547,7 @@ func testProviderFactories(c TestCase) (map[string]terraform.ResourceProviderFac
527 } 547 }
528 } 548 }
529 549
530 return ctxProviders, nil 550 return terraform.ResourceProviderResolverFixed(ctxProviders), nil
531} 551}
532 552
533// UnitTest is a helper to force the acceptance testing harness to run in the 553// UnitTest is a helper to force the acceptance testing harness to run in the
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/provider.go b/vendor/github.com/hashicorp/terraform/helper/schema/provider.go
index d52d2f5..fb28b41 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/provider.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/provider.go
@@ -8,6 +8,7 @@ import (
8 "sync" 8 "sync"
9 9
10 "github.com/hashicorp/go-multierror" 10 "github.com/hashicorp/go-multierror"
11 "github.com/hashicorp/terraform/config"
11 "github.com/hashicorp/terraform/terraform" 12 "github.com/hashicorp/terraform/terraform"
12) 13)
13 14
@@ -89,6 +90,13 @@ func (p *Provider) InternalValidate() error {
89 validationErrors = multierror.Append(validationErrors, err) 90 validationErrors = multierror.Append(validationErrors, err)
90 } 91 }
91 92
93 // Provider-specific checks
94 for k, _ := range sm {
95 if isReservedProviderFieldName(k) {
96 return fmt.Errorf("%s is a reserved field name for a provider", k)
97 }
98 }
99
92 for k, r := range p.ResourcesMap { 100 for k, r := range p.ResourcesMap {
93 if err := r.InternalValidate(nil, true); err != nil { 101 if err := r.InternalValidate(nil, true); err != nil {
94 validationErrors = multierror.Append(validationErrors, fmt.Errorf("resource %s: %s", k, err)) 102 validationErrors = multierror.Append(validationErrors, fmt.Errorf("resource %s: %s", k, err))
@@ -104,6 +112,15 @@ func (p *Provider) InternalValidate() error {
104 return validationErrors 112 return validationErrors
105} 113}
106 114
115func isReservedProviderFieldName(name string) bool {
116 for _, reservedName := range config.ReservedProviderFields {
117 if name == reservedName {
118 return true
119 }
120 }
121 return false
122}
123
107// Meta returns the metadata associated with this provider that was 124// Meta returns the metadata associated with this provider that was
108// returned by the Configure call. It will be nil until Configure is called. 125// returned by the Configure call. It will be nil until Configure is called.
109func (p *Provider) Meta() interface{} { 126func (p *Provider) Meta() interface{} {
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go b/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go
index 856c675..476192e 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go
@@ -43,7 +43,7 @@ type Provisioner struct {
43 43
44 // ValidateFunc is a function for extended validation. This is optional 44 // ValidateFunc is a function for extended validation. This is optional
45 // and should be used when individual field validation is not enough. 45 // and should be used when individual field validation is not enough.
46 ValidateFunc func(*ResourceData) ([]string, []error) 46 ValidateFunc func(*terraform.ResourceConfig) ([]string, []error)
47 47
48 stopCtx context.Context 48 stopCtx context.Context
49 stopCtxCancel context.CancelFunc 49 stopCtxCancel context.CancelFunc
@@ -121,32 +121,6 @@ func (p *Provisioner) Stop() error {
121 return nil 121 return nil
122} 122}
123 123
124func (p *Provisioner) Validate(config *terraform.ResourceConfig) ([]string, []error) {
125 if err := p.InternalValidate(); err != nil {
126 return nil, []error{fmt.Errorf(
127 "Internal validation of the provisioner failed! This is always a bug\n"+
128 "with the provisioner itself, and not a user issue. Please report\n"+
129 "this bug:\n\n%s", err)}
130 }
131 w := []string{}
132 e := []error{}
133 if p.Schema != nil {
134 w2, e2 := schemaMap(p.Schema).Validate(config)
135 w = append(w, w2...)
136 e = append(e, e2...)
137 }
138 if p.ValidateFunc != nil {
139 data := &ResourceData{
140 schema: p.Schema,
141 config: config,
142 }
143 w2, e2 := p.ValidateFunc(data)
144 w = append(w, w2...)
145 e = append(e, e2...)
146 }
147 return w, e
148}
149
150// Apply implementation of terraform.ResourceProvisioner interface. 124// Apply implementation of terraform.ResourceProvisioner interface.
151func (p *Provisioner) Apply( 125func (p *Provisioner) Apply(
152 o terraform.UIOutput, 126 o terraform.UIOutput,
@@ -204,3 +178,27 @@ func (p *Provisioner) Apply(
204 ctx = context.WithValue(ctx, ProvRawStateKey, s) 178 ctx = context.WithValue(ctx, ProvRawStateKey, s)
205 return p.ApplyFunc(ctx) 179 return p.ApplyFunc(ctx)
206} 180}
181
182// Validate implements the terraform.ResourceProvisioner interface.
183func (p *Provisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) {
184 if err := p.InternalValidate(); err != nil {
185 return nil, []error{fmt.Errorf(
186 "Internal validation of the provisioner failed! This is always a bug\n"+
187 "with the provisioner itself, and not a user issue. Please report\n"+
188 "this bug:\n\n%s", err)}
189 }
190
191 if p.Schema != nil {
192 w, e := schemaMap(p.Schema).Validate(c)
193 ws = append(ws, w...)
194 es = append(es, e...)
195 }
196
197 if p.ValidateFunc != nil {
198 w, e := p.ValidateFunc(c)
199 ws = append(ws, w...)
200 es = append(es, e...)
201 }
202
203 return ws, es
204}
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/resource.go b/vendor/github.com/hashicorp/terraform/helper/schema/resource.go
index c810558..ddba109 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/resource.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/resource.go
@@ -6,6 +6,7 @@ import (
6 "log" 6 "log"
7 "strconv" 7 "strconv"
8 8
9 "github.com/hashicorp/terraform/config"
9 "github.com/hashicorp/terraform/terraform" 10 "github.com/hashicorp/terraform/terraform"
10) 11)
11 12
@@ -142,6 +143,12 @@ func (r *Resource) Apply(
142 if err := rt.DiffDecode(d); err != nil { 143 if err := rt.DiffDecode(d); err != nil {
143 log.Printf("[ERR] Error decoding ResourceTimeout: %s", err) 144 log.Printf("[ERR] Error decoding ResourceTimeout: %s", err)
144 } 145 }
146 } else if s != nil {
147 if _, ok := s.Meta[TimeoutKey]; ok {
148 if err := rt.StateDecode(s); err != nil {
149 log.Printf("[ERR] Error decoding ResourceTimeout: %s", err)
150 }
151 }
145 } else { 152 } else {
146 log.Printf("[DEBUG] No meta timeoutkey found in Apply()") 153 log.Printf("[DEBUG] No meta timeoutkey found in Apply()")
147 } 154 }
@@ -388,9 +395,25 @@ func (r *Resource) InternalValidate(topSchemaMap schemaMap, writable bool) error
388 } 395 }
389 } 396 }
390 397
398 // Resource-specific checks
399 for k, _ := range tsm {
400 if isReservedResourceFieldName(k) {
401 return fmt.Errorf("%s is a reserved field name for a resource", k)
402 }
403 }
404
391 return schemaMap(r.Schema).InternalValidate(tsm) 405 return schemaMap(r.Schema).InternalValidate(tsm)
392} 406}
393 407
408func isReservedResourceFieldName(name string) bool {
409 for _, reservedName := range config.ReservedResourceFields {
410 if name == reservedName {
411 return true
412 }
413 }
414 return false
415}
416
394// Data returns a ResourceData struct for this Resource. Each return value 417// Data returns a ResourceData struct for this Resource. Each return value
395// is a separate copy and can be safely modified differently. 418// is a separate copy and can be safely modified differently.
396// 419//
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/schema.go b/vendor/github.com/hashicorp/terraform/helper/schema/schema.go
index 632672a..acb5618 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/schema.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/schema.go
@@ -15,6 +15,7 @@ import (
15 "fmt" 15 "fmt"
16 "os" 16 "os"
17 "reflect" 17 "reflect"
18 "regexp"
18 "sort" 19 "sort"
19 "strconv" 20 "strconv"
20 "strings" 21 "strings"
@@ -661,7 +662,13 @@ func (m schemaMap) InternalValidate(topSchemaMap schemaMap) error {
661 if v.ValidateFunc != nil { 662 if v.ValidateFunc != nil {
662 switch v.Type { 663 switch v.Type {
663 case TypeList, TypeSet: 664 case TypeList, TypeSet:
664 return fmt.Errorf("ValidateFunc is not yet supported on lists or sets.") 665 return fmt.Errorf("%s: ValidateFunc is not yet supported on lists or sets.", k)
666 }
667 }
668
669 if v.Deprecated == "" && v.Removed == "" {
670 if !isValidFieldName(k) {
671 return fmt.Errorf("%s: Field name may only contain lowercase alphanumeric characters & underscores.", k)
665 } 672 }
666 } 673 }
667 } 674 }
@@ -669,6 +676,11 @@ func (m schemaMap) InternalValidate(topSchemaMap schemaMap) error {
669 return nil 676 return nil
670} 677}
671 678
679func isValidFieldName(name string) bool {
680 re := regexp.MustCompile("^[a-z0-9_]+$")
681 return re.MatchString(name)
682}
683
672func (m schemaMap) diff( 684func (m schemaMap) diff(
673 k string, 685 k string,
674 schema *Schema, 686 schema *Schema,
diff --git a/vendor/github.com/hashicorp/terraform/helper/shadow/closer.go b/vendor/github.com/hashicorp/terraform/helper/shadow/closer.go
index 7edd5e7..edc1e2a 100644
--- a/vendor/github.com/hashicorp/terraform/helper/shadow/closer.go
+++ b/vendor/github.com/hashicorp/terraform/helper/shadow/closer.go
@@ -39,6 +39,8 @@ func (w *closeWalker) Struct(reflect.Value) error {
39 return nil 39 return nil
40} 40}
41 41
42var closerType = reflect.TypeOf((*io.Closer)(nil)).Elem()
43
42func (w *closeWalker) StructField(f reflect.StructField, v reflect.Value) error { 44func (w *closeWalker) StructField(f reflect.StructField, v reflect.Value) error {
43 // Not sure why this would be but lets avoid some panics 45 // Not sure why this would be but lets avoid some panics
44 if !v.IsValid() { 46 if !v.IsValid() {
@@ -56,17 +58,18 @@ func (w *closeWalker) StructField(f reflect.StructField, v reflect.Value) error
56 return nil 58 return nil
57 } 59 }
58 60
59 // We're looking for an io.Closer 61 var closer io.Closer
60 raw := v.Interface() 62 if v.Type().Implements(closerType) {
61 if raw == nil { 63 closer = v.Interface().(io.Closer)
62 return nil 64 } else if v.CanAddr() {
65 // The Close method may require a pointer receiver, but we only have a value.
66 v := v.Addr()
67 if v.Type().Implements(closerType) {
68 closer = v.Interface().(io.Closer)
69 }
63 } 70 }
64 71
65 closer, ok := raw.(io.Closer) 72 if closer == nil {
66 if !ok && v.CanAddr() {
67 closer, ok = v.Addr().Interface().(io.Closer)
68 }
69 if !ok {
70 return reflectwalk.SkipEntry 73 return reflectwalk.SkipEntry
71 } 74 }
72 75
diff --git a/vendor/github.com/hashicorp/terraform/helper/shadow/value.go b/vendor/github.com/hashicorp/terraform/helper/shadow/value.go
index 2413335..178b7e7 100644
--- a/vendor/github.com/hashicorp/terraform/helper/shadow/value.go
+++ b/vendor/github.com/hashicorp/terraform/helper/shadow/value.go
@@ -26,6 +26,14 @@ type Value struct {
26 valueSet bool 26 valueSet bool
27} 27}
28 28
29func (v *Value) Lock() {
30 v.lock.Lock()
31}
32
33func (v *Value) Unlock() {
34 v.lock.Unlock()
35}
36
29// Close closes the value. This can never fail. For a definition of 37// Close closes the value. This can never fail. For a definition of
30// "close" see the struct docs. 38// "close" see the struct docs.
31func (w *Value) Close() error { 39func (w *Value) Close() error {
diff --git a/vendor/github.com/hashicorp/terraform/moduledeps/dependencies.go b/vendor/github.com/hashicorp/terraform/moduledeps/dependencies.go
new file mode 100644
index 0000000..87c8431
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/moduledeps/dependencies.go
@@ -0,0 +1,43 @@
1package moduledeps
2
3import (
4 "github.com/hashicorp/terraform/plugin/discovery"
5)
6
7// Providers describes a set of provider dependencies for a given module.
8//
9// Each named provider instance can have one version constraint.
10type Providers map[ProviderInstance]ProviderDependency
11
12// ProviderDependency describes the dependency for a particular provider
13// instance, including both the set of allowed versions and the reason for
14// the dependency.
15type ProviderDependency struct {
16 Constraints discovery.Constraints
17 Reason ProviderDependencyReason
18}
19
20// ProviderDependencyReason is an enumeration of reasons why a dependency might be
21// present.
22type ProviderDependencyReason int
23
24const (
25 // ProviderDependencyExplicit means that there is an explicit "provider"
26 // block in the configuration for this module.
27 ProviderDependencyExplicit ProviderDependencyReason = iota
28
29 // ProviderDependencyImplicit means that there is no explicit "provider"
30 // block but there is at least one resource that uses this provider.
31 ProviderDependencyImplicit
32
33 // ProviderDependencyInherited is a special case of
34 // ProviderDependencyImplicit where a parent module has defined a
35 // configuration for the provider that has been inherited by at least one
36 // resource in this module.
37 ProviderDependencyInherited
38
39 // ProviderDependencyFromState means that this provider is not currently
40 // referenced by configuration at all, but some existing instances in
41 // the state still depend on it.
42 ProviderDependencyFromState
43)
diff --git a/vendor/github.com/hashicorp/terraform/moduledeps/doc.go b/vendor/github.com/hashicorp/terraform/moduledeps/doc.go
new file mode 100644
index 0000000..7eff083
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/moduledeps/doc.go
@@ -0,0 +1,7 @@
1// Package moduledeps contains types that can be used to describe the
2// providers required for all of the modules in a module tree.
3//
4// It does not itself contain the functionality for populating such
5// data structures; that's in Terraform core, since this package intentionally
6// does not depend on terraform core to avoid package dependency cycles.
7package moduledeps
diff --git a/vendor/github.com/hashicorp/terraform/moduledeps/module.go b/vendor/github.com/hashicorp/terraform/moduledeps/module.go
new file mode 100644
index 0000000..d6cbaf5
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/moduledeps/module.go
@@ -0,0 +1,204 @@
1package moduledeps
2
3import (
4 "sort"
5 "strings"
6
7 "github.com/hashicorp/terraform/plugin/discovery"
8)
9
10// Module represents the dependencies of a single module, as well being
11// a node in a tree of such structures representing the dependencies of
12// an entire configuration.
13type Module struct {
14 Name string
15 Providers Providers
16 Children []*Module
17}
18
19// WalkFunc is a callback type for use with Module.WalkTree
20type WalkFunc func(path []string, parent *Module, current *Module) error
21
22// WalkTree calls the given callback once for the receiver and then
23// once for each descendent, in an order such that parents are called
24// before their children and siblings are called in the order they
25// appear in the Children slice.
26//
27// When calling the callback, parent will be nil for the first call
28// for the receiving module, and then set to the direct parent of
29// each module for the subsequent calls.
30//
31// The path given to the callback is valid only until the callback
32// returns, after which it will be mutated and reused. Callbacks must
33// therefore copy the path slice if they wish to retain it.
34//
35// If the given callback returns an error, the walk will be aborted at
36// that point and that error returned to the caller.
37//
38// This function is not thread-safe for concurrent modifications of the
39// data structure, so it's the caller's responsibility to arrange for that
40// should it be needed.
41//
42// It is safe for a callback to modify the descendents of the "current"
43// module, including the ordering of the Children slice itself, but the
44// callback MUST NOT modify the parent module.
45func (m *Module) WalkTree(cb WalkFunc) error {
46 return walkModuleTree(make([]string, 0, 1), nil, m, cb)
47}
48
49func walkModuleTree(path []string, parent *Module, current *Module, cb WalkFunc) error {
50 path = append(path, current.Name)
51 err := cb(path, parent, current)
52 if err != nil {
53 return err
54 }
55
56 for _, child := range current.Children {
57 err := walkModuleTree(path, current, child, cb)
58 if err != nil {
59 return err
60 }
61 }
62 return nil
63}
64
65// SortChildren sorts the Children slice into lexicographic order by
66// name, in-place.
67//
68// This is primarily useful prior to calling WalkTree so that the walk
69// will proceed in a consistent order.
70func (m *Module) SortChildren() {
71 sort.Sort(sortModules{m.Children})
72}
73
74// SortDescendents is a convenience wrapper for calling SortChildren on
75// the receiver and all of its descendent modules.
76func (m *Module) SortDescendents() {
77 m.WalkTree(func(path []string, parent *Module, current *Module) error {
78 current.SortChildren()
79 return nil
80 })
81}
82
83type sortModules struct {
84 modules []*Module
85}
86
87func (s sortModules) Len() int {
88 return len(s.modules)
89}
90
91func (s sortModules) Less(i, j int) bool {
92 cmp := strings.Compare(s.modules[i].Name, s.modules[j].Name)
93 return cmp < 0
94}
95
96func (s sortModules) Swap(i, j int) {
97 s.modules[i], s.modules[j] = s.modules[j], s.modules[i]
98}
99
100// PluginRequirements produces a PluginRequirements structure that can
101// be used with discovery.PluginMetaSet.ConstrainVersions to identify
102// suitable plugins to satisfy the module's provider dependencies.
103//
104// This method only considers the direct requirements of the receiver.
105// Use AllPluginRequirements to flatten the dependencies for the
106// entire tree of modules.
107//
108// Requirements returned by this method include only version constraints,
109// and apply no particular SHA256 hash constraint.
110func (m *Module) PluginRequirements() discovery.PluginRequirements {
111 ret := make(discovery.PluginRequirements)
112 for inst, dep := range m.Providers {
113 // m.Providers is keyed on provider names, such as "aws.foo".
114 // a PluginRequirements wants keys to be provider *types*, such
115 // as "aws". If there are multiple aliases for the same
116 // provider then we will flatten them into a single requirement
117 // by combining their constraint sets.
118 pty := inst.Type()
119 if existing, exists := ret[pty]; exists {
120 ret[pty].Versions = existing.Versions.Append(dep.Constraints)
121 } else {
122 ret[pty] = &discovery.PluginConstraints{
123 Versions: dep.Constraints,
124 }
125 }
126 }
127 return ret
128}
129
130// AllPluginRequirements calls PluginRequirements for the receiver and all
131// of its descendents, and merges the result into a single PluginRequirements
132// structure that would satisfy all of the modules together.
133//
134// Requirements returned by this method include only version constraints,
135// and apply no particular SHA256 hash constraint.
136func (m *Module) AllPluginRequirements() discovery.PluginRequirements {
137 var ret discovery.PluginRequirements
138 m.WalkTree(func(path []string, parent *Module, current *Module) error {
139 ret = ret.Merge(current.PluginRequirements())
140 return nil
141 })
142 return ret
143}
144
145// Equal returns true if the receiver is the root of an identical tree
146// to the other given Module. This is a deep comparison that considers
147// the equality of all downstream modules too.
148//
149// The children are considered to be ordered, so callers may wish to use
150// SortDescendents first to normalize the order of the slices of child nodes.
151//
152// The implementation of this function is not optimized since it is provided
153// primarily for use in tests.
154func (m *Module) Equal(other *Module) bool {
155 // take care of nils first
156 if m == nil && other == nil {
157 return true
158 } else if (m == nil && other != nil) || (m != nil && other == nil) {
159 return false
160 }
161
162 if m.Name != other.Name {
163 return false
164 }
165
166 if len(m.Providers) != len(other.Providers) {
167 return false
168 }
169 if len(m.Children) != len(other.Children) {
170 return false
171 }
172
173 // Can't use reflect.DeepEqual on this provider structure because
174 // the nested Constraints objects contain function pointers that
175 // never compare as equal. So we'll need to walk it the long way.
176 for inst, dep := range m.Providers {
177 if _, exists := other.Providers[inst]; !exists {
178 return false
179 }
180
181 if dep.Reason != other.Providers[inst].Reason {
182 return false
183 }
184
185 // Constraints are not too easy to compare robustly, so
186 // we'll just use their string representations as a proxy
187 // for now.
188 if dep.Constraints.String() != other.Providers[inst].Constraints.String() {
189 return false
190 }
191 }
192
193 // Above we already checked that we have the same number of children
194 // in each module, so now we just need to check that they are
195 // recursively equal.
196 for i := range m.Children {
197 if !m.Children[i].Equal(other.Children[i]) {
198 return false
199 }
200 }
201
202 // If we fall out here then they are equal
203 return true
204}
diff --git a/vendor/github.com/hashicorp/terraform/moduledeps/provider.go b/vendor/github.com/hashicorp/terraform/moduledeps/provider.go
new file mode 100644
index 0000000..89ceefb
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/moduledeps/provider.go
@@ -0,0 +1,30 @@
1package moduledeps
2
3import (
4 "strings"
5)
6
7// ProviderInstance describes a particular provider instance by its full name,
8// like "null" or "aws.foo".
9type ProviderInstance string
10
11// Type returns the provider type of this instance. For example, for an instance
12// named "aws.foo" the type is "aws".
13func (p ProviderInstance) Type() string {
14 t := string(p)
15 if dotPos := strings.Index(t, "."); dotPos != -1 {
16 t = t[:dotPos]
17 }
18 return t
19}
20
21// Alias returns the alias of this provider, if any. An instance named "aws.foo"
22// has the alias "foo", while an instance named just "docker" has no alias,
23// so the empty string would be returned.
24func (p ProviderInstance) Alias() string {
25 t := string(p)
26 if dotPos := strings.Index(t, "."); dotPos != -1 {
27 return t[dotPos+1:]
28 }
29 return ""
30}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/client.go b/vendor/github.com/hashicorp/terraform/plugin/client.go
new file mode 100644
index 0000000..3a5cb7a
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/client.go
@@ -0,0 +1,24 @@
1package plugin
2
3import (
4 "os/exec"
5
6 plugin "github.com/hashicorp/go-plugin"
7 "github.com/hashicorp/terraform/plugin/discovery"
8)
9
10// ClientConfig returns a configuration object that can be used to instantiate
11// a client for the plugin described by the given metadata.
12func ClientConfig(m discovery.PluginMeta) *plugin.ClientConfig {
13 return &plugin.ClientConfig{
14 Cmd: exec.Command(m.Path),
15 HandshakeConfig: Handshake,
16 Managed: true,
17 Plugins: PluginMap,
18 }
19}
20
21// Client returns a plugin client for the plugin described by the given metadata.
22func Client(m discovery.PluginMeta) *plugin.Client {
23 return plugin.NewClient(ClientConfig(m))
24}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/error.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/error.go
new file mode 100644
index 0000000..df855a7
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/error.go
@@ -0,0 +1,30 @@
1package discovery
2
3// Error is a type used to describe situations that the caller must handle
4// since they indicate some form of user error.
5//
6// The functions and methods that return these specialized errors indicate so
7// in their documentation. The Error type should not itself be used directly,
8// but rather errors should be compared using the == operator with the
9// error constants in this package.
10//
11// Values of this type are _not_ used when the error being reported is an
12// operational error (server unavailable, etc) or indicative of a bug in
13// this package or its caller.
14type Error string
15
16// ErrorNoSuitableVersion indicates that a suitable version (meeting given
17// constraints) is not available.
18const ErrorNoSuitableVersion = Error("no suitable version is available")
19
20// ErrorNoVersionCompatible indicates that all of the available versions
21// that otherwise met constraints are not compatible with the current
22// version of Terraform.
23const ErrorNoVersionCompatible = Error("no available version is compatible with this version of Terraform")
24
25// ErrorNoSuchProvider indicates that no provider exists with a name given
26const ErrorNoSuchProvider = Error("no provider exists with the given name")
27
28func (err Error) Error() string {
29 return string(err)
30}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go
new file mode 100644
index 0000000..f5bc4c1
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go
@@ -0,0 +1,168 @@
1package discovery
2
3import (
4 "io/ioutil"
5 "log"
6 "path/filepath"
7 "strings"
8)
9
10// FindPlugins looks in the given directories for files whose filenames
11// suggest that they are plugins of the given kind (e.g. "provider") and
12// returns a PluginMetaSet representing the discovered potential-plugins.
13//
14// Currently this supports two different naming schemes. The current
15// standard naming scheme is a subdirectory called $GOOS-$GOARCH containing
16// files named terraform-$KIND-$NAME-V$VERSION. The legacy naming scheme is
17// files directly in the given directory whose names are like
18// terraform-$KIND-$NAME.
19//
20// Only one plugin will be returned for each unique plugin (name, version)
21// pair, with preference given to files found in earlier directories.
22//
23// This is a convenience wrapper around FindPluginPaths and ResolvePluginsPaths.
24func FindPlugins(kind string, dirs []string) PluginMetaSet {
25 return ResolvePluginPaths(FindPluginPaths(kind, dirs))
26}
27
28// FindPluginPaths looks in the given directories for files whose filenames
29// suggest that they are plugins of the given kind (e.g. "provider").
30//
31// The return value is a list of absolute paths that appear to refer to
32// plugins in the given directories, based only on what can be inferred
33// from the naming scheme. The paths returned are ordered such that files
34// in later dirs appear after files in earlier dirs in the given directory
35// list. Within the same directory plugins are returned in a consistent but
36// undefined order.
37func FindPluginPaths(kind string, dirs []string) []string {
38 // This is just a thin wrapper around findPluginPaths so that we can
39 // use the latter in tests with a fake machineName so we can use our
40 // test fixtures.
41 return findPluginPaths(kind, dirs)
42}
43
44func findPluginPaths(kind string, dirs []string) []string {
45 prefix := "terraform-" + kind + "-"
46
47 ret := make([]string, 0, len(dirs))
48
49 for _, dir := range dirs {
50 items, err := ioutil.ReadDir(dir)
51 if err != nil {
52 // Ignore missing dirs, non-dirs, etc
53 continue
54 }
55
56 log.Printf("[DEBUG] checking for %s in %q", kind, dir)
57
58 for _, item := range items {
59 fullName := item.Name()
60
61 if !strings.HasPrefix(fullName, prefix) {
62 log.Printf("[DEBUG] skipping %q, not a %s", fullName, kind)
63 continue
64 }
65
66 // New-style paths must have a version segment in filename
67 if strings.Contains(strings.ToLower(fullName), "_v") {
68 absPath, err := filepath.Abs(filepath.Join(dir, fullName))
69 if err != nil {
70 log.Printf("[ERROR] plugin filepath error: %s", err)
71 continue
72 }
73
74 log.Printf("[DEBUG] found %s %q", kind, fullName)
75 ret = append(ret, filepath.Clean(absPath))
76 continue
77 }
78
79 // Legacy style with files directly in the base directory
80 absPath, err := filepath.Abs(filepath.Join(dir, fullName))
81 if err != nil {
82 log.Printf("[ERROR] plugin filepath error: %s", err)
83 continue
84 }
85
86 log.Printf("[WARNING] found legacy %s %q", kind, fullName)
87
88 ret = append(ret, filepath.Clean(absPath))
89 }
90 }
91
92 return ret
93}
94
95// ResolvePluginPaths takes a list of paths to plugin executables (as returned
96// by e.g. FindPluginPaths) and produces a PluginMetaSet describing the
97// referenced plugins.
98//
99// If the same combination of plugin name and version appears multiple times,
100// the earlier reference will be preferred. Several different versions of
101// the same plugin name may be returned, in which case the methods of
102// PluginMetaSet can be used to filter down.
103func ResolvePluginPaths(paths []string) PluginMetaSet {
104 s := make(PluginMetaSet)
105
106 type nameVersion struct {
107 Name string
108 Version string
109 }
110 found := make(map[nameVersion]struct{})
111
112 for _, path := range paths {
113 baseName := strings.ToLower(filepath.Base(path))
114 if !strings.HasPrefix(baseName, "terraform-") {
115 // Should never happen with reasonable input
116 continue
117 }
118
119 baseName = baseName[10:]
120 firstDash := strings.Index(baseName, "-")
121 if firstDash == -1 {
122 // Should never happen with reasonable input
123 continue
124 }
125
126 baseName = baseName[firstDash+1:]
127 if baseName == "" {
128 // Should never happen with reasonable input
129 continue
130 }
131
132 // Trim the .exe suffix used on Windows before we start wrangling
133 // the remainder of the path.
134 if strings.HasSuffix(baseName, ".exe") {
135 baseName = baseName[:len(baseName)-4]
136 }
137
138 parts := strings.SplitN(baseName, "_v", 2)
139 name := parts[0]
140 version := VersionZero
141 if len(parts) == 2 {
142 version = parts[1]
143 }
144
145 // Auto-installed plugins contain an extra name portion representing
146 // the expected plugin version, which we must trim off.
147 if underX := strings.Index(version, "_x"); underX != -1 {
148 version = version[:underX]
149 }
150
151 if _, ok := found[nameVersion{name, version}]; ok {
152 // Skip duplicate versions of the same plugin
153 // (We do this during this step because after this we will be
154 // dealing with sets and thus lose our ordering with which to
155 // decide preference.)
156 continue
157 }
158
159 s.Add(PluginMeta{
160 Name: name,
161 Version: VersionStr(version),
162 Path: path,
163 })
164 found[nameVersion{name, version}] = struct{}{}
165 }
166
167 return s
168}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go
new file mode 100644
index 0000000..241b5cb
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go
@@ -0,0 +1,424 @@
1package discovery
2
3import (
4 "errors"
5 "fmt"
6 "io/ioutil"
7 "log"
8 "net/http"
9 "os"
10 "runtime"
11 "strconv"
12 "strings"
13
14 "golang.org/x/net/html"
15
16 cleanhttp "github.com/hashicorp/go-cleanhttp"
17 getter "github.com/hashicorp/go-getter"
18 multierror "github.com/hashicorp/go-multierror"
19)
20
21// Releases are located by parsing the html listing from releases.hashicorp.com.
22//
23// The URL for releases follows the pattern:
24// https://releases.hashicorp.com/terraform-provider-name/<x.y.z>/terraform-provider-name_<x.y.z>_<os>_<arch>.<ext>
25//
26// The plugin protocol version will be saved with the release and returned in
27// the header X-TERRAFORM_PROTOCOL_VERSION.
28
29const protocolVersionHeader = "x-terraform-protocol-version"
30
31var releaseHost = "https://releases.hashicorp.com"
32
33var httpClient = cleanhttp.DefaultClient()
34
35// An Installer maintains a local cache of plugins by downloading plugins
36// from an online repository.
37type Installer interface {
38 Get(name string, req Constraints) (PluginMeta, error)
39 PurgeUnused(used map[string]PluginMeta) (removed PluginMetaSet, err error)
40}
41
42// ProviderInstaller is an Installer implementation that knows how to
43// download Terraform providers from the official HashiCorp releases service
44// into a local directory. The files downloaded are compliant with the
45// naming scheme expected by FindPlugins, so the target directory of a
46// provider installer can be used as one of several plugin discovery sources.
47type ProviderInstaller struct {
48 Dir string
49
50 PluginProtocolVersion uint
51
52 // OS and Arch specify the OS and architecture that should be used when
53 // installing plugins. These use the same labels as the runtime.GOOS and
54 // runtime.GOARCH variables respectively, and indeed the values of these
55 // are used as defaults if either of these is the empty string.
56 OS string
57 Arch string
58
59 // Skip checksum and signature verification
60 SkipVerify bool
61}
62
63// Get is part of an implementation of type Installer, and attempts to download
64// and install a Terraform provider matching the given constraints.
65//
66// This method may return one of a number of sentinel errors from this
67// package to indicate issues that are likely to be resolvable via user action:
68//
69// ErrorNoSuchProvider: no provider with the given name exists in the repository.
70// ErrorNoSuitableVersion: the provider exists but no available version matches constraints.
71// ErrorNoVersionCompatible: a plugin was found within the constraints but it is
72// incompatible with the current Terraform version.
73//
74// These errors should be recognized and handled as special cases by the caller
75// to present a suitable user-oriented error message.
76//
77// All other errors indicate an internal problem that is likely _not_ solvable
78// through user action, or at least not within Terraform's scope. Error messages
79// are produced under the assumption that if presented to the user they will
80// be presented alongside context about what is being installed, and thus the
81// error messages do not redundantly include such information.
82func (i *ProviderInstaller) Get(provider string, req Constraints) (PluginMeta, error) {
83 versions, err := i.listProviderVersions(provider)
84 // TODO: return multiple errors
85 if err != nil {
86 return PluginMeta{}, err
87 }
88
89 if len(versions) == 0 {
90 return PluginMeta{}, ErrorNoSuitableVersion
91 }
92
93 versions = allowedVersions(versions, req)
94 if len(versions) == 0 {
95 return PluginMeta{}, ErrorNoSuitableVersion
96 }
97
98 // sort them newest to oldest
99 Versions(versions).Sort()
100
101 // take the first matching plugin we find
102 for _, v := range versions {
103 url := i.providerURL(provider, v.String())
104
105 if !i.SkipVerify {
106 sha256, err := i.getProviderChecksum(provider, v.String())
107 if err != nil {
108 return PluginMeta{}, err
109 }
110
111 // add the checksum parameter for go-getter to verify the download for us.
112 if sha256 != "" {
113 url = url + "?checksum=sha256:" + sha256
114 }
115 }
116
117 log.Printf("[DEBUG] fetching provider info for %s version %s", provider, v)
118 if checkPlugin(url, i.PluginProtocolVersion) {
119 log.Printf("[DEBUG] getting provider %q version %q at %s", provider, v, url)
120 err := getter.Get(i.Dir, url)
121 if err != nil {
122 return PluginMeta{}, err
123 }
124
125 // Find what we just installed
126 // (This is weird, because go-getter doesn't directly return
127 // information about what was extracted, and we just extracted
128 // the archive directly into a shared dir here.)
129 log.Printf("[DEBUG] looking for the %s %s plugin we just installed", provider, v)
130 metas := FindPlugins("provider", []string{i.Dir})
131 log.Printf("[DEBUG] all plugins found %#v", metas)
132 metas, _ = metas.ValidateVersions()
133 metas = metas.WithName(provider).WithVersion(v)
134 log.Printf("[DEBUG] filtered plugins %#v", metas)
135 if metas.Count() == 0 {
136 // This should never happen. Suggests that the release archive
137 // contains an executable file whose name doesn't match the
138 // expected convention.
139 return PluginMeta{}, fmt.Errorf(
140 "failed to find installed plugin version %s; this is a bug in Terraform and should be reported",
141 v,
142 )
143 }
144
145 if metas.Count() > 1 {
146 // This should also never happen, and suggests that a
147 // particular version was re-released with a different
148 // executable filename. We consider releases as immutable, so
149 // this is an error.
150 return PluginMeta{}, fmt.Errorf(
151 "multiple plugins installed for version %s; this is a bug in Terraform and should be reported",
152 v,
153 )
154 }
155
156 // By now we know we have exactly one meta, and so "Newest" will
157 // return that one.
158 return metas.Newest(), nil
159 }
160
161 log.Printf("[INFO] incompatible ProtocolVersion for %s version %s", provider, v)
162 }
163
164 return PluginMeta{}, ErrorNoVersionCompatible
165}
166
167func (i *ProviderInstaller) PurgeUnused(used map[string]PluginMeta) (PluginMetaSet, error) {
168 purge := make(PluginMetaSet)
169
170 present := FindPlugins("provider", []string{i.Dir})
171 for meta := range present {
172 chosen, ok := used[meta.Name]
173 if !ok {
174 purge.Add(meta)
175 }
176 if chosen.Path != meta.Path {
177 purge.Add(meta)
178 }
179 }
180
181 removed := make(PluginMetaSet)
182 var errs error
183 for meta := range purge {
184 path := meta.Path
185 err := os.Remove(path)
186 if err != nil {
187 errs = multierror.Append(errs, fmt.Errorf(
188 "failed to remove unused provider plugin %s: %s",
189 path, err,
190 ))
191 } else {
192 removed.Add(meta)
193 }
194 }
195
196 return removed, errs
197}
198
199// Plugins are referred to by the short name, but all URLs and files will use
200// the full name prefixed with terraform-<plugin_type>-
201func (i *ProviderInstaller) providerName(name string) string {
202 return "terraform-provider-" + name
203}
204
205func (i *ProviderInstaller) providerFileName(name, version string) string {
206 os := i.OS
207 arch := i.Arch
208 if os == "" {
209 os = runtime.GOOS
210 }
211 if arch == "" {
212 arch = runtime.GOARCH
213 }
214 return fmt.Sprintf("%s_%s_%s_%s.zip", i.providerName(name), version, os, arch)
215}
216
217// providerVersionsURL returns the path to the released versions directory for the provider:
218// https://releases.hashicorp.com/terraform-provider-name/
219func (i *ProviderInstaller) providerVersionsURL(name string) string {
220 return releaseHost + "/" + i.providerName(name) + "/"
221}
222
223// providerURL returns the full path to the provider file, using the current OS
224// and ARCH:
225// .../terraform-provider-name_<x.y.z>/terraform-provider-name_<x.y.z>_<os>_<arch>.<ext>
226func (i *ProviderInstaller) providerURL(name, version string) string {
227 return fmt.Sprintf("%s%s/%s", i.providerVersionsURL(name), version, i.providerFileName(name, version))
228}
229
230func (i *ProviderInstaller) providerChecksumURL(name, version string) string {
231 fileName := fmt.Sprintf("%s_%s_SHA256SUMS", i.providerName(name), version)
232 u := fmt.Sprintf("%s%s/%s", i.providerVersionsURL(name), version, fileName)
233 return u
234}
235
236func (i *ProviderInstaller) getProviderChecksum(name, version string) (string, error) {
237 checksums, err := getPluginSHA256SUMs(i.providerChecksumURL(name, version))
238 if err != nil {
239 return "", err
240 }
241
242 return checksumForFile(checksums, i.providerFileName(name, version)), nil
243}
244
245// Return the plugin version by making a HEAD request to the provided url.
246// If the header is not present, we assume the latest version will be
247// compatible, and leave the check for discovery or execution.
248func checkPlugin(url string, pluginProtocolVersion uint) bool {
249 resp, err := httpClient.Head(url)
250 if err != nil {
251 log.Printf("[ERROR] error fetching plugin headers: %s", err)
252 return false
253 }
254
255 if resp.StatusCode != http.StatusOK {
256 log.Println("[ERROR] non-200 status fetching plugin headers:", resp.Status)
257 return false
258 }
259
260 proto := resp.Header.Get(protocolVersionHeader)
261 if proto == "" {
262 // The header isn't present, but we don't make this error fatal since
263 // the latest version will probably work.
264 log.Printf("[WARNING] missing %s from: %s", protocolVersionHeader, url)
265 return true
266 }
267
268 protoVersion, err := strconv.Atoi(proto)
269 if err != nil {
270 log.Printf("[ERROR] invalid ProtocolVersion: %s", proto)
271 return false
272 }
273
274 return protoVersion == int(pluginProtocolVersion)
275}
276
277// list the version available for the named plugin
278func (i *ProviderInstaller) listProviderVersions(name string) ([]Version, error) {
279 versions, err := listPluginVersions(i.providerVersionsURL(name))
280 if err != nil {
281 // listPluginVersions returns a verbose error message indicating
282 // what was being accessed and what failed
283 return nil, err
284 }
285 return versions, nil
286}
287
288var errVersionNotFound = errors.New("version not found")
289
290// take the list of available versions for a plugin, and filter out those that
291// don't fit the constraints.
292func allowedVersions(available []Version, required Constraints) []Version {
293 var allowed []Version
294
295 for _, v := range available {
296 if required.Allows(v) {
297 allowed = append(allowed, v)
298 }
299 }
300
301 return allowed
302}
303
304// return a list of the plugin versions at the given URL
305func listPluginVersions(url string) ([]Version, error) {
306 resp, err := httpClient.Get(url)
307 if err != nil {
308 // http library produces a verbose error message that includes the
309 // URL being accessed, etc.
310 return nil, err
311 }
312 defer resp.Body.Close()
313
314 if resp.StatusCode != http.StatusOK {
315 body, _ := ioutil.ReadAll(resp.Body)
316 log.Printf("[ERROR] failed to fetch plugin versions from %s\n%s\n%s", url, resp.Status, body)
317
318 switch resp.StatusCode {
319 case http.StatusNotFound, http.StatusForbidden:
320 // These are treated as indicative of the given name not being
321 // a valid provider name at all.
322 return nil, ErrorNoSuchProvider
323
324 default:
325 // All other errors are assumed to be operational problems.
326 return nil, fmt.Errorf("error accessing %s: %s", url, resp.Status)
327 }
328
329 }
330
331 body, err := html.Parse(resp.Body)
332 if err != nil {
333 log.Fatal(err)
334 }
335
336 names := []string{}
337
338 // all we need to do is list links on the directory listing page that look like plugins
339 var f func(*html.Node)
340 f = func(n *html.Node) {
341 if n.Type == html.ElementNode && n.Data == "a" {
342 c := n.FirstChild
343 if c != nil && c.Type == html.TextNode && strings.HasPrefix(c.Data, "terraform-") {
344 names = append(names, c.Data)
345 return
346 }
347 }
348 for c := n.FirstChild; c != nil; c = c.NextSibling {
349 f(c)
350 }
351 }
352 f(body)
353
354 return versionsFromNames(names), nil
355}
356
357// parse the list of directory names into a sorted list of available versions
358func versionsFromNames(names []string) []Version {
359 var versions []Version
360 for _, name := range names {
361 parts := strings.SplitN(name, "_", 2)
362 if len(parts) == 2 && parts[1] != "" {
363 v, err := VersionStr(parts[1]).Parse()
364 if err != nil {
365 // filter invalid versions scraped from the page
366 log.Printf("[WARN] invalid version found for %q: %s", name, err)
367 continue
368 }
369
370 versions = append(versions, v)
371 }
372 }
373
374 return versions
375}
376
377func checksumForFile(sums []byte, name string) string {
378 for _, line := range strings.Split(string(sums), "\n") {
379 parts := strings.Fields(line)
380 if len(parts) > 1 && parts[1] == name {
381 return parts[0]
382 }
383 }
384 return ""
385}
386
387// fetch the SHA256SUMS file provided, and verify its signature.
388func getPluginSHA256SUMs(sumsURL string) ([]byte, error) {
389 sigURL := sumsURL + ".sig"
390
391 sums, err := getFile(sumsURL)
392 if err != nil {
393 return nil, fmt.Errorf("error fetching checksums: %s", err)
394 }
395
396 sig, err := getFile(sigURL)
397 if err != nil {
398 return nil, fmt.Errorf("error fetching checksums signature: %s", err)
399 }
400
401 if err := verifySig(sums, sig); err != nil {
402 return nil, err
403 }
404
405 return sums, nil
406}
407
408func getFile(url string) ([]byte, error) {
409 resp, err := httpClient.Get(url)
410 if err != nil {
411 return nil, err
412 }
413 defer resp.Body.Close()
414
415 if resp.StatusCode != http.StatusOK {
416 return nil, fmt.Errorf("%s", resp.Status)
417 }
418
419 data, err := ioutil.ReadAll(resp.Body)
420 if err != nil {
421 return data, err
422 }
423 return data, nil
424}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/meta.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/meta.go
new file mode 100644
index 0000000..bdcebcb
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/meta.go
@@ -0,0 +1,41 @@
1package discovery
2
3import (
4 "crypto/sha256"
5 "io"
6 "os"
7)
8
9// PluginMeta is metadata about a plugin, useful for launching the plugin
10// and for understanding which plugins are available.
11type PluginMeta struct {
12 // Name is the name of the plugin, e.g. as inferred from the plugin
13 // binary's filename, or by explicit configuration.
14 Name string
15
16 // Version is the semver version of the plugin, expressed as a string
17 // that might not be semver-valid.
18 Version VersionStr
19
20 // Path is the absolute path of the executable that can be launched
21 // to provide the RPC server for this plugin.
22 Path string
23}
24
25// SHA256 returns a SHA256 hash of the content of the referenced executable
26// file, or an error if the file's contents cannot be read.
27func (m PluginMeta) SHA256() ([]byte, error) {
28 f, err := os.Open(m.Path)
29 if err != nil {
30 return nil, err
31 }
32 defer f.Close()
33
34 h := sha256.New()
35 _, err = io.Copy(h, f)
36 if err != nil {
37 return nil, err
38 }
39
40 return h.Sum(nil), nil
41}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go
new file mode 100644
index 0000000..181ea1f
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go
@@ -0,0 +1,195 @@
1package discovery
2
3// A PluginMetaSet is a set of PluginMeta objects meeting a certain criteria.
4//
5// Methods on this type allow filtering of the set to produce subsets that
6// meet more restrictive criteria.
7type PluginMetaSet map[PluginMeta]struct{}
8
9// Add inserts the given PluginMeta into the receiving set. This is a no-op
10// if the given meta is already present.
11func (s PluginMetaSet) Add(p PluginMeta) {
12 s[p] = struct{}{}
13}
14
15// Remove removes the given PluginMeta from the receiving set. This is a no-op
16// if the given meta is not already present.
17func (s PluginMetaSet) Remove(p PluginMeta) {
18 delete(s, p)
19}
20
21// Has returns true if the given meta is in the receiving set, or false
22// otherwise.
23func (s PluginMetaSet) Has(p PluginMeta) bool {
24 _, ok := s[p]
25 return ok
26}
27
28// Count returns the number of metas in the set
29func (s PluginMetaSet) Count() int {
30 return len(s)
31}
32
33// ValidateVersions returns two new PluginMetaSets, separating those with
34// versions that have syntax-valid semver versions from those that don't.
35//
36// Eliminating invalid versions from consideration (and possibly warning about
37// them) is usually the first step of working with a meta set after discovery
38// has completed.
39func (s PluginMetaSet) ValidateVersions() (valid, invalid PluginMetaSet) {
40 valid = make(PluginMetaSet)
41 invalid = make(PluginMetaSet)
42 for p := range s {
43 if _, err := p.Version.Parse(); err == nil {
44 valid.Add(p)
45 } else {
46 invalid.Add(p)
47 }
48 }
49 return
50}
51
52// WithName returns the subset of metas that have the given name.
53func (s PluginMetaSet) WithName(name string) PluginMetaSet {
54 ns := make(PluginMetaSet)
55 for p := range s {
56 if p.Name == name {
57 ns.Add(p)
58 }
59 }
60 return ns
61}
62
63// WithVersion returns the subset of metas that have the given version.
64//
65// This should be used only with the "valid" result from ValidateVersions;
66// it will ignore any plugin metas that have a invalid version strings.
67func (s PluginMetaSet) WithVersion(version Version) PluginMetaSet {
68 ns := make(PluginMetaSet)
69 for p := range s {
70 gotVersion, err := p.Version.Parse()
71 if err != nil {
72 continue
73 }
74 if gotVersion.Equal(version) {
75 ns.Add(p)
76 }
77 }
78 return ns
79}
80
81// ByName groups the metas in the set by their Names, returning a map.
82func (s PluginMetaSet) ByName() map[string]PluginMetaSet {
83 ret := make(map[string]PluginMetaSet)
84 for p := range s {
85 if _, ok := ret[p.Name]; !ok {
86 ret[p.Name] = make(PluginMetaSet)
87 }
88 ret[p.Name].Add(p)
89 }
90 return ret
91}
92
93// Newest returns the one item from the set that has the newest Version value.
94//
95// The result is meaningful only if the set is already filtered such that
96// all of the metas have the same Name.
97//
98// If there isn't at least one meta in the set then this function will panic.
99// Use Count() to ensure that there is at least one value before calling.
100//
101// If any of the metas have invalid version strings then this function will
102// panic. Use ValidateVersions() first to filter out metas with invalid
103// versions.
104//
105// If two metas have the same Version then one is arbitrarily chosen. This
106// situation should be avoided by pre-filtering the set.
107func (s PluginMetaSet) Newest() PluginMeta {
108 if len(s) == 0 {
109 panic("can't call NewestStable on empty PluginMetaSet")
110 }
111
112 var first = true
113 var winner PluginMeta
114 var winnerVersion Version
115 for p := range s {
116 version, err := p.Version.Parse()
117 if err != nil {
118 panic(err)
119 }
120
121 if first == true || version.NewerThan(winnerVersion) {
122 winner = p
123 winnerVersion = version
124 first = false
125 }
126 }
127
128 return winner
129}
130
131// ConstrainVersions takes a set of requirements and attempts to
132// return a map from name to a set of metas that have the matching
133// name and an appropriate version.
134//
135// If any of the given requirements match *no* plugins then its PluginMetaSet
136// in the returned map will be empty.
137//
138// All viable metas are returned, so the caller can apply any desired filtering
139// to reduce down to a single option. For example, calling Newest() to obtain
140// the highest available version.
141//
142// If any of the metas in the set have invalid version strings then this
143// function will panic. Use ValidateVersions() first to filter out metas with
144// invalid versions.
145func (s PluginMetaSet) ConstrainVersions(reqd PluginRequirements) map[string]PluginMetaSet {
146 ret := make(map[string]PluginMetaSet)
147 for p := range s {
148 name := p.Name
149 allowedVersions, ok := reqd[name]
150 if !ok {
151 continue
152 }
153 if _, ok := ret[p.Name]; !ok {
154 ret[p.Name] = make(PluginMetaSet)
155 }
156 version, err := p.Version.Parse()
157 if err != nil {
158 panic(err)
159 }
160 if allowedVersions.Allows(version) {
161 ret[p.Name].Add(p)
162 }
163 }
164 return ret
165}
166
167// OverridePaths returns a new set where any existing plugins with the given
168// names are removed and replaced with the single path given in the map.
169//
170// This is here only to continue to support the legacy way of overriding
171// plugin binaries in the .terraformrc file. It treats all given plugins
172// as pre-versioning (version 0.0.0). This mechanism will eventually be
173// phased out, with vendor directories being the intended replacement.
174func (s PluginMetaSet) OverridePaths(paths map[string]string) PluginMetaSet {
175 ret := make(PluginMetaSet)
176 for p := range s {
177 if _, ok := paths[p.Name]; ok {
178 // Skip plugins that we're overridding
179 continue
180 }
181
182 ret.Add(p)
183 }
184
185 // Now add the metadata for overriding plugins
186 for name, path := range paths {
187 ret.Add(PluginMeta{
188 Name: name,
189 Version: VersionZero,
190 Path: path,
191 })
192 }
193
194 return ret
195}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go
new file mode 100644
index 0000000..75430fd
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go
@@ -0,0 +1,105 @@
1package discovery
2
3import (
4 "bytes"
5)
6
7// PluginRequirements describes a set of plugins (assumed to be of a consistent
8// kind) that are required to exist and have versions within the given
9// corresponding sets.
10type PluginRequirements map[string]*PluginConstraints
11
12// PluginConstraints represents an element of PluginRequirements describing
13// the constraints for a single plugin.
14type PluginConstraints struct {
15 // Specifies that the plugin's version must be within the given
16 // constraints.
17 Versions Constraints
18
19 // If non-nil, the hash of the on-disk plugin executable must exactly
20 // match the SHA256 hash given here.
21 SHA256 []byte
22}
23
24// Allows returns true if the given version is within the receiver's version
25// constraints.
26func (s *PluginConstraints) Allows(v Version) bool {
27 return s.Versions.Allows(v)
28}
29
30// AcceptsSHA256 returns true if the given executable SHA256 hash is acceptable,
31// either because it matches the constraint or because there is no such
32// constraint.
33func (s *PluginConstraints) AcceptsSHA256(digest []byte) bool {
34 if s.SHA256 == nil {
35 return true
36 }
37 return bytes.Equal(s.SHA256, digest)
38}
39
40// Merge takes the contents of the receiver and the other given requirements
41// object and merges them together into a single requirements structure
42// that satisfies both sets of requirements.
43//
44// Note that it doesn't make sense to merge two PluginRequirements with
45// differing required plugin SHA256 hashes, since the result will never
46// match any plugin.
47func (r PluginRequirements) Merge(other PluginRequirements) PluginRequirements {
48 ret := make(PluginRequirements)
49 for n, c := range r {
50 ret[n] = &PluginConstraints{
51 Versions: Constraints{}.Append(c.Versions),
52 SHA256: c.SHA256,
53 }
54 }
55 for n, c := range other {
56 if existing, exists := ret[n]; exists {
57 ret[n].Versions = ret[n].Versions.Append(c.Versions)
58
59 if existing.SHA256 != nil {
60 if c.SHA256 != nil && !bytes.Equal(c.SHA256, existing.SHA256) {
61 // If we've been asked to merge two constraints with
62 // different SHA256 hashes then we'll produce a dummy value
63 // that can never match anything. This is a silly edge case
64 // that no reasonable caller should hit.
65 ret[n].SHA256 = []byte(invalidProviderHash)
66 }
67 } else {
68 ret[n].SHA256 = c.SHA256 // might still be nil
69 }
70 } else {
71 ret[n] = &PluginConstraints{
72 Versions: Constraints{}.Append(c.Versions),
73 SHA256: c.SHA256,
74 }
75 }
76 }
77 return ret
78}
79
80// LockExecutables applies additional constraints to the receiver that
81// require plugin executables with specific SHA256 digests. This modifies
82// the receiver in-place, since it's intended to be applied after
83// version constraints have been resolved.
84//
85// The given map must include a key for every plugin that is already
86// required. If not, any missing keys will cause the corresponding plugin
87// to never match, though the direct caller doesn't necessarily need to
88// guarantee this as long as the downstream code _applying_ these constraints
89// is able to deal with the non-match in some way.
90func (r PluginRequirements) LockExecutables(sha256s map[string][]byte) {
91 for name, cons := range r {
92 digest := sha256s[name]
93
94 if digest == nil {
95 // Prevent any match, which will then presumably cause the
96 // downstream consumer of this requirements to report an error.
97 cons.SHA256 = []byte(invalidProviderHash)
98 continue
99 }
100
101 cons.SHA256 = digest
102 }
103}
104
105const invalidProviderHash = "<invalid>"
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go
new file mode 100644
index 0000000..b6686a5
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go
@@ -0,0 +1,53 @@
1package discovery
2
3import (
4 "bytes"
5 "log"
6 "strings"
7
8 "golang.org/x/crypto/openpgp"
9)
10
11// Verify the data using the provided openpgp detached signature and the
12// embedded hashicorp public key.
13func verifySig(data, sig []byte) error {
14 el, err := openpgp.ReadArmoredKeyRing(strings.NewReader(hashiPublicKey))
15 if err != nil {
16 log.Fatal(err)
17 }
18
19 _, err = openpgp.CheckDetachedSignature(el, bytes.NewReader(data), bytes.NewReader(sig))
20 return err
21}
22
23// this is the public key that signs the checksums file for releases.
24const hashiPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
25Version: GnuPG v1
26
27mQENBFMORM0BCADBRyKO1MhCirazOSVwcfTr1xUxjPvfxD3hjUwHtjsOy/bT6p9f
28W2mRPfwnq2JB5As+paL3UGDsSRDnK9KAxQb0NNF4+eVhr/EJ18s3wwXXDMjpIifq
29fIm2WyH3G+aRLTLPIpscUNKDyxFOUbsmgXAmJ46Re1fn8uKxKRHbfa39aeuEYWFA
303drdL1WoUngvED7f+RnKBK2G6ZEpO+LDovQk19xGjiMTtPJrjMjZJ3QXqPvx5wca
31KSZLr4lMTuoTI/ZXyZy5bD4tShiZz6KcyX27cD70q2iRcEZ0poLKHyEIDAi3TM5k
32SwbbWBFd5RNPOR0qzrb/0p9ksKK48IIfH2FvABEBAAG0K0hhc2hpQ29ycCBTZWN1
33cml0eSA8c2VjdXJpdHlAaGFzaGljb3JwLmNvbT6JATgEEwECACIFAlMORM0CGwMG
34CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEFGFLYc0j/xMyWIIAIPhcVqiQ59n
35Jc07gjUX0SWBJAxEG1lKxfzS4Xp+57h2xxTpdotGQ1fZwsihaIqow337YHQI3q0i
36SqV534Ms+j/tU7X8sq11xFJIeEVG8PASRCwmryUwghFKPlHETQ8jJ+Y8+1asRydi
37psP3B/5Mjhqv/uOK+Vy3zAyIpyDOMtIpOVfjSpCplVRdtSTFWBu9Em7j5I2HMn1w
38sJZnJgXKpybpibGiiTtmnFLOwibmprSu04rsnP4ncdC2XRD4wIjoyA+4PKgX3sCO
39klEzKryWYBmLkJOMDdo52LttP3279s7XrkLEE7ia0fXa2c12EQ0f0DQ1tGUvyVEW
40WmJVccm5bq25AQ0EUw5EzQEIANaPUY04/g7AmYkOMjaCZ6iTp9hB5Rsj/4ee/ln9
41wArzRO9+3eejLWh53FoN1rO+su7tiXJA5YAzVy6tuolrqjM8DBztPxdLBbEi4V+j
422tK0dATdBQBHEh3OJApO2UBtcjaZBT31zrG9K55D+CrcgIVEHAKY8Cb4kLBkb5wM
43skn+DrASKU0BNIV1qRsxfiUdQHZfSqtp004nrql1lbFMLFEuiY8FZrkkQ9qduixo
44mTT6f34/oiY+Jam3zCK7RDN/OjuWheIPGj/Qbx9JuNiwgX6yRj7OE1tjUx6d8g9y
450H1fmLJbb3WZZbuuGFnK6qrE3bGeY8+AWaJAZ37wpWh1p0cAEQEAAYkBHwQYAQIA
46CQUCUw5EzQIbDAAKCRBRhS2HNI/8TJntCAClU7TOO/X053eKF1jqNW4A1qpxctVc
47z8eTcY8Om5O4f6a/rfxfNFKn9Qyja/OG1xWNobETy7MiMXYjaa8uUx5iFy6kMVaP
480BXJ59NLZjMARGw6lVTYDTIvzqqqwLxgliSDfSnqUhubGwvykANPO+93BBx89MRG
49unNoYGXtPlhNFrAsB1VR8+EyKLv2HQtGCPSFBhrjuzH3gxGibNDDdFQLxxuJWepJ
50EK1UbTS4ms0NgZ2Uknqn1WRU1Ki7rE4sTy68iZtWpKQXZEJa0IGnuI2sSINGcXCJ
51oEIgXTMyCILo34Fa/C6VCm2WBgz9zZO8/rHIiQm1J5zqz0DrDwKBUM9C
52=LYpS
53-----END PGP PUBLIC KEY BLOCK-----`
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/version.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/version.go
new file mode 100644
index 0000000..8fad58d
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/version.go
@@ -0,0 +1,72 @@
1package discovery
2
3import (
4 "fmt"
5 "sort"
6
7 version "github.com/hashicorp/go-version"
8)
9
10const VersionZero = "0.0.0"
11
12// A VersionStr is a string containing a possibly-invalid representation
13// of a semver version number. Call Parse on it to obtain a real Version
14// object, or discover that it is invalid.
15type VersionStr string
16
17// Parse transforms a VersionStr into a Version if it is
18// syntactically valid. If it isn't then an error is returned instead.
19func (s VersionStr) Parse() (Version, error) {
20 raw, err := version.NewVersion(string(s))
21 if err != nil {
22 return Version{}, err
23 }
24 return Version{raw}, nil
25}
26
27// MustParse transforms a VersionStr into a Version if it is
28// syntactically valid. If it isn't then it panics.
29func (s VersionStr) MustParse() Version {
30 ret, err := s.Parse()
31 if err != nil {
32 panic(err)
33 }
34 return ret
35}
36
37// Version represents a version number that has been parsed from
38// a semver string and known to be valid.
39type Version struct {
40 // We wrap this here just because it avoids a proliferation of
41 // direct go-version imports all over the place, and keeps the
42 // version-processing details within this package.
43 raw *version.Version
44}
45
46func (v Version) String() string {
47 return v.raw.String()
48}
49
50func (v Version) NewerThan(other Version) bool {
51 return v.raw.GreaterThan(other.raw)
52}
53
54func (v Version) Equal(other Version) bool {
55 return v.raw.Equal(other.raw)
56}
57
58// MinorUpgradeConstraintStr returns a ConstraintStr that would permit
59// minor upgrades relative to the receiving version.
60func (v Version) MinorUpgradeConstraintStr() ConstraintStr {
61 segments := v.raw.Segments()
62 return ConstraintStr(fmt.Sprintf("~> %d.%d", segments[0], segments[1]))
63}
64
65type Versions []Version
66
67// Sort sorts version from newest to oldest.
68func (v Versions) Sort() {
69 sort.Slice(v, func(i, j int) bool {
70 return v[i].NewerThan(v[j])
71 })
72}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go
new file mode 100644
index 0000000..0aefd75
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go
@@ -0,0 +1,84 @@
1package discovery
2
3import (
4 "sort"
5
6 version "github.com/hashicorp/go-version"
7)
8
9// A ConstraintStr is a string containing a possibly-invalid representation
10// of a version constraint provided in configuration. Call Parse on it to
11// obtain a real Constraint object, or discover that it is invalid.
12type ConstraintStr string
13
14// Parse transforms a ConstraintStr into a Constraints if it is
15// syntactically valid. If it isn't then an error is returned instead.
16func (s ConstraintStr) Parse() (Constraints, error) {
17 raw, err := version.NewConstraint(string(s))
18 if err != nil {
19 return Constraints{}, err
20 }
21 return Constraints{raw}, nil
22}
23
24// MustParse is like Parse but it panics if the constraint string is invalid.
25func (s ConstraintStr) MustParse() Constraints {
26 ret, err := s.Parse()
27 if err != nil {
28 panic(err)
29 }
30 return ret
31}
32
33// Constraints represents a set of versions which any given Version is either
34// a member of or not.
35type Constraints struct {
36 raw version.Constraints
37}
38
39// AllVersions is a Constraints containing all versions
40var AllVersions Constraints
41
42func init() {
43 AllVersions = Constraints{
44 raw: make(version.Constraints, 0),
45 }
46}
47
48// Allows returns true if the given version permitted by the receiving
49// constraints set.
50func (s Constraints) Allows(v Version) bool {
51 return s.raw.Check(v.raw)
52}
53
54// Append combines the receiving set with the given other set to produce
55// a set that is the intersection of both sets, which is to say that resulting
56// constraints contain only the versions that are members of both.
57func (s Constraints) Append(other Constraints) Constraints {
58 raw := make(version.Constraints, 0, len(s.raw)+len(other.raw))
59
60 // Since "raw" is a list of constraints that remove versions from the set,
61 // "Intersection" is implemented by concatenating together those lists,
62 // thus leaving behind only the versions not removed by either list.
63 raw = append(raw, s.raw...)
64 raw = append(raw, other.raw...)
65
66 // while the set is unordered, we sort these lexically for consistent output
67 sort.Slice(raw, func(i, j int) bool {
68 return raw[i].String() < raw[j].String()
69 })
70
71 return Constraints{raw}
72}
73
74// String returns a string representation of the set members as a set
75// of range constraints.
76func (s Constraints) String() string {
77 return s.raw.String()
78}
79
80// Unconstrained returns true if and only if the receiver is an empty
81// constraint set.
82func (s Constraints) Unconstrained() bool {
83 return len(s.raw) == 0
84}
diff --git a/vendor/github.com/hashicorp/terraform/terraform/context.go b/vendor/github.com/hashicorp/terraform/terraform/context.go
index 306128e..a814a85 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/context.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/context.go
@@ -57,12 +57,17 @@ type ContextOpts struct {
57 Parallelism int 57 Parallelism int
58 State *State 58 State *State
59 StateFutureAllowed bool 59 StateFutureAllowed bool
60 Providers map[string]ResourceProviderFactory 60 ProviderResolver ResourceProviderResolver
61 Provisioners map[string]ResourceProvisionerFactory 61 Provisioners map[string]ResourceProvisionerFactory
62 Shadow bool 62 Shadow bool
63 Targets []string 63 Targets []string
64 Variables map[string]interface{} 64 Variables map[string]interface{}
65 65
66 // If non-nil, will apply as additional constraints on the provider
67 // plugins that will be requested from the provider resolver.
68 ProviderSHA256s map[string][]byte
69 SkipProviderVerify bool
70
66 UIInput UIInput 71 UIInput UIInput
67} 72}
68 73
@@ -102,6 +107,7 @@ type Context struct {
102 l sync.Mutex // Lock acquired during any task 107 l sync.Mutex // Lock acquired during any task
103 parallelSem Semaphore 108 parallelSem Semaphore
104 providerInputConfig map[string]map[string]interface{} 109 providerInputConfig map[string]map[string]interface{}
110 providerSHA256s map[string][]byte
105 runLock sync.Mutex 111 runLock sync.Mutex
106 runCond *sync.Cond 112 runCond *sync.Cond
107 runContext context.Context 113 runContext context.Context
@@ -166,7 +172,6 @@ func NewContext(opts *ContextOpts) (*Context, error) {
166 // set by environment variables if necessary. This includes 172 // set by environment variables if necessary. This includes
167 // values taken from -var-file in addition. 173 // values taken from -var-file in addition.
168 variables := make(map[string]interface{}) 174 variables := make(map[string]interface{})
169
170 if opts.Module != nil { 175 if opts.Module != nil {
171 var err error 176 var err error
172 variables, err = Variables(opts.Module, opts.Variables) 177 variables, err = Variables(opts.Module, opts.Variables)
@@ -175,6 +180,23 @@ func NewContext(opts *ContextOpts) (*Context, error) {
175 } 180 }
176 } 181 }
177 182
183 // Bind available provider plugins to the constraints in config
184 var providers map[string]ResourceProviderFactory
185 if opts.ProviderResolver != nil {
186 var err error
187 deps := ModuleTreeDependencies(opts.Module, state)
188 reqd := deps.AllPluginRequirements()
189 if opts.ProviderSHA256s != nil && !opts.SkipProviderVerify {
190 reqd.LockExecutables(opts.ProviderSHA256s)
191 }
192 providers, err = resourceProviderFactories(opts.ProviderResolver, reqd)
193 if err != nil {
194 return nil, err
195 }
196 } else {
197 providers = make(map[string]ResourceProviderFactory)
198 }
199
178 diff := opts.Diff 200 diff := opts.Diff
179 if diff == nil { 201 if diff == nil {
180 diff = &Diff{} 202 diff = &Diff{}
@@ -182,7 +204,7 @@ func NewContext(opts *ContextOpts) (*Context, error) {
182 204
183 return &Context{ 205 return &Context{
184 components: &basicComponentFactory{ 206 components: &basicComponentFactory{
185 providers: opts.Providers, 207 providers: providers,
186 provisioners: opts.Provisioners, 208 provisioners: opts.Provisioners,
187 }, 209 },
188 destroy: opts.Destroy, 210 destroy: opts.Destroy,
@@ -198,6 +220,7 @@ func NewContext(opts *ContextOpts) (*Context, error) {
198 220
199 parallelSem: NewSemaphore(par), 221 parallelSem: NewSemaphore(par),
200 providerInputConfig: make(map[string]map[string]interface{}), 222 providerInputConfig: make(map[string]map[string]interface{}),
223 providerSHA256s: opts.ProviderSHA256s,
201 sh: sh, 224 sh: sh,
202 }, nil 225 }, nil
203} 226}
@@ -509,6 +532,9 @@ func (c *Context) Plan() (*Plan, error) {
509 Vars: c.variables, 532 Vars: c.variables,
510 State: c.state, 533 State: c.state,
511 Targets: c.targets, 534 Targets: c.targets,
535
536 TerraformVersion: VersionString(),
537 ProviderSHA256s: c.providerSHA256s,
512 } 538 }
513 539
514 var operation walkOperation 540 var operation walkOperation
diff --git a/vendor/github.com/hashicorp/terraform/terraform/diff.go b/vendor/github.com/hashicorp/terraform/terraform/diff.go
index a9fae6c..fd1687e 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/diff.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/diff.go
@@ -28,7 +28,7 @@ const (
28// multiVal matches the index key to a flatmapped set, list or map 28// multiVal matches the index key to a flatmapped set, list or map
29var multiVal = regexp.MustCompile(`\.(#|%)$`) 29var multiVal = regexp.MustCompile(`\.(#|%)$`)
30 30
31// Diff trackes the changes that are necessary to apply a configuration 31// Diff tracks the changes that are necessary to apply a configuration
32// to an existing infrastructure. 32// to an existing infrastructure.
33type Diff struct { 33type Diff struct {
34 // Modules contains all the modules that have a diff 34 // Modules contains all the modules that have a diff
@@ -370,7 +370,7 @@ type InstanceDiff struct {
370 370
371 // Meta is a simple K/V map that is stored in a diff and persisted to 371 // Meta is a simple K/V map that is stored in a diff and persisted to
372 // plans but otherwise is completely ignored by Terraform core. It is 372 // plans but otherwise is completely ignored by Terraform core. It is
373 // mean to be used for additional data a resource may want to pass through. 373 // meant to be used for additional data a resource may want to pass through.
374 // The value here must only contain Go primitives and collections. 374 // The value here must only contain Go primitives and collections.
375 Meta map[string]interface{} 375 Meta map[string]interface{}
376} 376}
@@ -551,7 +551,7 @@ func (d *InstanceDiff) SetDestroyDeposed(b bool) {
551} 551}
552 552
553// These methods are properly locked, for use outside other InstanceDiff 553// These methods are properly locked, for use outside other InstanceDiff
554// methods but everywhere else within in the terraform package. 554// methods but everywhere else within the terraform package.
555// TODO refactor the locking scheme 555// TODO refactor the locking scheme
556func (d *InstanceDiff) SetTainted(b bool) { 556func (d *InstanceDiff) SetTainted(b bool) {
557 d.mu.Lock() 557 d.mu.Lock()
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go b/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go
index 6f09526..c35f908 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/eval_diff.go
@@ -81,6 +81,12 @@ type EvalDiff struct {
81 // Resource is needed to fetch the ignore_changes list so we can 81 // Resource is needed to fetch the ignore_changes list so we can
82 // filter user-requested ignored attributes from the diff. 82 // filter user-requested ignored attributes from the diff.
83 Resource *config.Resource 83 Resource *config.Resource
84
85 // Stub is used to flag the generated InstanceDiff as a stub. This is used to
86 // ensure that the node exists to perform interpolations and generate
87 // computed paths off of, but not as an actual diff where resouces should be
88 // counted, and not as a diff that should be acted on.
89 Stub bool
84} 90}
85 91
86// TODO: test 92// TODO: test
@@ -90,11 +96,13 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
90 provider := *n.Provider 96 provider := *n.Provider
91 97
92 // Call pre-diff hook 98 // Call pre-diff hook
93 err := ctx.Hook(func(h Hook) (HookAction, error) { 99 if !n.Stub {
94 return h.PreDiff(n.Info, state) 100 err := ctx.Hook(func(h Hook) (HookAction, error) {
95 }) 101 return h.PreDiff(n.Info, state)
96 if err != nil { 102 })
97 return nil, err 103 if err != nil {
104 return nil, err
105 }
98 } 106 }
99 107
100 // The state for the diff must never be nil 108 // The state for the diff must never be nil
@@ -158,15 +166,19 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
158 } 166 }
159 167
160 // Call post-refresh hook 168 // Call post-refresh hook
161 err = ctx.Hook(func(h Hook) (HookAction, error) { 169 if !n.Stub {
162 return h.PostDiff(n.Info, diff) 170 err = ctx.Hook(func(h Hook) (HookAction, error) {
163 }) 171 return h.PostDiff(n.Info, diff)
164 if err != nil { 172 })
165 return nil, err 173 if err != nil {
174 return nil, err
175 }
166 } 176 }
167 177
168 // Update our output 178 // Update our output if we care
169 *n.OutputDiff = diff 179 if n.OutputDiff != nil {
180 *n.OutputDiff = diff
181 }
170 182
171 // Update the state if we care 183 // Update the state if we care
172 if n.OutputState != nil { 184 if n.OutputState != nil {
diff --git a/vendor/github.com/hashicorp/terraform/terraform/graph_builder_plan.go b/vendor/github.com/hashicorp/terraform/terraform/graph_builder_plan.go
index a6a3a90..4b29bbb 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/graph_builder_plan.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/graph_builder_plan.go
@@ -117,7 +117,15 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
117 &CountBoundaryTransformer{}, 117 &CountBoundaryTransformer{},
118 118
119 // Target 119 // Target
120 &TargetsTransformer{Targets: b.Targets}, 120 &TargetsTransformer{
121 Targets: b.Targets,
122
123 // Resource nodes from config have not yet been expanded for
124 // "count", so we must apply targeting without indices. Exact
125 // targeting will be dealt with later when these resources
126 // DynamicExpand.
127 IgnoreIndices: true,
128 },
121 129
122 // Close opened plugin connections 130 // Close opened plugin connections
123 &CloseProviderTransformer{}, 131 &CloseProviderTransformer{},
diff --git a/vendor/github.com/hashicorp/terraform/terraform/graph_builder_refresh.go b/vendor/github.com/hashicorp/terraform/terraform/graph_builder_refresh.go
index 0634f96..3d3e968 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/graph_builder_refresh.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/graph_builder_refresh.go
@@ -144,7 +144,15 @@ func (b *RefreshGraphBuilder) Steps() []GraphTransformer {
144 &ReferenceTransformer{}, 144 &ReferenceTransformer{},
145 145
146 // Target 146 // Target
147 &TargetsTransformer{Targets: b.Targets}, 147 &TargetsTransformer{
148 Targets: b.Targets,
149
150 // Resource nodes from config have not yet been expanded for
151 // "count", so we must apply targeting without indices. Exact
152 // targeting will be dealt with later when these resources
153 // DynamicExpand.
154 IgnoreIndices: true,
155 },
148 156
149 // Close opened plugin connections 157 // Close opened plugin connections
150 &CloseProviderTransformer{}, 158 &CloseProviderTransformer{},
diff --git a/vendor/github.com/hashicorp/terraform/terraform/interpolate.go b/vendor/github.com/hashicorp/terraform/terraform/interpolate.go
index 0def295..22ddce6 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/interpolate.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/interpolate.go
@@ -317,9 +317,13 @@ func (i *Interpolater) valueTerraformVar(
317 n string, 317 n string,
318 v *config.TerraformVariable, 318 v *config.TerraformVariable,
319 result map[string]ast.Variable) error { 319 result map[string]ast.Variable) error {
320 if v.Field != "env" { 320
321 // "env" is supported for backward compatibility, but it's deprecated and
322 // so we won't advertise it as being allowed in the error message. It will
323 // be removed in a future version of Terraform.
324 if v.Field != "workspace" && v.Field != "env" {
321 return fmt.Errorf( 325 return fmt.Errorf(
322 "%s: only supported key for 'terraform.X' interpolations is 'env'", n) 326 "%s: only supported key for 'terraform.X' interpolations is 'workspace'", n)
323 } 327 }
324 328
325 if i.Meta == nil { 329 if i.Meta == nil {
diff --git a/vendor/github.com/hashicorp/terraform/terraform/module_dependencies.go b/vendor/github.com/hashicorp/terraform/terraform/module_dependencies.go
new file mode 100644
index 0000000..b9f44a0
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/terraform/module_dependencies.go
@@ -0,0 +1,156 @@
1package terraform
2
3import (
4 "github.com/hashicorp/terraform/config"
5 "github.com/hashicorp/terraform/config/module"
6 "github.com/hashicorp/terraform/moduledeps"
7 "github.com/hashicorp/terraform/plugin/discovery"
8)
9
10// ModuleTreeDependencies returns the dependencies of the tree of modules
11// described by the given configuration tree and state.
12//
13// Both configuration and state are required because there can be resources
14// implied by instances in the state that no longer exist in config.
15//
16// This function will panic if any invalid version constraint strings are
17// present in the configuration. This is guaranteed not to happen for any
18// configuration that has passed a call to Config.Validate().
19func ModuleTreeDependencies(root *module.Tree, state *State) *moduledeps.Module {
20
21 // First we walk the configuration tree to build the overall structure
22 // and capture the explicit/implicit/inherited provider dependencies.
23 deps := moduleTreeConfigDependencies(root, nil)
24
25 // Next we walk over the resources in the state to catch any additional
26 // dependencies created by existing resources that are no longer in config.
27 // Most things we find in state will already be present in 'deps', but
28 // we're interested in the rare thing that isn't.
29 moduleTreeMergeStateDependencies(deps, state)
30
31 return deps
32}
33
34func moduleTreeConfigDependencies(root *module.Tree, inheritProviders map[string]*config.ProviderConfig) *moduledeps.Module {
35 if root == nil {
36 // If no config is provided, we'll make a synthetic root.
37 // This isn't necessarily correct if we're called with a nil that
38 // *isn't* at the root, but in practice that can never happen.
39 return &moduledeps.Module{
40 Name: "root",
41 }
42 }
43
44 ret := &moduledeps.Module{
45 Name: root.Name(),
46 }
47
48 cfg := root.Config()
49 providerConfigs := cfg.ProviderConfigsByFullName()
50
51 // Provider dependencies
52 {
53 providers := make(moduledeps.Providers, len(providerConfigs))
54
55 // Any providerConfigs elements are *explicit* provider dependencies,
56 // which is the only situation where the user might provide an actual
57 // version constraint. We'll take care of these first.
58 for fullName, pCfg := range providerConfigs {
59 inst := moduledeps.ProviderInstance(fullName)
60 versionSet := discovery.AllVersions
61 if pCfg.Version != "" {
62 versionSet = discovery.ConstraintStr(pCfg.Version).MustParse()
63 }
64 providers[inst] = moduledeps.ProviderDependency{
65 Constraints: versionSet,
66 Reason: moduledeps.ProviderDependencyExplicit,
67 }
68 }
69
70 // Each resource in the configuration creates an *implicit* provider
71 // dependency, though we'll only record it if there isn't already
72 // an explicit dependency on the same provider.
73 for _, rc := range cfg.Resources {
74 fullName := rc.ProviderFullName()
75 inst := moduledeps.ProviderInstance(fullName)
76 if _, exists := providers[inst]; exists {
77 // Explicit dependency already present
78 continue
79 }
80
81 reason := moduledeps.ProviderDependencyImplicit
82 if _, inherited := inheritProviders[fullName]; inherited {
83 reason = moduledeps.ProviderDependencyInherited
84 }
85
86 providers[inst] = moduledeps.ProviderDependency{
87 Constraints: discovery.AllVersions,
88 Reason: reason,
89 }
90 }
91
92 ret.Providers = providers
93 }
94
95 childInherit := make(map[string]*config.ProviderConfig)
96 for k, v := range inheritProviders {
97 childInherit[k] = v
98 }
99 for k, v := range providerConfigs {
100 childInherit[k] = v
101 }
102 for _, c := range root.Children() {
103 ret.Children = append(ret.Children, moduleTreeConfigDependencies(c, childInherit))
104 }
105
106 return ret
107}
108
109func moduleTreeMergeStateDependencies(root *moduledeps.Module, state *State) {
110 if state == nil {
111 return
112 }
113
114 findModule := func(path []string) *moduledeps.Module {
115 module := root
116 for _, name := range path[1:] { // skip initial "root"
117 var next *moduledeps.Module
118 for _, cm := range module.Children {
119 if cm.Name == name {
120 next = cm
121 break
122 }
123 }
124
125 if next == nil {
126 // If we didn't find a next node, we'll need to make one
127 next = &moduledeps.Module{
128 Name: name,
129 }
130 module.Children = append(module.Children, next)
131 }
132
133 module = next
134 }
135 return module
136 }
137
138 for _, ms := range state.Modules {
139 module := findModule(ms.Path)
140
141 for _, is := range ms.Resources {
142 fullName := config.ResourceProviderFullName(is.Type, is.Provider)
143 inst := moduledeps.ProviderInstance(fullName)
144 if _, exists := module.Providers[inst]; !exists {
145 if module.Providers == nil {
146 module.Providers = make(moduledeps.Providers)
147 }
148 module.Providers[inst] = moduledeps.ProviderDependency{
149 Constraints: discovery.AllVersions,
150 Reason: moduledeps.ProviderDependencyFromState,
151 }
152 }
153 }
154 }
155
156}
diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go
index 6ab9df7..cd4fe92 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go
@@ -45,13 +45,6 @@ func (n *NodeRefreshableManagedResource) DynamicExpand(ctx EvalContext) (*Graph,
45 Addr: n.ResourceAddr(), 45 Addr: n.ResourceAddr(),
46 }, 46 },
47 47
48 // Switch up any node missing state to a plannable resource. This helps
49 // catch cases where data sources depend on the counts from this resource
50 // during a scale out.
51 &ResourceRefreshPlannableTransformer{
52 State: state,
53 },
54
55 // Add the count orphans to make sure these resources are accounted for 48 // Add the count orphans to make sure these resources are accounted for
56 // during a scale in. 49 // during a scale in.
57 &OrphanResourceCountTransformer{ 50 &OrphanResourceCountTransformer{
@@ -100,6 +93,9 @@ func (n *NodeRefreshableManagedResourceInstance) EvalTree() EvalNode {
100 // Eval info is different depending on what kind of resource this is 93 // Eval info is different depending on what kind of resource this is
101 switch mode := n.Addr.Mode; mode { 94 switch mode := n.Addr.Mode; mode {
102 case config.ManagedResourceMode: 95 case config.ManagedResourceMode:
96 if n.ResourceState == nil {
97 return n.evalTreeManagedResourceNoState()
98 }
103 return n.evalTreeManagedResource() 99 return n.evalTreeManagedResource()
104 100
105 case config.DataResourceMode: 101 case config.DataResourceMode:
@@ -176,3 +172,88 @@ func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResource() EvalN
176 }, 172 },
177 } 173 }
178} 174}
175
176// evalTreeManagedResourceNoState produces an EvalSequence for refresh resource
177// nodes that don't have state attached. An example of where this functionality
178// is useful is when a resource that already exists in state is being scaled
179// out, ie: has its resource count increased. In this case, the scaled out node
180// needs to be available to other nodes (namely data sources) that may depend
181// on it for proper interpolation, or confusing "index out of range" errors can
182// occur.
183//
184// The steps in this sequence are very similar to the steps carried out in
185// plan, but nothing is done with the diff after it is created - it is dropped,
186// and its changes are not counted in the UI.
187func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResourceNoState() EvalNode {
188 // Declare a bunch of variables that are used for state during
189 // evaluation. Most of this are written to by-address below.
190 var provider ResourceProvider
191 var state *InstanceState
192 var resourceConfig *ResourceConfig
193
194 addr := n.NodeAbstractResource.Addr
195 stateID := addr.stateId()
196 info := &InstanceInfo{
197 Id: stateID,
198 Type: addr.Type,
199 ModulePath: normalizeModulePath(addr.Path),
200 }
201
202 // Build the resource for eval
203 resource := &Resource{
204 Name: addr.Name,
205 Type: addr.Type,
206 CountIndex: addr.Index,
207 }
208 if resource.CountIndex < 0 {
209 resource.CountIndex = 0
210 }
211
212 // Determine the dependencies for the state.
213 stateDeps := n.StateReferences()
214
215 return &EvalSequence{
216 Nodes: []EvalNode{
217 &EvalInterpolate{
218 Config: n.Config.RawConfig.Copy(),
219 Resource: resource,
220 Output: &resourceConfig,
221 },
222 &EvalGetProvider{
223 Name: n.ProvidedBy()[0],
224 Output: &provider,
225 },
226 // Re-run validation to catch any errors we missed, e.g. type
227 // mismatches on computed values.
228 &EvalValidateResource{
229 Provider: &provider,
230 Config: &resourceConfig,
231 ResourceName: n.Config.Name,
232 ResourceType: n.Config.Type,
233 ResourceMode: n.Config.Mode,
234 IgnoreWarnings: true,
235 },
236 &EvalReadState{
237 Name: stateID,
238 Output: &state,
239 },
240 &EvalDiff{
241 Name: stateID,
242 Info: info,
243 Config: &resourceConfig,
244 Resource: n.Config,
245 Provider: &provider,
246 State: &state,
247 OutputState: &state,
248 Stub: true,
249 },
250 &EvalWriteState{
251 Name: stateID,
252 ResourceType: n.Config.Type,
253 Provider: n.Config.Provider,
254 Dependencies: stateDeps,
255 State: &state,
256 },
257 },
258 }
259}
diff --git a/vendor/github.com/hashicorp/terraform/terraform/plan.go b/vendor/github.com/hashicorp/terraform/terraform/plan.go
index ea08845..51d6652 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/plan.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/plan.go
@@ -6,6 +6,7 @@ import (
6 "errors" 6 "errors"
7 "fmt" 7 "fmt"
8 "io" 8 "io"
9 "log"
9 "sync" 10 "sync"
10 11
11 "github.com/hashicorp/terraform/config/module" 12 "github.com/hashicorp/terraform/config/module"
@@ -31,6 +32,9 @@ type Plan struct {
31 Vars map[string]interface{} 32 Vars map[string]interface{}
32 Targets []string 33 Targets []string
33 34
35 TerraformVersion string
36 ProviderSHA256s map[string][]byte
37
34 // Backend is the backend that this plan should use and store data with. 38 // Backend is the backend that this plan should use and store data with.
35 Backend *BackendState 39 Backend *BackendState
36 40
@@ -40,19 +44,58 @@ type Plan struct {
40// Context returns a Context with the data encapsulated in this plan. 44// Context returns a Context with the data encapsulated in this plan.
41// 45//
42// The following fields in opts are overridden by the plan: Config, 46// The following fields in opts are overridden by the plan: Config,
43// Diff, State, Variables. 47// Diff, Variables.
48//
49// If State is not provided, it is set from the plan. If it _is_ provided,
50// it must be Equal to the state stored in plan, but may have a newer
51// serial.
44func (p *Plan) Context(opts *ContextOpts) (*Context, error) { 52func (p *Plan) Context(opts *ContextOpts) (*Context, error) {
53 var err error
54 opts, err = p.contextOpts(opts)
55 if err != nil {
56 return nil, err
57 }
58 return NewContext(opts)
59}
60
61// contextOpts mutates the given base ContextOpts in place to use input
62// objects obtained from the receiving plan.
63func (p *Plan) contextOpts(base *ContextOpts) (*ContextOpts, error) {
64 opts := base
65
45 opts.Diff = p.Diff 66 opts.Diff = p.Diff
46 opts.Module = p.Module 67 opts.Module = p.Module
47 opts.State = p.State
48 opts.Targets = p.Targets 68 opts.Targets = p.Targets
69 opts.ProviderSHA256s = p.ProviderSHA256s
70
71 if opts.State == nil {
72 opts.State = p.State
73 } else if !opts.State.Equal(p.State) {
74 // Even if we're overriding the state, it should be logically equal
75 // to what's in plan. The only valid change to have made by the time
76 // we get here is to have incremented the serial.
77 //
78 // Due to the fact that serialization may change the representation of
79 // the state, there is little chance that these aren't actually equal.
80 // Log the error condition for reference, but continue with the state
81 // we have.
82 log.Println("[WARNING] Plan state and ContextOpts state are not equal")
83 }
84
85 thisVersion := VersionString()
86 if p.TerraformVersion != "" && p.TerraformVersion != thisVersion {
87 return nil, fmt.Errorf(
88 "plan was created with a different version of Terraform (created with %s, but running %s)",
89 p.TerraformVersion, thisVersion,
90 )
91 }
49 92
50 opts.Variables = make(map[string]interface{}) 93 opts.Variables = make(map[string]interface{})
51 for k, v := range p.Vars { 94 for k, v := range p.Vars {
52 opts.Variables[k] = v 95 opts.Variables[k] = v
53 } 96 }
54 97
55 return NewContext(opts) 98 return opts, nil
56} 99}
57 100
58func (p *Plan) String() string { 101func (p *Plan) String() string {
@@ -86,7 +129,7 @@ func (p *Plan) init() {
86// the ability in the future to change the file format if we want for any 129// the ability in the future to change the file format if we want for any
87// reason. 130// reason.
88const planFormatMagic = "tfplan" 131const planFormatMagic = "tfplan"
89const planFormatVersion byte = 1 132const planFormatVersion byte = 2
90 133
91// ReadPlan reads a plan structure out of a reader in the format that 134// ReadPlan reads a plan structure out of a reader in the format that
92// was written by WritePlan. 135// was written by WritePlan.
diff --git a/vendor/github.com/hashicorp/terraform/terraform/resource_address.go b/vendor/github.com/hashicorp/terraform/terraform/resource_address.go
index a8a0c95..8badca8 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/resource_address.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/resource_address.go
@@ -8,6 +8,7 @@ import (
8 "strings" 8 "strings"
9 9
10 "github.com/hashicorp/terraform/config" 10 "github.com/hashicorp/terraform/config"
11 "github.com/hashicorp/terraform/config/module"
11) 12)
12 13
13// ResourceAddress is a way of identifying an individual resource (or, 14// ResourceAddress is a way of identifying an individual resource (or,
@@ -89,6 +90,51 @@ func (r *ResourceAddress) String() string {
89 return strings.Join(result, ".") 90 return strings.Join(result, ".")
90} 91}
91 92
93// HasResourceSpec returns true if the address has a resource spec, as
94// defined in the documentation:
95// https://www.terraform.io/docs/internals/resource-addressing.html
96// In particular, this returns false if the address contains only
97// a module path, thus addressing the entire module.
98func (r *ResourceAddress) HasResourceSpec() bool {
99 return r.Type != "" && r.Name != ""
100}
101
102// WholeModuleAddress returns the resource address that refers to all
103// resources in the same module as the receiver address.
104func (r *ResourceAddress) WholeModuleAddress() *ResourceAddress {
105 return &ResourceAddress{
106 Path: r.Path,
107 Index: -1,
108 InstanceTypeSet: false,
109 }
110}
111
112// MatchesConfig returns true if the receiver matches the given
113// configuration resource within the given configuration module.
114//
115// Since resource configuration blocks represent all of the instances of
116// a multi-instance resource, the index of the address (if any) is not
117// considered.
118func (r *ResourceAddress) MatchesConfig(mod *module.Tree, rc *config.Resource) bool {
119 if r.HasResourceSpec() {
120 if r.Mode != rc.Mode || r.Type != rc.Type || r.Name != rc.Name {
121 return false
122 }
123 }
124
125 addrPath := r.Path
126 cfgPath := mod.Path()
127
128 // normalize
129 if len(addrPath) == 0 {
130 addrPath = nil
131 }
132 if len(cfgPath) == 0 {
133 cfgPath = nil
134 }
135 return reflect.DeepEqual(addrPath, cfgPath)
136}
137
92// stateId returns the ID that this resource should be entered with 138// stateId returns the ID that this resource should be entered with
93// in the state. This is also used for diffs. In the future, we'd like to 139// in the state. This is also used for diffs. In the future, we'd like to
94// move away from this string field so I don't export this. 140// move away from this string field so I don't export this.
@@ -185,7 +231,10 @@ func ParseResourceAddress(s string) (*ResourceAddress, error) {
185 231
186 // not allowed to say "data." without a type following 232 // not allowed to say "data." without a type following
187 if mode == config.DataResourceMode && matches["type"] == "" { 233 if mode == config.DataResourceMode && matches["type"] == "" {
188 return nil, fmt.Errorf("must target specific data instance") 234 return nil, fmt.Errorf(
235 "invalid resource address %q: must target specific data instance",
236 s,
237 )
189 } 238 }
190 239
191 return &ResourceAddress{ 240 return &ResourceAddress{
@@ -199,6 +248,75 @@ func ParseResourceAddress(s string) (*ResourceAddress, error) {
199 }, nil 248 }, nil
200} 249}
201 250
251// ParseResourceAddressForInstanceDiff creates a ResourceAddress for a
252// resource name as described in a module diff.
253//
254// For historical reasons a different addressing format is used in this
255// context. The internal format should not be shown in the UI and instead
256// this function should be used to translate to a ResourceAddress and
257// then, where appropriate, use the String method to produce a canonical
258// resource address string for display in the UI.
259//
260// The given path slice must be empty (or nil) for the root module, and
261// otherwise consist of a sequence of module names traversing down into
262// the module tree. If a non-nil path is provided, the caller must not
263// modify its underlying array after passing it to this function.
264func ParseResourceAddressForInstanceDiff(path []string, key string) (*ResourceAddress, error) {
265 addr, err := parseResourceAddressInternal(key)
266 if err != nil {
267 return nil, err
268 }
269 addr.Path = path
270 return addr, nil
271}
272
273// Contains returns true if and only if the given node is contained within
274// the receiver.
275//
276// Containment is defined in terms of the module and resource heirarchy:
277// a resource is contained within its module and any ancestor modules,
278// an indexed resource instance is contained with the unindexed resource, etc.
279func (addr *ResourceAddress) Contains(other *ResourceAddress) bool {
280 ourPath := addr.Path
281 givenPath := other.Path
282 if len(givenPath) < len(ourPath) {
283 return false
284 }
285 for i := range ourPath {
286 if ourPath[i] != givenPath[i] {
287 return false
288 }
289 }
290
291 // If the receiver is a whole-module address then the path prefix
292 // matching is all we need.
293 if !addr.HasResourceSpec() {
294 return true
295 }
296
297 if addr.Type != other.Type || addr.Name != other.Name || addr.Mode != other.Mode {
298 return false
299 }
300
301 if addr.Index != -1 && addr.Index != other.Index {
302 return false
303 }
304
305 if addr.InstanceTypeSet && (addr.InstanceTypeSet != other.InstanceTypeSet || addr.InstanceType != other.InstanceType) {
306 return false
307 }
308
309 return true
310}
311
312// Equals returns true if the receiver matches the given address.
313//
314// The name of this method is a misnomer, since it doesn't test for exact
315// equality. Instead, it tests that the _specified_ parts of each
316// address match, treating any unspecified parts as wildcards.
317//
318// See also Contains, which takes a more heirarchical approach to comparing
319// addresses.
202func (addr *ResourceAddress) Equals(raw interface{}) bool { 320func (addr *ResourceAddress) Equals(raw interface{}) bool {
203 other, ok := raw.(*ResourceAddress) 321 other, ok := raw.(*ResourceAddress)
204 if !ok { 322 if !ok {
@@ -233,6 +351,58 @@ func (addr *ResourceAddress) Equals(raw interface{}) bool {
233 modeMatch 351 modeMatch
234} 352}
235 353
354// Less returns true if and only if the receiver should be sorted before
355// the given address when presenting a list of resource addresses to
356// an end-user.
357//
358// This sort uses lexicographic sorting for most components, but uses
359// numeric sort for indices, thus causing index 10 to sort after
360// index 9, rather than after index 1.
361func (addr *ResourceAddress) Less(other *ResourceAddress) bool {
362
363 switch {
364
365 case len(addr.Path) < len(other.Path):
366 return true
367
368 case !reflect.DeepEqual(addr.Path, other.Path):
369 // If the two paths are the same length but don't match, we'll just
370 // cheat and compare the string forms since it's easier than
371 // comparing all of the path segments in turn.
372 addrStr := addr.String()
373 otherStr := other.String()
374 return addrStr < otherStr
375
376 case addr.Mode == config.DataResourceMode && other.Mode != config.DataResourceMode:
377 return true
378
379 case addr.Type < other.Type:
380 return true
381
382 case addr.Name < other.Name:
383 return true
384
385 case addr.Index < other.Index:
386 // Since "Index" is -1 for an un-indexed address, this also conveniently
387 // sorts unindexed addresses before indexed ones, should they both
388 // appear for some reason.
389 return true
390
391 case other.InstanceTypeSet && !addr.InstanceTypeSet:
392 return true
393
394 case addr.InstanceType < other.InstanceType:
395 // InstanceType is actually an enum, so this is just an arbitrary
396 // sort based on the enum numeric values, and thus not particularly
397 // meaningful.
398 return true
399
400 default:
401 return false
402
403 }
404}
405
236func ParseResourceIndex(s string) (int, error) { 406func ParseResourceIndex(s string) (int, error) {
237 if s == "" { 407 if s == "" {
238 return -1, nil 408 return -1, nil
@@ -275,7 +445,7 @@ func tokenizeResourceAddress(s string) (map[string]string, error) {
275 // string "aws_instance.web.tainted[1]" 445 // string "aws_instance.web.tainted[1]"
276 re := regexp.MustCompile(`\A` + 446 re := regexp.MustCompile(`\A` +
277 // "module.foo.module.bar" (optional) 447 // "module.foo.module.bar" (optional)
278 `(?P<path>(?:module\.[^.]+\.?)*)` + 448 `(?P<path>(?:module\.(?P<module_name>[^.]+)\.?)*)` +
279 // possibly "data.", if targeting is a data resource 449 // possibly "data.", if targeting is a data resource
280 `(?P<data_prefix>(?:data\.)?)` + 450 `(?P<data_prefix>(?:data\.)?)` +
281 // "aws_instance.web" (optional when module path specified) 451 // "aws_instance.web" (optional when module path specified)
@@ -289,7 +459,7 @@ func tokenizeResourceAddress(s string) (map[string]string, error) {
289 groupNames := re.SubexpNames() 459 groupNames := re.SubexpNames()
290 rawMatches := re.FindAllStringSubmatch(s, -1) 460 rawMatches := re.FindAllStringSubmatch(s, -1)
291 if len(rawMatches) != 1 { 461 if len(rawMatches) != 1 {
292 return nil, fmt.Errorf("Problem parsing address: %q", s) 462 return nil, fmt.Errorf("invalid resource address %q", s)
293 } 463 }
294 464
295 matches := make(map[string]string) 465 matches := make(map[string]string)
diff --git a/vendor/github.com/hashicorp/terraform/terraform/resource_provider.go b/vendor/github.com/hashicorp/terraform/terraform/resource_provider.go
index 1a68c86..7d78f67 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/resource_provider.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/resource_provider.go
@@ -1,5 +1,12 @@
1package terraform 1package terraform
2 2
3import (
4 "fmt"
5
6 multierror "github.com/hashicorp/go-multierror"
7 "github.com/hashicorp/terraform/plugin/discovery"
8)
9
3// ResourceProvider is an interface that must be implemented by any 10// ResourceProvider is an interface that must be implemented by any
4// resource provider: the thing that creates and manages the resources in 11// resource provider: the thing that creates and manages the resources in
5// a Terraform configuration. 12// a Terraform configuration.
@@ -154,6 +161,18 @@ type ResourceProvider interface {
154 ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error) 161 ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error)
155} 162}
156 163
164// ResourceProviderError may be returned when creating a Context if the
165// required providers cannot be satisfied. This error can then be used to
166// format a more useful message for the user.
167type ResourceProviderError struct {
168 Errors []error
169}
170
171func (e *ResourceProviderError) Error() string {
172 // use multierror to format the default output
173 return multierror.Append(nil, e.Errors...).Error()
174}
175
157// ResourceProviderCloser is an interface that providers that can close 176// ResourceProviderCloser is an interface that providers that can close
158// connections that aren't needed anymore must implement. 177// connections that aren't needed anymore must implement.
159type ResourceProviderCloser interface { 178type ResourceProviderCloser interface {
@@ -171,6 +190,50 @@ type DataSource struct {
171 Name string 190 Name string
172} 191}
173 192
193// ResourceProviderResolver is an interface implemented by objects that are
194// able to resolve a given set of resource provider version constraints
195// into ResourceProviderFactory callbacks.
196type ResourceProviderResolver interface {
197 // Given a constraint map, return a ResourceProviderFactory for each
198 // requested provider. If some or all of the constraints cannot be
199 // satisfied, return a non-nil slice of errors describing the problems.
200 ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error)
201}
202
203// ResourceProviderResolverFunc wraps a callback function and turns it into
204// a ResourceProviderResolver implementation, for convenience in situations
205// where a function and its associated closure are sufficient as a resolver
206// implementation.
207type ResourceProviderResolverFunc func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error)
208
209// ResolveProviders implements ResourceProviderResolver by calling the
210// wrapped function.
211func (f ResourceProviderResolverFunc) ResolveProviders(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) {
212 return f(reqd)
213}
214
215// ResourceProviderResolverFixed returns a ResourceProviderResolver that
216// has a fixed set of provider factories provided by the caller. The returned
217// resolver ignores version constraints entirely and just returns the given
218// factory for each requested provider name.
219//
220// This function is primarily used in tests, to provide mock providers or
221// in-process providers under test.
222func ResourceProviderResolverFixed(factories map[string]ResourceProviderFactory) ResourceProviderResolver {
223 return ResourceProviderResolverFunc(func(reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, []error) {
224 ret := make(map[string]ResourceProviderFactory, len(reqd))
225 var errs []error
226 for name := range reqd {
227 if factory, exists := factories[name]; exists {
228 ret[name] = factory
229 } else {
230 errs = append(errs, fmt.Errorf("provider %q is not available", name))
231 }
232 }
233 return ret, errs
234 })
235}
236
174// ResourceProviderFactory is a function type that creates a new instance 237// ResourceProviderFactory is a function type that creates a new instance
175// of a resource provider. 238// of a resource provider.
176type ResourceProviderFactory func() (ResourceProvider, error) 239type ResourceProviderFactory func() (ResourceProvider, error)
@@ -202,3 +265,21 @@ func ProviderHasDataSource(p ResourceProvider, n string) bool {
202 265
203 return false 266 return false
204} 267}
268
269// resourceProviderFactories matches available plugins to the given version
270// requirements to produce a map of compatible provider plugins if possible,
271// or an error if the currently-available plugins are insufficient.
272//
273// This should be called only with configurations that have passed calls
274// to config.Validate(), which ensures that all of the given version
275// constraints are valid. It will panic if any invalid constraints are present.
276func resourceProviderFactories(resolver ResourceProviderResolver, reqd discovery.PluginRequirements) (map[string]ResourceProviderFactory, error) {
277 ret, errs := resolver.ResolveProviders(reqd)
278 if errs != nil {
279 return nil, &ResourceProviderError{
280 Errors: errs,
281 }
282 }
283
284 return ret, nil
285}
diff --git a/vendor/github.com/hashicorp/terraform/terraform/state.go b/vendor/github.com/hashicorp/terraform/terraform/state.go
index 074b682..0c46194 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/state.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/state.go
@@ -533,6 +533,43 @@ func (s *State) equal(other *State) bool {
533 return true 533 return true
534} 534}
535 535
536// MarshalEqual is similar to Equal but provides a stronger definition of
537// "equal", where two states are equal if and only if their serialized form
538// is byte-for-byte identical.
539//
540// This is primarily useful for callers that are trying to save snapshots
541// of state to persistent storage, allowing them to detect when a new
542// snapshot must be taken.
543//
544// Note that the serial number and lineage are included in the serialized form,
545// so it's the caller's responsibility to properly manage these attributes
546// so that this method is only called on two states that have the same
547// serial and lineage, unless detecting such differences is desired.
548func (s *State) MarshalEqual(other *State) bool {
549 if s == nil && other == nil {
550 return true
551 } else if s == nil || other == nil {
552 return false
553 }
554
555 recvBuf := &bytes.Buffer{}
556 otherBuf := &bytes.Buffer{}
557
558 err := WriteState(s, recvBuf)
559 if err != nil {
560 // should never happen, since we're writing to a buffer
561 panic(err)
562 }
563
564 err = WriteState(other, otherBuf)
565 if err != nil {
566 // should never happen, since we're writing to a buffer
567 panic(err)
568 }
569
570 return bytes.Equal(recvBuf.Bytes(), otherBuf.Bytes())
571}
572
536type StateAgeComparison int 573type StateAgeComparison int
537 574
538const ( 575const (
@@ -603,6 +640,10 @@ func (s *State) SameLineage(other *State) bool {
603// DeepCopy performs a deep copy of the state structure and returns 640// DeepCopy performs a deep copy of the state structure and returns
604// a new structure. 641// a new structure.
605func (s *State) DeepCopy() *State { 642func (s *State) DeepCopy() *State {
643 if s == nil {
644 return nil
645 }
646
606 copy, err := copystructure.Config{Lock: true}.Copy(s) 647 copy, err := copystructure.Config{Lock: true}.Copy(s)
607 if err != nil { 648 if err != nil {
608 panic(err) 649 panic(err)
@@ -611,30 +652,6 @@ func (s *State) DeepCopy() *State {
611 return copy.(*State) 652 return copy.(*State)
612} 653}
613 654
614// IncrementSerialMaybe increments the serial number of this state
615// if it different from the other state.
616func (s *State) IncrementSerialMaybe(other *State) {
617 if s == nil {
618 return
619 }
620 if other == nil {
621 return
622 }
623 s.Lock()
624 defer s.Unlock()
625
626 if s.Serial > other.Serial {
627 return
628 }
629 if other.TFVersion != s.TFVersion || !s.equal(other) {
630 if other.Serial > s.Serial {
631 s.Serial = other.Serial
632 }
633
634 s.Serial++
635 }
636}
637
638// FromFutureTerraform checks if this state was written by a Terraform 655// FromFutureTerraform checks if this state was written by a Terraform
639// version from the future. 656// version from the future.
640func (s *State) FromFutureTerraform() bool { 657func (s *State) FromFutureTerraform() bool {
@@ -660,6 +677,7 @@ func (s *State) init() {
660 if s.Version == 0 { 677 if s.Version == 0 {
661 s.Version = StateVersion 678 s.Version = StateVersion
662 } 679 }
680
663 if s.moduleByPath(rootModulePath) == nil { 681 if s.moduleByPath(rootModulePath) == nil {
664 s.addModule(rootModulePath) 682 s.addModule(rootModulePath)
665 } 683 }
diff --git a/vendor/github.com/hashicorp/terraform/terraform/test_failure b/vendor/github.com/hashicorp/terraform/terraform/test_failure
new file mode 100644
index 0000000..5d3ad1a
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/terraform/test_failure
@@ -0,0 +1,9 @@
1--- FAIL: TestContext2Plan_moduleProviderInherit (0.01s)
2 context_plan_test.go:552: bad: []string{"child"}
3map[string]dag.Vertex{}
4"module.middle.null"
5map[string]dag.Vertex{}
6"module.middle.module.inner.null"
7map[string]dag.Vertex{}
8"aws"
9FAIL
diff --git a/vendor/github.com/hashicorp/terraform/terraform/transform_resource_refresh_plannable.go b/vendor/github.com/hashicorp/terraform/terraform/transform_resource_refresh_plannable.go
deleted file mode 100644
index 35358a3..0000000
--- a/vendor/github.com/hashicorp/terraform/terraform/transform_resource_refresh_plannable.go
+++ /dev/null
@@ -1,55 +0,0 @@
1package terraform
2
3import (
4 "fmt"
5 "log"
6)
7
8// ResourceRefreshPlannableTransformer is a GraphTransformer that replaces any
9// nodes that don't have state yet exist in config with
10// NodePlannableResourceInstance.
11//
12// This transformer is used when expanding count on managed resource nodes
13// during the refresh phase to ensure that data sources that have
14// interpolations that depend on resources existing in the graph can be walked
15// properly.
16type ResourceRefreshPlannableTransformer struct {
17 // The full global state.
18 State *State
19}
20
21// Transform implements GraphTransformer for
22// ResourceRefreshPlannableTransformer.
23func (t *ResourceRefreshPlannableTransformer) Transform(g *Graph) error {
24nextVertex:
25 for _, v := range g.Vertices() {
26 addr := v.(*NodeRefreshableManagedResourceInstance).Addr
27
28 // Find the state for this address, if there is one
29 filter := &StateFilter{State: t.State}
30 results, err := filter.Filter(addr.String())
31 if err != nil {
32 return err
33 }
34
35 // Check to see if we have a state for this resource. If we do, skip this
36 // node.
37 for _, result := range results {
38 if _, ok := result.Value.(*ResourceState); ok {
39 continue nextVertex
40 }
41 }
42 // If we don't, convert this resource to a NodePlannableResourceInstance node
43 // with all of the data we need to make it happen.
44 log.Printf("[TRACE] No state for %s, converting to NodePlannableResourceInstance", addr.String())
45 new := &NodePlannableResourceInstance{
46 NodeAbstractResource: v.(*NodeRefreshableManagedResourceInstance).NodeAbstractResource,
47 }
48 // Replace the node in the graph
49 if !g.Replace(v, new) {
50 return fmt.Errorf("ResourceRefreshPlannableTransformer: Could not replace node %#v with %#v", v, new)
51 }
52 }
53
54 return nil
55}
diff --git a/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go b/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go
index 125f9e3..4f117b4 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go
@@ -41,6 +41,12 @@ type TargetsTransformer struct {
41 // that already have the targets parsed 41 // that already have the targets parsed
42 ParsedTargets []ResourceAddress 42 ParsedTargets []ResourceAddress
43 43
44 // If set, the index portions of resource addresses will be ignored
45 // for comparison. This is used when transforming a graph where
46 // counted resources have not yet been expanded, since otherwise
47 // the unexpanded nodes (which never have indices) would not match.
48 IgnoreIndices bool
49
44 // Set to true when we're in a `terraform destroy` or a 50 // Set to true when we're in a `terraform destroy` or a
45 // `terraform plan -destroy` 51 // `terraform plan -destroy`
46 Destroy bool 52 Destroy bool
@@ -199,7 +205,12 @@ func (t *TargetsTransformer) nodeIsTarget(
199 205
200 addr := r.ResourceAddr() 206 addr := r.ResourceAddr()
201 for _, targetAddr := range addrs { 207 for _, targetAddr := range addrs {
202 if targetAddr.Equals(addr) { 208 if t.IgnoreIndices {
209 // targetAddr is not a pointer, so we can safely mutate it without
210 // interfering with references elsewhere.
211 targetAddr.Index = -1
212 }
213 if targetAddr.Contains(addr) {
203 return true 214 return true
204 } 215 }
205 } 216 }
diff --git a/vendor/github.com/hashicorp/terraform/terraform/util.go b/vendor/github.com/hashicorp/terraform/terraform/util.go
index f41f0d7..752241a 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/util.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/util.go
@@ -2,7 +2,8 @@ package terraform
2 2
3import ( 3import (
4 "sort" 4 "sort"
5 "strings" 5
6 "github.com/hashicorp/terraform/config"
6) 7)
7 8
8// Semaphore is a wrapper around a channel to provide 9// Semaphore is a wrapper around a channel to provide
@@ -47,21 +48,8 @@ func (s Semaphore) Release() {
47 } 48 }
48} 49}
49 50
50// resourceProvider returns the provider name for the given type. 51func resourceProvider(resourceType, explicitProvider string) string {
51func resourceProvider(t, alias string) string { 52 return config.ResourceProviderFullName(resourceType, explicitProvider)
52 if alias != "" {
53 return alias
54 }
55
56 idx := strings.IndexRune(t, '_')
57 if idx == -1 {
58 // If no underscores, the resource name is assumed to be
59 // also the provider name, e.g. if the provider exposes
60 // only a single resource of each type.
61 return t
62 }
63
64 return t[:idx]
65} 53}
66 54
67// strSliceContains checks if a given string is contained in a slice 55// strSliceContains checks if a given string is contained in a slice
diff --git a/vendor/github.com/hashicorp/terraform/terraform/version.go b/vendor/github.com/hashicorp/terraform/terraform/version.go
index cdfb8fb..d61b11e 100644
--- a/vendor/github.com/hashicorp/terraform/terraform/version.go
+++ b/vendor/github.com/hashicorp/terraform/terraform/version.go
@@ -7,12 +7,12 @@ import (
7) 7)
8 8
9// The main version number that is being run at the moment. 9// The main version number that is being run at the moment.
10const Version = "0.9.8" 10const Version = "0.10.0"
11 11
12// A pre-release marker for the version. If this is "" (empty string) 12// A pre-release marker for the version. If this is "" (empty string)
13// then it means that it is a final release. Otherwise, this is a pre-release 13// then it means that it is a final release. Otherwise, this is a pre-release
14// such as "dev" (in development), "beta", "rc1", etc. 14// such as "dev" (in development), "beta", "rc1", etc.
15var VersionPrerelease = "" 15var VersionPrerelease = "dev"
16 16
17// SemVersion is an instance of version.Version. This has the secondary 17// SemVersion is an instance of version.Version. This has the secondary
18// benefit of verifying during tests and init time that our version is a 18// benefit of verifying during tests and init time that our version is a