aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/helper
diff options
context:
space:
mode:
authorappilon <apilon@hashicorp.com>2019-02-27 16:43:31 -0500
committerGitHub <noreply@github.com>2019-02-27 16:43:31 -0500
commit844b5a68d8af4791755b8f0ad293cc99f5959183 (patch)
tree255c250a5c9d4801c74092d33b7337d8c14438ff /vendor/github.com/hashicorp/terraform/helper
parent303b299eeb6b06e939e35905e4b34cb410dd9dc3 (diff)
parent15c0b25d011f37e7c20aeca9eaf461f78285b8d9 (diff)
downloadterraform-provider-statuscake-844b5a68d8af4791755b8f0ad293cc99f5959183.tar.gz
terraform-provider-statuscake-844b5a68d8af4791755b8f0ad293cc99f5959183.tar.zst
terraform-provider-statuscake-844b5a68d8af4791755b8f0ad293cc99f5959183.zip
Merge pull request #27 from terraform-providers/go-modules-2019-02-22
[MODULES] Switch to Go Modules
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/helper')
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/experiment/experiment.go154
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/experiment/id.go34
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/hashcode/hashcode.go13
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/logging/logging.go8
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/logging/transport.go21
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/resource/id.go5
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/resource/state.go2
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/resource/testing.go348
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/resource/testing_config.go41
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/resource/testing_import_state.go15
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/resource/wait.go2
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/backend.go2
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/core_schema.go155
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/data_source_resource_shim.go2
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/field_reader.go11
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/field_reader_config.go2
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/field_reader_diff.go43
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/field_reader_map.go2
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/field_writer_map.go32
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/getsource_string.go6
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/provider.go40
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go4
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/resource.go98
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/resource_data.go39
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/resource_diff.go559
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/schema.go252
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/set.go31
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/testing.go4
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/schema/valuetype_string.go4
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/shadow/closer.go83
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/shadow/compared_value.go128
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/shadow/keyed_value.go151
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/shadow/ordered_value.go66
-rw-r--r--vendor/github.com/hashicorp/terraform/helper/shadow/value.go87
34 files changed, 1529 insertions, 915 deletions
diff --git a/vendor/github.com/hashicorp/terraform/helper/experiment/experiment.go b/vendor/github.com/hashicorp/terraform/helper/experiment/experiment.go
deleted file mode 100644
index 18b8837..0000000
--- a/vendor/github.com/hashicorp/terraform/helper/experiment/experiment.go
+++ /dev/null
@@ -1,154 +0,0 @@
1// experiment package contains helper functions for tracking experimental
2// features throughout Terraform.
3//
4// This package should be used for creating, enabling, querying, and deleting
5// experimental features. By unifying all of that onto a single interface,
6// we can have the Go compiler help us by enforcing every place we touch
7// an experimental feature.
8//
9// To create a new experiment:
10//
11// 1. Add the experiment to the global vars list below, prefixed with X_
12//
13// 2. Add the experiment variable to the All listin the init() function
14//
15// 3. Use it!
16//
17// To remove an experiment:
18//
19// 1. Delete the experiment global var.
20//
21// 2. Try to compile and fix all the places where the var was referenced.
22//
23// To use an experiment:
24//
25// 1. Use Flag() if you want the experiment to be available from the CLI.
26//
27// 2. Use Enabled() to check whether it is enabled.
28//
29// As a general user:
30//
31// 1. The `-Xexperiment-name` flag
32// 2. The `TF_X_<experiment-name>` env var.
33// 3. The `TF_X_FORCE` env var can be set to force an experimental feature
34// without human verifications.
35//
36package experiment
37
38import (
39 "flag"
40 "fmt"
41 "os"
42 "strconv"
43 "strings"
44 "sync"
45)
46
47// The experiments that are available are listed below. Any package in
48// Terraform defining an experiment should define the experiments below.
49// By keeping them all within the experiment package we force a single point
50// of definition and use. This allows the compiler to enforce references
51// so it becomes easy to remove the features.
52var (
53 // Shadow graph. This is already on by default. Disabling it will be
54 // allowed for awhile in order for it to not block operations.
55 X_shadow = newBasicID("shadow", "SHADOW", false)
56)
57
58// Global variables this package uses because we are a package
59// with global state.
60var (
61 // all is the list of all experiements. Do not modify this.
62 All []ID
63
64 // enabled keeps track of what flags have been enabled
65 enabled map[string]bool
66 enabledLock sync.Mutex
67
68 // Hidden "experiment" that forces all others to be on without verification
69 x_force = newBasicID("force", "FORCE", false)
70)
71
72func init() {
73 // The list of all experiments, update this when an experiment is added.
74 All = []ID{
75 X_shadow,
76 x_force,
77 }
78
79 // Load
80 reload()
81}
82
83// reload is used by tests to reload the global state. This is called by
84// init publicly.
85func reload() {
86 // Initialize
87 enabledLock.Lock()
88 enabled = make(map[string]bool)
89 enabledLock.Unlock()
90
91 // Set defaults and check env vars
92 for _, id := range All {
93 // Get the default value
94 def := id.Default()
95
96 // If we set it in the env var, default it to true
97 key := fmt.Sprintf("TF_X_%s", strings.ToUpper(id.Env()))
98 if v := os.Getenv(key); v != "" {
99 def = v != "0"
100 }
101
102 // Set the default
103 SetEnabled(id, def)
104 }
105}
106
107// Enabled returns whether an experiment has been enabled or not.
108func Enabled(id ID) bool {
109 enabledLock.Lock()
110 defer enabledLock.Unlock()
111 return enabled[id.Flag()]
112}
113
114// SetEnabled sets an experiment to enabled/disabled. Please check with
115// the experiment docs for when calling this actually affects the experiment.
116func SetEnabled(id ID, v bool) {
117 enabledLock.Lock()
118 defer enabledLock.Unlock()
119 enabled[id.Flag()] = v
120}
121
122// Force returns true if the -Xforce of TF_X_FORCE flag is present, which
123// advises users of this package to not verify with the user that they want
124// experimental behavior and to just continue with it.
125func Force() bool {
126 return Enabled(x_force)
127}
128
129// Flag configures the given FlagSet with the flags to configure
130// all active experiments.
131func Flag(fs *flag.FlagSet) {
132 for _, id := range All {
133 desc := id.Flag()
134 key := fmt.Sprintf("X%s", id.Flag())
135 fs.Var(&idValue{X: id}, key, desc)
136 }
137}
138
139// idValue implements flag.Value for setting the enabled/disabled state
140// of an experiment from the CLI.
141type idValue struct {
142 X ID
143}
144
145func (v *idValue) IsBoolFlag() bool { return true }
146func (v *idValue) String() string { return strconv.FormatBool(Enabled(v.X)) }
147func (v *idValue) Set(raw string) error {
148 b, err := strconv.ParseBool(raw)
149 if err == nil {
150 SetEnabled(v.X, b)
151 }
152
153 return err
154}
diff --git a/vendor/github.com/hashicorp/terraform/helper/experiment/id.go b/vendor/github.com/hashicorp/terraform/helper/experiment/id.go
deleted file mode 100644
index 8e2f707..0000000
--- a/vendor/github.com/hashicorp/terraform/helper/experiment/id.go
+++ /dev/null
@@ -1,34 +0,0 @@
1package experiment
2
3// ID represents an experimental feature.
4//
5// The global vars defined on this package should be used as ID values.
6// This interface is purposely not implement-able outside of this package
7// so that we can rely on the Go compiler to enforce all experiment references.
8type ID interface {
9 Env() string
10 Flag() string
11 Default() bool
12
13 unexported() // So the ID can't be implemented externally.
14}
15
16// basicID implements ID.
17type basicID struct {
18 EnvValue string
19 FlagValue string
20 DefaultValue bool
21}
22
23func newBasicID(flag, env string, def bool) ID {
24 return &basicID{
25 EnvValue: env,
26 FlagValue: flag,
27 DefaultValue: def,
28 }
29}
30
31func (id *basicID) Env() string { return id.EnvValue }
32func (id *basicID) Flag() string { return id.FlagValue }
33func (id *basicID) Default() bool { return id.DefaultValue }
34func (id *basicID) unexported() {}
diff --git a/vendor/github.com/hashicorp/terraform/helper/hashcode/hashcode.go b/vendor/github.com/hashicorp/terraform/helper/hashcode/hashcode.go
index 64d8263..6ccc523 100644
--- a/vendor/github.com/hashicorp/terraform/helper/hashcode/hashcode.go
+++ b/vendor/github.com/hashicorp/terraform/helper/hashcode/hashcode.go
@@ -1,6 +1,8 @@
1package hashcode 1package hashcode
2 2
3import ( 3import (
4 "bytes"
5 "fmt"
4 "hash/crc32" 6 "hash/crc32"
5) 7)
6 8
@@ -20,3 +22,14 @@ func String(s string) int {
20 // v == MinInt 22 // v == MinInt
21 return 0 23 return 0
22} 24}
25
26// Strings hashes a list of strings to a unique hashcode.
27func Strings(strings []string) string {
28 var buf bytes.Buffer
29
30 for _, s := range strings {
31 buf.WriteString(fmt.Sprintf("%s-", s))
32 }
33
34 return fmt.Sprintf("%d", String(buf.String()))
35}
diff --git a/vendor/github.com/hashicorp/terraform/helper/logging/logging.go b/vendor/github.com/hashicorp/terraform/helper/logging/logging.go
index 433cd77..6bd92f7 100644
--- a/vendor/github.com/hashicorp/terraform/helper/logging/logging.go
+++ b/vendor/github.com/hashicorp/terraform/helper/logging/logging.go
@@ -18,7 +18,7 @@ const (
18 EnvLogFile = "TF_LOG_PATH" // Set to a file 18 EnvLogFile = "TF_LOG_PATH" // Set to a file
19) 19)
20 20
21var validLevels = []logutils.LogLevel{"TRACE", "DEBUG", "INFO", "WARN", "ERROR"} 21var ValidLevels = []logutils.LogLevel{"TRACE", "DEBUG", "INFO", "WARN", "ERROR"}
22 22
23// LogOutput determines where we should send logs (if anywhere) and the log level. 23// LogOutput determines where we should send logs (if anywhere) and the log level.
24func LogOutput() (logOutput io.Writer, err error) { 24func LogOutput() (logOutput io.Writer, err error) {
@@ -40,7 +40,7 @@ func LogOutput() (logOutput io.Writer, err error) {
40 40
41 // This was the default since the beginning 41 // This was the default since the beginning
42 logOutput = &logutils.LevelFilter{ 42 logOutput = &logutils.LevelFilter{
43 Levels: validLevels, 43 Levels: ValidLevels,
44 MinLevel: logutils.LogLevel(logLevel), 44 MinLevel: logutils.LogLevel(logLevel),
45 Writer: logOutput, 45 Writer: logOutput,
46 } 46 }
@@ -77,7 +77,7 @@ func LogLevel() string {
77 logLevel = strings.ToUpper(envLevel) 77 logLevel = strings.ToUpper(envLevel)
78 } else { 78 } else {
79 log.Printf("[WARN] Invalid log level: %q. Defaulting to level: TRACE. Valid levels are: %+v", 79 log.Printf("[WARN] Invalid log level: %q. Defaulting to level: TRACE. Valid levels are: %+v",
80 envLevel, validLevels) 80 envLevel, ValidLevels)
81 } 81 }
82 82
83 return logLevel 83 return logLevel
@@ -90,7 +90,7 @@ func IsDebugOrHigher() bool {
90} 90}
91 91
92func isValidLogLevel(level string) bool { 92func isValidLogLevel(level string) bool {
93 for _, l := range validLevels { 93 for _, l := range ValidLevels {
94 if strings.ToUpper(level) == string(l) { 94 if strings.ToUpper(level) == string(l) {
95 return true 95 return true
96 } 96 }
diff --git a/vendor/github.com/hashicorp/terraform/helper/logging/transport.go b/vendor/github.com/hashicorp/terraform/helper/logging/transport.go
index 4477924..bddabe6 100644
--- a/vendor/github.com/hashicorp/terraform/helper/logging/transport.go
+++ b/vendor/github.com/hashicorp/terraform/helper/logging/transport.go
@@ -1,9 +1,12 @@
1package logging 1package logging
2 2
3import ( 3import (
4 "bytes"
5 "encoding/json"
4 "log" 6 "log"
5 "net/http" 7 "net/http"
6 "net/http/httputil" 8 "net/http/httputil"
9 "strings"
7) 10)
8 11
9type transport struct { 12type transport struct {
@@ -15,7 +18,7 @@ func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
15 if IsDebugOrHigher() { 18 if IsDebugOrHigher() {
16 reqData, err := httputil.DumpRequestOut(req, true) 19 reqData, err := httputil.DumpRequestOut(req, true)
17 if err == nil { 20 if err == nil {
18 log.Printf("[DEBUG] "+logReqMsg, t.name, string(reqData)) 21 log.Printf("[DEBUG] "+logReqMsg, t.name, prettyPrintJsonLines(reqData))
19 } else { 22 } else {
20 log.Printf("[ERROR] %s API Request error: %#v", t.name, err) 23 log.Printf("[ERROR] %s API Request error: %#v", t.name, err)
21 } 24 }
@@ -29,7 +32,7 @@ func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
29 if IsDebugOrHigher() { 32 if IsDebugOrHigher() {
30 respData, err := httputil.DumpResponse(resp, true) 33 respData, err := httputil.DumpResponse(resp, true)
31 if err == nil { 34 if err == nil {
32 log.Printf("[DEBUG] "+logRespMsg, t.name, string(respData)) 35 log.Printf("[DEBUG] "+logRespMsg, t.name, prettyPrintJsonLines(respData))
33 } else { 36 } else {
34 log.Printf("[ERROR] %s API Response error: %#v", t.name, err) 37 log.Printf("[ERROR] %s API Response error: %#v", t.name, err)
35 } 38 }
@@ -42,6 +45,20 @@ func NewTransport(name string, t http.RoundTripper) *transport {
42 return &transport{name, t} 45 return &transport{name, t}
43} 46}
44 47
48// prettyPrintJsonLines iterates through a []byte line-by-line,
49// transforming any lines that are complete json into pretty-printed json.
50func prettyPrintJsonLines(b []byte) string {
51 parts := strings.Split(string(b), "\n")
52 for i, p := range parts {
53 if b := []byte(p); json.Valid(b) {
54 var out bytes.Buffer
55 json.Indent(&out, b, "", " ")
56 parts[i] = out.String()
57 }
58 }
59 return strings.Join(parts, "\n")
60}
61
45const logReqMsg = `%s API Request Details: 62const logReqMsg = `%s API Request Details:
46---[ REQUEST ]--------------------------------------- 63---[ REQUEST ]---------------------------------------
47%s 64%s
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/id.go b/vendor/github.com/hashicorp/terraform/helper/resource/id.go
index 1cde67c..4494955 100644
--- a/vendor/github.com/hashicorp/terraform/helper/resource/id.go
+++ b/vendor/github.com/hashicorp/terraform/helper/resource/id.go
@@ -18,6 +18,11 @@ func UniqueId() string {
18 return PrefixedUniqueId(UniqueIdPrefix) 18 return PrefixedUniqueId(UniqueIdPrefix)
19} 19}
20 20
21// UniqueIDSuffixLength is the string length of the suffix generated by
22// PrefixedUniqueId. This can be used by length validation functions to
23// ensure prefixes are the correct length for the target field.
24const UniqueIDSuffixLength = 26
25
21// Helper for a resource to generate a unique identifier w/ given prefix 26// Helper for a resource to generate a unique identifier w/ given prefix
22// 27//
23// After the prefix, the ID consists of an incrementing 26 digit value (to match 28// After the prefix, the ID consists of an incrementing 26 digit value (to match
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/state.go b/vendor/github.com/hashicorp/terraform/helper/resource/state.go
index 37c586a..c34e21b 100644
--- a/vendor/github.com/hashicorp/terraform/helper/resource/state.go
+++ b/vendor/github.com/hashicorp/terraform/helper/resource/state.go
@@ -46,7 +46,7 @@ type StateChangeConf struct {
46// If the Timeout is exceeded before reaching the Target state, return an 46// If the Timeout is exceeded before reaching the Target state, return an
47// error. 47// error.
48// 48//
49// Otherwise, result the result of the first call to the Refresh function to 49// Otherwise, the result is the result of the first call to the Refresh function to
50// reach the target state. 50// reach the target state.
51func (conf *StateChangeConf) WaitForState() (interface{}, error) { 51func (conf *StateChangeConf) WaitForState() (interface{}, error) {
52 log.Printf("[DEBUG] Waiting for state to become: %s", conf.Target) 52 log.Printf("[DEBUG] Waiting for state to become: %s", conf.Target)
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/testing.go b/vendor/github.com/hashicorp/terraform/helper/resource/testing.go
index d7de1a0..b97673f 100644
--- a/vendor/github.com/hashicorp/terraform/helper/resource/testing.go
+++ b/vendor/github.com/hashicorp/terraform/helper/resource/testing.go
@@ -11,11 +11,13 @@ import (
11 "reflect" 11 "reflect"
12 "regexp" 12 "regexp"
13 "strings" 13 "strings"
14 "syscall"
14 "testing" 15 "testing"
15 16
16 "github.com/davecgh/go-spew/spew" 17 "github.com/davecgh/go-spew/spew"
17 "github.com/hashicorp/go-getter" 18 "github.com/hashicorp/errwrap"
18 "github.com/hashicorp/go-multierror" 19 "github.com/hashicorp/go-multierror"
20 "github.com/hashicorp/logutils"
19 "github.com/hashicorp/terraform/config/module" 21 "github.com/hashicorp/terraform/config/module"
20 "github.com/hashicorp/terraform/helper/logging" 22 "github.com/hashicorp/terraform/helper/logging"
21 "github.com/hashicorp/terraform/terraform" 23 "github.com/hashicorp/terraform/terraform"
@@ -186,6 +188,10 @@ type TestCheckFunc func(*terraform.State) error
186// ImportStateCheckFunc is the check function for ImportState tests 188// ImportStateCheckFunc is the check function for ImportState tests
187type ImportStateCheckFunc func([]*terraform.InstanceState) error 189type ImportStateCheckFunc func([]*terraform.InstanceState) error
188 190
191// ImportStateIdFunc is an ID generation function to help with complex ID
192// generation for ImportState tests.
193type ImportStateIdFunc func(*terraform.State) (string, error)
194
189// TestCase is a single acceptance test case used to test the apply/destroy 195// TestCase is a single acceptance test case used to test the apply/destroy
190// lifecycle of a resource in a specific configuration. 196// lifecycle of a resource in a specific configuration.
191// 197//
@@ -260,6 +266,15 @@ type TestStep struct {
260 // below. 266 // below.
261 PreConfig func() 267 PreConfig func()
262 268
269 // Taint is a list of resource addresses to taint prior to the execution of
270 // the step. Be sure to only include this at a step where the referenced
271 // address will be present in state, as it will fail the test if the resource
272 // is missing.
273 //
274 // This option is ignored on ImportState tests, and currently only works for
275 // resources in the root module path.
276 Taint []string
277
263 //--------------------------------------------------------------- 278 //---------------------------------------------------------------
264 // Test modes. One of the following groups of settings must be 279 // Test modes. One of the following groups of settings must be
265 // set to determine what the test step will do. Ideally we would've 280 // set to determine what the test step will do. Ideally we would've
@@ -304,10 +319,19 @@ type TestStep struct {
304 // no-op plans 319 // no-op plans
305 PlanOnly bool 320 PlanOnly bool
306 321
322 // PreventDiskCleanup can be set to true for testing terraform modules which
323 // require access to disk at runtime. Note that this will leave files in the
324 // temp folder
325 PreventDiskCleanup bool
326
307 // PreventPostDestroyRefresh can be set to true for cases where data sources 327 // PreventPostDestroyRefresh can be set to true for cases where data sources
308 // are tested alongside real resources 328 // are tested alongside real resources
309 PreventPostDestroyRefresh bool 329 PreventPostDestroyRefresh bool
310 330
331 // SkipFunc is called before applying config, but after PreConfig
332 // This is useful for defining test steps with platform-dependent checks
333 SkipFunc func() (bool, error)
334
311 //--------------------------------------------------------------- 335 //---------------------------------------------------------------
312 // ImportState testing 336 // ImportState testing
313 //--------------------------------------------------------------- 337 //---------------------------------------------------------------
@@ -329,6 +353,12 @@ type TestStep struct {
329 // the unset ImportStateId field. 353 // the unset ImportStateId field.
330 ImportStateIdPrefix string 354 ImportStateIdPrefix string
331 355
356 // ImportStateIdFunc is a function that can be used to dynamically generate
357 // the ID for the ImportState tests. It is sent the state, which can be
358 // checked to derive the attributes necessary and generate the string in the
359 // desired format.
360 ImportStateIdFunc ImportStateIdFunc
361
332 // ImportStateCheck checks the results of ImportState. It should be 362 // ImportStateCheck checks the results of ImportState. It should be
333 // used to verify that the resulting value of ImportState has the 363 // used to verify that the resulting value of ImportState has the
334 // proper resources, IDs, and attributes. 364 // proper resources, IDs, and attributes.
@@ -345,6 +375,60 @@ type TestStep struct {
345 ImportStateVerifyIgnore []string 375 ImportStateVerifyIgnore []string
346} 376}
347 377
378// Set to a file mask in sprintf format where %s is test name
379const EnvLogPathMask = "TF_LOG_PATH_MASK"
380
381func LogOutput(t TestT) (logOutput io.Writer, err error) {
382 logOutput = ioutil.Discard
383
384 logLevel := logging.LogLevel()
385 if logLevel == "" {
386 return
387 }
388
389 logOutput = os.Stderr
390
391 if logPath := os.Getenv(logging.EnvLogFile); logPath != "" {
392 var err error
393 logOutput, err = os.OpenFile(logPath, syscall.O_CREAT|syscall.O_RDWR|syscall.O_APPEND, 0666)
394 if err != nil {
395 return nil, err
396 }
397 }
398
399 if logPathMask := os.Getenv(EnvLogPathMask); logPathMask != "" {
400 // Escape special characters which may appear if we have subtests
401 testName := strings.Replace(t.Name(), "/", "__", -1)
402
403 logPath := fmt.Sprintf(logPathMask, testName)
404 var err error
405 logOutput, err = os.OpenFile(logPath, syscall.O_CREAT|syscall.O_RDWR|syscall.O_APPEND, 0666)
406 if err != nil {
407 return nil, err
408 }
409 }
410
411 // This was the default since the beginning
412 logOutput = &logutils.LevelFilter{
413 Levels: logging.ValidLevels,
414 MinLevel: logutils.LogLevel(logLevel),
415 Writer: logOutput,
416 }
417
418 return
419}
420
421// ParallelTest performs an acceptance test on a resource, allowing concurrency
422// with other ParallelTest.
423//
424// Tests will fail if they do not properly handle conditions to allow multiple
425// tests to occur against the same resource or service (e.g. random naming).
426// All other requirements of the Test function also apply to this function.
427func ParallelTest(t TestT, c TestCase) {
428 t.Parallel()
429 Test(t, c)
430}
431
348// Test performs an acceptance test on a resource. 432// Test performs an acceptance test on a resource.
349// 433//
350// Tests are not run unless an environmental variable "TF_ACC" is 434// Tests are not run unless an environmental variable "TF_ACC" is
@@ -366,7 +450,7 @@ func Test(t TestT, c TestCase) {
366 return 450 return
367 } 451 }
368 452
369 logWriter, err := logging.LogOutput() 453 logWriter, err := LogOutput(t)
370 if err != nil { 454 if err != nil {
371 t.Error(fmt.Errorf("error setting up logging: %s", err)) 455 t.Error(fmt.Errorf("error setting up logging: %s", err))
372 } 456 }
@@ -398,7 +482,18 @@ func Test(t TestT, c TestCase) {
398 errored := false 482 errored := false
399 for i, step := range c.Steps { 483 for i, step := range c.Steps {
400 var err error 484 var err error
401 log.Printf("[WARN] Test: Executing step %d", i) 485 log.Printf("[DEBUG] Test: Executing step %d", i)
486
487 if step.SkipFunc != nil {
488 skip, err := step.SkipFunc()
489 if err != nil {
490 t.Fatal(err)
491 }
492 if skip {
493 log.Printf("[WARN] Skipping step %d", i)
494 continue
495 }
496 }
402 497
403 if step.Config == "" && !step.ImportState { 498 if step.Config == "" && !step.ImportState {
404 err = fmt.Errorf( 499 err = fmt.Errorf(
@@ -418,6 +513,15 @@ func Test(t TestT, c TestCase) {
418 } 513 }
419 } 514 }
420 515
516 // If we expected an error, but did not get one, fail
517 if err == nil && step.ExpectError != nil {
518 errored = true
519 t.Error(fmt.Sprintf(
520 "Step %d, no error received, but expected a match to:\n\n%s\n\n",
521 i, step.ExpectError))
522 break
523 }
524
421 // If there was an error, exit 525 // If there was an error, exit
422 if err != nil { 526 if err != nil {
423 // Perhaps we expected an error? Check if it matches 527 // Perhaps we expected an error? Check if it matches
@@ -485,6 +589,7 @@ func Test(t TestT, c TestCase) {
485 Config: lastStep.Config, 589 Config: lastStep.Config,
486 Check: c.CheckDestroy, 590 Check: c.CheckDestroy,
487 Destroy: true, 591 Destroy: true,
592 PreventDiskCleanup: lastStep.PreventDiskCleanup,
488 PreventPostDestroyRefresh: c.PreventPostDestroyRefresh, 593 PreventPostDestroyRefresh: c.PreventPostDestroyRefresh,
489 } 594 }
490 595
@@ -593,18 +698,12 @@ func testIDOnlyRefresh(c TestCase, opts terraform.ContextOpts, step TestStep, r
593 if err != nil { 698 if err != nil {
594 return err 699 return err
595 } 700 }
596 if ws, es := ctx.Validate(); len(ws) > 0 || len(es) > 0 { 701 if diags := ctx.Validate(); len(diags) > 0 {
597 if len(es) > 0 { 702 if diags.HasErrors() {
598 estrs := make([]string, len(es)) 703 return errwrap.Wrapf("config is invalid: {{err}}", diags.Err())
599 for i, e := range es {
600 estrs[i] = e.Error()
601 }
602 return fmt.Errorf(
603 "Configuration is invalid.\n\nWarnings: %#v\n\nErrors: %#v",
604 ws, estrs)
605 } 704 }
606 705
607 log.Printf("[WARN] Config warnings: %#v", ws) 706 log.Printf("[WARN] Config warnings:\n%s", diags.Err().Error())
608 } 707 }
609 708
610 // Refresh! 709 // Refresh!
@@ -657,9 +756,7 @@ func testIDOnlyRefresh(c TestCase, opts terraform.ContextOpts, step TestStep, r
657 return nil 756 return nil
658} 757}
659 758
660func testModule( 759func testModule(opts terraform.ContextOpts, step TestStep) (*module.Tree, error) {
661 opts terraform.ContextOpts,
662 step TestStep) (*module.Tree, error) {
663 if step.PreConfig != nil { 760 if step.PreConfig != nil {
664 step.PreConfig() 761 step.PreConfig()
665 } 762 }
@@ -669,7 +766,12 @@ func testModule(
669 return nil, fmt.Errorf( 766 return nil, fmt.Errorf(
670 "Error creating temporary directory for config: %s", err) 767 "Error creating temporary directory for config: %s", err)
671 } 768 }
672 defer os.RemoveAll(cfgPath) 769
770 if step.PreventDiskCleanup {
771 log.Printf("[INFO] Skipping defer os.RemoveAll call")
772 } else {
773 defer os.RemoveAll(cfgPath)
774 }
673 775
674 // Write the configuration 776 // Write the configuration
675 cfgF, err := os.Create(filepath.Join(cfgPath, "main.tf")) 777 cfgF, err := os.Create(filepath.Join(cfgPath, "main.tf"))
@@ -693,10 +795,11 @@ func testModule(
693 } 795 }
694 796
695 // Load the modules 797 // Load the modules
696 modStorage := &getter.FolderStorage{ 798 modStorage := &module.Storage{
697 StorageDir: filepath.Join(cfgPath, ".tfmodules"), 799 StorageDir: filepath.Join(cfgPath, ".tfmodules"),
800 Mode: module.GetModeGet,
698 } 801 }
699 err = mod.Load(modStorage, module.GetModeGet) 802 err = mod.Load(modStorage)
700 if err != nil { 803 if err != nil {
701 return nil, fmt.Errorf("Error downloading modules: %s", err) 804 return nil, fmt.Errorf("Error downloading modules: %s", err)
702 } 805 }
@@ -771,12 +874,29 @@ func TestCheckResourceAttrSet(name, key string) TestCheckFunc {
771 return err 874 return err
772 } 875 }
773 876
774 if val, ok := is.Attributes[key]; ok && val != "" { 877 return testCheckResourceAttrSet(is, name, key)
775 return nil 878 }
879}
880
881// TestCheckModuleResourceAttrSet - as per TestCheckResourceAttrSet but with
882// support for non-root modules
883func TestCheckModuleResourceAttrSet(mp []string, name string, key string) TestCheckFunc {
884 return func(s *terraform.State) error {
885 is, err := modulePathPrimaryInstanceState(s, mp, name)
886 if err != nil {
887 return err
776 } 888 }
777 889
890 return testCheckResourceAttrSet(is, name, key)
891 }
892}
893
894func testCheckResourceAttrSet(is *terraform.InstanceState, name string, key string) error {
895 if val, ok := is.Attributes[key]; !ok || val == "" {
778 return fmt.Errorf("%s: Attribute '%s' expected to be set", name, key) 896 return fmt.Errorf("%s: Attribute '%s' expected to be set", name, key)
779 } 897 }
898
899 return nil
780} 900}
781 901
782// TestCheckResourceAttr is a TestCheckFunc which validates 902// TestCheckResourceAttr is a TestCheckFunc which validates
@@ -788,21 +908,37 @@ func TestCheckResourceAttr(name, key, value string) TestCheckFunc {
788 return err 908 return err
789 } 909 }
790 910
791 if v, ok := is.Attributes[key]; !ok || v != value { 911 return testCheckResourceAttr(is, name, key, value)
792 if !ok { 912 }
793 return fmt.Errorf("%s: Attribute '%s' not found", name, key) 913}
794 }
795 914
796 return fmt.Errorf( 915// TestCheckModuleResourceAttr - as per TestCheckResourceAttr but with
797 "%s: Attribute '%s' expected %#v, got %#v", 916// support for non-root modules
798 name, 917func TestCheckModuleResourceAttr(mp []string, name string, key string, value string) TestCheckFunc {
799 key, 918 return func(s *terraform.State) error {
800 value, 919 is, err := modulePathPrimaryInstanceState(s, mp, name)
801 v) 920 if err != nil {
921 return err
802 } 922 }
803 923
804 return nil 924 return testCheckResourceAttr(is, name, key, value)
925 }
926}
927
928func testCheckResourceAttr(is *terraform.InstanceState, name string, key string, value string) error {
929 if v, ok := is.Attributes[key]; !ok || v != value {
930 if !ok {
931 return fmt.Errorf("%s: Attribute '%s' not found", name, key)
932 }
933
934 return fmt.Errorf(
935 "%s: Attribute '%s' expected %#v, got %#v",
936 name,
937 key,
938 value,
939 v)
805 } 940 }
941 return nil
806} 942}
807 943
808// TestCheckNoResourceAttr is a TestCheckFunc which ensures that 944// TestCheckNoResourceAttr is a TestCheckFunc which ensures that
@@ -814,14 +950,31 @@ func TestCheckNoResourceAttr(name, key string) TestCheckFunc {
814 return err 950 return err
815 } 951 }
816 952
817 if _, ok := is.Attributes[key]; ok { 953 return testCheckNoResourceAttr(is, name, key)
818 return fmt.Errorf("%s: Attribute '%s' found when not expected", name, key) 954 }
955}
956
957// TestCheckModuleNoResourceAttr - as per TestCheckNoResourceAttr but with
958// support for non-root modules
959func TestCheckModuleNoResourceAttr(mp []string, name string, key string) TestCheckFunc {
960 return func(s *terraform.State) error {
961 is, err := modulePathPrimaryInstanceState(s, mp, name)
962 if err != nil {
963 return err
819 } 964 }
820 965
821 return nil 966 return testCheckNoResourceAttr(is, name, key)
822 } 967 }
823} 968}
824 969
970func testCheckNoResourceAttr(is *terraform.InstanceState, name string, key string) error {
971 if _, ok := is.Attributes[key]; ok {
972 return fmt.Errorf("%s: Attribute '%s' found when not expected", name, key)
973 }
974
975 return nil
976}
977
825// TestMatchResourceAttr is a TestCheckFunc which checks that the value 978// TestMatchResourceAttr is a TestCheckFunc which checks that the value
826// in state for the given name/key combination matches the given regex. 979// in state for the given name/key combination matches the given regex.
827func TestMatchResourceAttr(name, key string, r *regexp.Regexp) TestCheckFunc { 980func TestMatchResourceAttr(name, key string, r *regexp.Regexp) TestCheckFunc {
@@ -831,17 +984,34 @@ func TestMatchResourceAttr(name, key string, r *regexp.Regexp) TestCheckFunc {
831 return err 984 return err
832 } 985 }
833 986
834 if !r.MatchString(is.Attributes[key]) { 987 return testMatchResourceAttr(is, name, key, r)
835 return fmt.Errorf( 988 }
836 "%s: Attribute '%s' didn't match %q, got %#v", 989}
837 name, 990
838 key, 991// TestModuleMatchResourceAttr - as per TestMatchResourceAttr but with
839 r.String(), 992// support for non-root modules
840 is.Attributes[key]) 993func TestModuleMatchResourceAttr(mp []string, name string, key string, r *regexp.Regexp) TestCheckFunc {
994 return func(s *terraform.State) error {
995 is, err := modulePathPrimaryInstanceState(s, mp, name)
996 if err != nil {
997 return err
841 } 998 }
842 999
843 return nil 1000 return testMatchResourceAttr(is, name, key, r)
1001 }
1002}
1003
1004func testMatchResourceAttr(is *terraform.InstanceState, name string, key string, r *regexp.Regexp) error {
1005 if !r.MatchString(is.Attributes[key]) {
1006 return fmt.Errorf(
1007 "%s: Attribute '%s' didn't match %q, got %#v",
1008 name,
1009 key,
1010 r.String(),
1011 is.Attributes[key])
844 } 1012 }
1013
1014 return nil
845} 1015}
846 1016
847// TestCheckResourceAttrPtr is like TestCheckResourceAttr except the 1017// TestCheckResourceAttrPtr is like TestCheckResourceAttr except the
@@ -853,6 +1023,14 @@ func TestCheckResourceAttrPtr(name string, key string, value *string) TestCheckF
853 } 1023 }
854} 1024}
855 1025
1026// TestCheckModuleResourceAttrPtr - as per TestCheckResourceAttrPtr but with
1027// support for non-root modules
1028func TestCheckModuleResourceAttrPtr(mp []string, name string, key string, value *string) TestCheckFunc {
1029 return func(s *terraform.State) error {
1030 return TestCheckModuleResourceAttr(mp, name, key, *value)(s)
1031 }
1032}
1033
856// TestCheckResourceAttrPair is a TestCheckFunc which validates that the values 1034// TestCheckResourceAttrPair is a TestCheckFunc which validates that the values
857// in state for a pair of name/key combinations are equal. 1035// in state for a pair of name/key combinations are equal.
858func TestCheckResourceAttrPair(nameFirst, keyFirst, nameSecond, keySecond string) TestCheckFunc { 1036func TestCheckResourceAttrPair(nameFirst, keyFirst, nameSecond, keySecond string) TestCheckFunc {
@@ -861,33 +1039,57 @@ func TestCheckResourceAttrPair(nameFirst, keyFirst, nameSecond, keySecond string
861 if err != nil { 1039 if err != nil {
862 return err 1040 return err
863 } 1041 }
864 vFirst, ok := isFirst.Attributes[keyFirst]
865 if !ok {
866 return fmt.Errorf("%s: Attribute '%s' not found", nameFirst, keyFirst)
867 }
868 1042
869 isSecond, err := primaryInstanceState(s, nameSecond) 1043 isSecond, err := primaryInstanceState(s, nameSecond)
870 if err != nil { 1044 if err != nil {
871 return err 1045 return err
872 } 1046 }
873 vSecond, ok := isSecond.Attributes[keySecond] 1047
874 if !ok { 1048 return testCheckResourceAttrPair(isFirst, nameFirst, keyFirst, isSecond, nameSecond, keySecond)
875 return fmt.Errorf("%s: Attribute '%s' not found", nameSecond, keySecond) 1049 }
1050}
1051
1052// TestCheckModuleResourceAttrPair - as per TestCheckResourceAttrPair but with
1053// support for non-root modules
1054func TestCheckModuleResourceAttrPair(mpFirst []string, nameFirst string, keyFirst string, mpSecond []string, nameSecond string, keySecond string) TestCheckFunc {
1055 return func(s *terraform.State) error {
1056 isFirst, err := modulePathPrimaryInstanceState(s, mpFirst, nameFirst)
1057 if err != nil {
1058 return err
876 } 1059 }
877 1060
878 if vFirst != vSecond { 1061 isSecond, err := modulePathPrimaryInstanceState(s, mpSecond, nameSecond)
879 return fmt.Errorf( 1062 if err != nil {
880 "%s: Attribute '%s' expected %#v, got %#v", 1063 return err
881 nameFirst,
882 keyFirst,
883 vSecond,
884 vFirst)
885 } 1064 }
886 1065
887 return nil 1066 return testCheckResourceAttrPair(isFirst, nameFirst, keyFirst, isSecond, nameSecond, keySecond)
888 } 1067 }
889} 1068}
890 1069
1070func testCheckResourceAttrPair(isFirst *terraform.InstanceState, nameFirst string, keyFirst string, isSecond *terraform.InstanceState, nameSecond string, keySecond string) error {
1071 vFirst, ok := isFirst.Attributes[keyFirst]
1072 if !ok {
1073 return fmt.Errorf("%s: Attribute '%s' not found", nameFirst, keyFirst)
1074 }
1075
1076 vSecond, ok := isSecond.Attributes[keySecond]
1077 if !ok {
1078 return fmt.Errorf("%s: Attribute '%s' not found", nameSecond, keySecond)
1079 }
1080
1081 if vFirst != vSecond {
1082 return fmt.Errorf(
1083 "%s: Attribute '%s' expected %#v, got %#v",
1084 nameFirst,
1085 keyFirst,
1086 vSecond,
1087 vFirst)
1088 }
1089
1090 return nil
1091}
1092
891// TestCheckOutput checks an output in the Terraform configuration 1093// TestCheckOutput checks an output in the Terraform configuration
892func TestCheckOutput(name, value string) TestCheckFunc { 1094func TestCheckOutput(name, value string) TestCheckFunc {
893 return func(s *terraform.State) error { 1095 return func(s *terraform.State) error {
@@ -936,23 +1138,43 @@ type TestT interface {
936 Error(args ...interface{}) 1138 Error(args ...interface{})
937 Fatal(args ...interface{}) 1139 Fatal(args ...interface{})
938 Skip(args ...interface{}) 1140 Skip(args ...interface{})
1141 Name() string
1142 Parallel()
939} 1143}
940 1144
941// This is set to true by unit tests to alter some behavior 1145// This is set to true by unit tests to alter some behavior
942var testTesting = false 1146var testTesting = false
943 1147
944// primaryInstanceState returns the primary instance state for the given resource name. 1148// modulePrimaryInstanceState returns the instance state for the given resource
945func primaryInstanceState(s *terraform.State, name string) (*terraform.InstanceState, error) { 1149// name in a ModuleState
946 ms := s.RootModule() 1150func modulePrimaryInstanceState(s *terraform.State, ms *terraform.ModuleState, name string) (*terraform.InstanceState, error) {
947 rs, ok := ms.Resources[name] 1151 rs, ok := ms.Resources[name]
948 if !ok { 1152 if !ok {
949 return nil, fmt.Errorf("Not found: %s", name) 1153 return nil, fmt.Errorf("Not found: %s in %s", name, ms.Path)
950 } 1154 }
951 1155
952 is := rs.Primary 1156 is := rs.Primary
953 if is == nil { 1157 if is == nil {
954 return nil, fmt.Errorf("No primary instance: %s", name) 1158 return nil, fmt.Errorf("No primary instance: %s in %s", name, ms.Path)
955 } 1159 }
956 1160
957 return is, nil 1161 return is, nil
958} 1162}
1163
1164// modulePathPrimaryInstanceState returns the primary instance state for the
1165// given resource name in a given module path.
1166func modulePathPrimaryInstanceState(s *terraform.State, mp []string, name string) (*terraform.InstanceState, error) {
1167 ms := s.ModuleByPath(mp)
1168 if ms == nil {
1169 return nil, fmt.Errorf("No module found at: %s", mp)
1170 }
1171
1172 return modulePrimaryInstanceState(s, ms, name)
1173}
1174
1175// primaryInstanceState returns the primary instance state for the given
1176// resource name in the root module.
1177func primaryInstanceState(s *terraform.State, name string) (*terraform.InstanceState, error) {
1178 ms := s.RootModule()
1179 return modulePrimaryInstanceState(s, ms, name)
1180}
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/testing_config.go b/vendor/github.com/hashicorp/terraform/helper/resource/testing_config.go
index 537a11c..033f126 100644
--- a/vendor/github.com/hashicorp/terraform/helper/resource/testing_config.go
+++ b/vendor/github.com/hashicorp/terraform/helper/resource/testing_config.go
@@ -1,10 +1,12 @@
1package resource 1package resource
2 2
3import ( 3import (
4 "errors"
4 "fmt" 5 "fmt"
5 "log" 6 "log"
6 "strings" 7 "strings"
7 8
9 "github.com/hashicorp/errwrap"
8 "github.com/hashicorp/terraform/terraform" 10 "github.com/hashicorp/terraform/terraform"
9) 11)
10 12
@@ -20,6 +22,14 @@ func testStep(
20 opts terraform.ContextOpts, 22 opts terraform.ContextOpts,
21 state *terraform.State, 23 state *terraform.State,
22 step TestStep) (*terraform.State, error) { 24 step TestStep) (*terraform.State, error) {
25 // Pre-taint any resources that have been defined in Taint, as long as this
26 // is not a destroy step.
27 if !step.Destroy {
28 if err := testStepTaint(state, step); err != nil {
29 return state, err
30 }
31 }
32
23 mod, err := testModule(opts, step) 33 mod, err := testModule(opts, step)
24 if err != nil { 34 if err != nil {
25 return state, err 35 return state, err
@@ -33,17 +43,12 @@ func testStep(
33 if err != nil { 43 if err != nil {
34 return state, fmt.Errorf("Error initializing context: %s", err) 44 return state, fmt.Errorf("Error initializing context: %s", err)
35 } 45 }
36 if ws, es := ctx.Validate(); len(ws) > 0 || len(es) > 0 { 46 if diags := ctx.Validate(); len(diags) > 0 {
37 if len(es) > 0 { 47 if diags.HasErrors() {
38 estrs := make([]string, len(es)) 48 return nil, errwrap.Wrapf("config is invalid: {{err}}", diags.Err())
39 for i, e := range es {
40 estrs[i] = e.Error()
41 }
42 return state, fmt.Errorf(
43 "Configuration is invalid.\n\nWarnings: %#v\n\nErrors: %#v",
44 ws, estrs)
45 } 49 }
46 log.Printf("[WARN] Config warnings: %#v", ws) 50
51 log.Printf("[WARN] Config warnings:\n%s", diags)
47 } 52 }
48 53
49 // Refresh! 54 // Refresh!
@@ -158,3 +163,19 @@ func testStep(
158 // Made it here? Good job test step! 163 // Made it here? Good job test step!
159 return state, nil 164 return state, nil
160} 165}
166
167func testStepTaint(state *terraform.State, step TestStep) error {
168 for _, p := range step.Taint {
169 m := state.RootModule()
170 if m == nil {
171 return errors.New("no state")
172 }
173 rs, ok := m.Resources[p]
174 if !ok {
175 return fmt.Errorf("resource %q not found in state", p)
176 }
177 log.Printf("[WARN] Test: Explicitly tainting resource %q", p)
178 rs.Taint()
179 }
180 return nil
181}
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/testing_import_state.go b/vendor/github.com/hashicorp/terraform/helper/resource/testing_import_state.go
index 28ad105..94fef3c 100644
--- a/vendor/github.com/hashicorp/terraform/helper/resource/testing_import_state.go
+++ b/vendor/github.com/hashicorp/terraform/helper/resource/testing_import_state.go
@@ -16,15 +16,24 @@ func testStepImportState(
16 state *terraform.State, 16 state *terraform.State,
17 step TestStep) (*terraform.State, error) { 17 step TestStep) (*terraform.State, error) {
18 // Determine the ID to import 18 // Determine the ID to import
19 importId := step.ImportStateId 19 var importId string
20 if importId == "" { 20 switch {
21 case step.ImportStateIdFunc != nil:
22 var err error
23 importId, err = step.ImportStateIdFunc(state)
24 if err != nil {
25 return state, err
26 }
27 case step.ImportStateId != "":
28 importId = step.ImportStateId
29 default:
21 resource, err := testResource(step, state) 30 resource, err := testResource(step, state)
22 if err != nil { 31 if err != nil {
23 return state, err 32 return state, err
24 } 33 }
25
26 importId = resource.Primary.ID 34 importId = resource.Primary.ID
27 } 35 }
36
28 importPrefix := step.ImportStateIdPrefix 37 importPrefix := step.ImportStateIdPrefix
29 if importPrefix != "" { 38 if importPrefix != "" {
30 importId = fmt.Sprintf("%s%s", importPrefix, importId) 39 importId = fmt.Sprintf("%s%s", importPrefix, importId)
diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/wait.go b/vendor/github.com/hashicorp/terraform/helper/resource/wait.go
index ca50e29..e56a515 100644
--- a/vendor/github.com/hashicorp/terraform/helper/resource/wait.go
+++ b/vendor/github.com/hashicorp/terraform/helper/resource/wait.go
@@ -74,7 +74,7 @@ func RetryableError(err error) *RetryError {
74 return &RetryError{Err: err, Retryable: true} 74 return &RetryError{Err: err, Retryable: true}
75} 75}
76 76
77// NonRetryableError is a helper to create a RetryError that's _not)_ retryable 77// NonRetryableError is a helper to create a RetryError that's _not_ retryable
78// from a given error. 78// from a given error.
79func NonRetryableError(err error) *RetryError { 79func NonRetryableError(err error) *RetryError {
80 if err == nil { 80 if err == nil {
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/backend.go b/vendor/github.com/hashicorp/terraform/helper/schema/backend.go
index a0729c0..57fbba7 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/backend.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/backend.go
@@ -65,7 +65,7 @@ func (b *Backend) Configure(c *terraform.ResourceConfig) error {
65 65
66 // Get a ResourceData for this configuration. To do this, we actually 66 // Get a ResourceData for this configuration. To do this, we actually
67 // generate an intermediary "diff" although that is never exposed. 67 // generate an intermediary "diff" although that is never exposed.
68 diff, err := sm.Diff(nil, c) 68 diff, err := sm.Diff(nil, c, nil, nil)
69 if err != nil { 69 if err != nil {
70 return err 70 return err
71 } 71 }
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/core_schema.go b/vendor/github.com/hashicorp/terraform/helper/schema/core_schema.go
new file mode 100644
index 0000000..bf952f6
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/core_schema.go
@@ -0,0 +1,155 @@
1package schema
2
3import (
4 "fmt"
5
6 "github.com/hashicorp/terraform/config/configschema"
7 "github.com/zclconf/go-cty/cty"
8)
9
10// The functions and methods in this file are concerned with the conversion
11// of this package's schema model into the slightly-lower-level schema model
12// used by Terraform core for configuration parsing.
13
14// CoreConfigSchema lowers the receiver to the schema model expected by
15// Terraform core.
16//
17// This lower-level model has fewer features than the schema in this package,
18// describing only the basic structure of configuration and state values we
19// expect. The full schemaMap from this package is still required for full
20// validation, handling of default values, etc.
21//
22// This method presumes a schema that passes InternalValidate, and so may
23// panic or produce an invalid result if given an invalid schemaMap.
24func (m schemaMap) CoreConfigSchema() *configschema.Block {
25 if len(m) == 0 {
26 // We return an actual (empty) object here, rather than a nil,
27 // because a nil result would mean that we don't have a schema at
28 // all, rather than that we have an empty one.
29 return &configschema.Block{}
30 }
31
32 ret := &configschema.Block{
33 Attributes: map[string]*configschema.Attribute{},
34 BlockTypes: map[string]*configschema.NestedBlock{},
35 }
36
37 for name, schema := range m {
38 if schema.Elem == nil {
39 ret.Attributes[name] = schema.coreConfigSchemaAttribute()
40 continue
41 }
42 switch schema.Elem.(type) {
43 case *Schema:
44 ret.Attributes[name] = schema.coreConfigSchemaAttribute()
45 case *Resource:
46 ret.BlockTypes[name] = schema.coreConfigSchemaBlock()
47 default:
48 // Should never happen for a valid schema
49 panic(fmt.Errorf("invalid Schema.Elem %#v; need *Schema or *Resource", schema.Elem))
50 }
51 }
52
53 return ret
54}
55
56// coreConfigSchemaAttribute prepares a configschema.Attribute representation
57// of a schema. This is appropriate only for primitives or collections whose
58// Elem is an instance of Schema. Use coreConfigSchemaBlock for collections
59// whose elem is a whole resource.
60func (s *Schema) coreConfigSchemaAttribute() *configschema.Attribute {
61 return &configschema.Attribute{
62 Type: s.coreConfigSchemaType(),
63 Optional: s.Optional,
64 Required: s.Required,
65 Computed: s.Computed,
66 Sensitive: s.Sensitive,
67 }
68}
69
70// coreConfigSchemaBlock prepares a configschema.NestedBlock representation of
71// a schema. This is appropriate only for collections whose Elem is an instance
72// of Resource, and will panic otherwise.
73func (s *Schema) coreConfigSchemaBlock() *configschema.NestedBlock {
74 ret := &configschema.NestedBlock{}
75 if nested := s.Elem.(*Resource).CoreConfigSchema(); nested != nil {
76 ret.Block = *nested
77 }
78 switch s.Type {
79 case TypeList:
80 ret.Nesting = configschema.NestingList
81 case TypeSet:
82 ret.Nesting = configschema.NestingSet
83 case TypeMap:
84 ret.Nesting = configschema.NestingMap
85 default:
86 // Should never happen for a valid schema
87 panic(fmt.Errorf("invalid s.Type %s for s.Elem being resource", s.Type))
88 }
89
90 ret.MinItems = s.MinItems
91 ret.MaxItems = s.MaxItems
92
93 if s.Required && s.MinItems == 0 {
94 // configschema doesn't have a "required" representation for nested
95 // blocks, but we can fake it by requiring at least one item.
96 ret.MinItems = 1
97 }
98
99 return ret
100}
101
102// coreConfigSchemaType determines the core config schema type that corresponds
103// to a particular schema's type.
104func (s *Schema) coreConfigSchemaType() cty.Type {
105 switch s.Type {
106 case TypeString:
107 return cty.String
108 case TypeBool:
109 return cty.Bool
110 case TypeInt, TypeFloat:
111 // configschema doesn't distinguish int and float, so helper/schema
112 // will deal with this as an additional validation step after
113 // configuration has been parsed and decoded.
114 return cty.Number
115 case TypeList, TypeSet, TypeMap:
116 var elemType cty.Type
117 switch set := s.Elem.(type) {
118 case *Schema:
119 elemType = set.coreConfigSchemaType()
120 case *Resource:
121 // In practice we don't actually use this for normal schema
122 // construction because we construct a NestedBlock in that
123 // case instead. See schemaMap.CoreConfigSchema.
124 elemType = set.CoreConfigSchema().ImpliedType()
125 default:
126 if set != nil {
127 // Should never happen for a valid schema
128 panic(fmt.Errorf("invalid Schema.Elem %#v; need *Schema or *Resource", s.Elem))
129 }
130 // Some pre-existing schemas assume string as default, so we need
131 // to be compatible with them.
132 elemType = cty.String
133 }
134 switch s.Type {
135 case TypeList:
136 return cty.List(elemType)
137 case TypeSet:
138 return cty.Set(elemType)
139 case TypeMap:
140 return cty.Map(elemType)
141 default:
142 // can never get here in practice, due to the case we're inside
143 panic("invalid collection type")
144 }
145 default:
146 // should never happen for a valid schema
147 panic(fmt.Errorf("invalid Schema.Type %s", s.Type))
148 }
149}
150
151// CoreConfigSchema is a convenient shortcut for calling CoreConfigSchema
152// on the resource's schema.
153func (r *Resource) CoreConfigSchema() *configschema.Block {
154 return schemaMap(r.Schema).CoreConfigSchema()
155}
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/data_source_resource_shim.go b/vendor/github.com/hashicorp/terraform/helper/schema/data_source_resource_shim.go
index 5a03d2d..8d93750 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/data_source_resource_shim.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/data_source_resource_shim.go
@@ -32,7 +32,7 @@ func DataSourceResourceShim(name string, dataSource *Resource) *Resource {
32 32
33 // FIXME: Link to some further docs either on the website or in the 33 // FIXME: Link to some further docs either on the website or in the
34 // changelog, once such a thing exists. 34 // changelog, once such a thing exists.
35 dataSource.deprecationMessage = fmt.Sprintf( 35 dataSource.DeprecationMessage = fmt.Sprintf(
36 "using %s as a resource is deprecated; consider using the data source instead", 36 "using %s as a resource is deprecated; consider using the data source instead",
37 name, 37 name,
38 ) 38 )
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/field_reader.go b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader.go
index 1660a67..b80b223 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/field_reader.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader.go
@@ -126,6 +126,8 @@ func addrToSchema(addr []string, schemaMap map[string]*Schema) []*Schema {
126 switch v := current.Elem.(type) { 126 switch v := current.Elem.(type) {
127 case ValueType: 127 case ValueType:
128 current = &Schema{Type: v} 128 current = &Schema{Type: v}
129 case *Schema:
130 current, _ = current.Elem.(*Schema)
129 default: 131 default:
130 // maps default to string values. This is all we can have 132 // maps default to string values. This is all we can have
131 // if this is nested in another list or map. 133 // if this is nested in another list or map.
@@ -249,11 +251,10 @@ func readObjectField(
249} 251}
250 252
251// convert map values to the proper primitive type based on schema.Elem 253// convert map values to the proper primitive type based on schema.Elem
252func mapValuesToPrimitive(m map[string]interface{}, schema *Schema) error { 254func mapValuesToPrimitive(k string, m map[string]interface{}, schema *Schema) error {
253 255 elemType, err := getValueType(k, schema)
254 elemType := TypeString 256 if err != nil {
255 if et, ok := schema.Elem.(ValueType); ok { 257 return err
256 elemType = et
257 } 258 }
258 259
259 switch elemType { 260 switch elemType {
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_config.go b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_config.go
index f958bbc..55a301d 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_config.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_config.go
@@ -206,7 +206,7 @@ func (r *ConfigFieldReader) readMap(k string, schema *Schema) (FieldReadResult,
206 panic(fmt.Sprintf("unknown type: %#v", mraw)) 206 panic(fmt.Sprintf("unknown type: %#v", mraw))
207 } 207 }
208 208
209 err := mapValuesToPrimitive(result, schema) 209 err := mapValuesToPrimitive(k, result, schema)
210 if err != nil { 210 if err != nil {
211 return FieldReadResult{}, nil 211 return FieldReadResult{}, nil
212 } 212 }
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_diff.go b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_diff.go
index 16bbae2..d558a5b 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_diff.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_diff.go
@@ -29,29 +29,59 @@ type DiffFieldReader struct {
29 Diff *terraform.InstanceDiff 29 Diff *terraform.InstanceDiff
30 Source FieldReader 30 Source FieldReader
31 Schema map[string]*Schema 31 Schema map[string]*Schema
32
33 // cache for memoizing ReadField calls.
34 cache map[string]cachedFieldReadResult
35}
36
37type cachedFieldReadResult struct {
38 val FieldReadResult
39 err error
32} 40}
33 41
34func (r *DiffFieldReader) ReadField(address []string) (FieldReadResult, error) { 42func (r *DiffFieldReader) ReadField(address []string) (FieldReadResult, error) {
43 if r.cache == nil {
44 r.cache = make(map[string]cachedFieldReadResult)
45 }
46
47 // Create the cache key by joining around a value that isn't a valid part
48 // of an address. This assumes that the Source and Schema are not changed
49 // for the life of this DiffFieldReader.
50 cacheKey := strings.Join(address, "|")
51 if cached, ok := r.cache[cacheKey]; ok {
52 return cached.val, cached.err
53 }
54
35 schemaList := addrToSchema(address, r.Schema) 55 schemaList := addrToSchema(address, r.Schema)
36 if len(schemaList) == 0 { 56 if len(schemaList) == 0 {
57 r.cache[cacheKey] = cachedFieldReadResult{}
37 return FieldReadResult{}, nil 58 return FieldReadResult{}, nil
38 } 59 }
39 60
61 var res FieldReadResult
62 var err error
63
40 schema := schemaList[len(schemaList)-1] 64 schema := schemaList[len(schemaList)-1]
41 switch schema.Type { 65 switch schema.Type {
42 case TypeBool, TypeInt, TypeFloat, TypeString: 66 case TypeBool, TypeInt, TypeFloat, TypeString:
43 return r.readPrimitive(address, schema) 67 res, err = r.readPrimitive(address, schema)
44 case TypeList: 68 case TypeList:
45 return readListField(r, address, schema) 69 res, err = readListField(r, address, schema)
46 case TypeMap: 70 case TypeMap:
47 return r.readMap(address, schema) 71 res, err = r.readMap(address, schema)
48 case TypeSet: 72 case TypeSet:
49 return r.readSet(address, schema) 73 res, err = r.readSet(address, schema)
50 case typeObject: 74 case typeObject:
51 return readObjectField(r, address, schema.Elem.(map[string]*Schema)) 75 res, err = readObjectField(r, address, schema.Elem.(map[string]*Schema))
52 default: 76 default:
53 panic(fmt.Sprintf("Unknown type: %#v", schema.Type)) 77 panic(fmt.Sprintf("Unknown type: %#v", schema.Type))
54 } 78 }
79
80 r.cache[cacheKey] = cachedFieldReadResult{
81 val: res,
82 err: err,
83 }
84 return res, err
55} 85}
56 86
57func (r *DiffFieldReader) readMap( 87func (r *DiffFieldReader) readMap(
@@ -92,7 +122,8 @@ func (r *DiffFieldReader) readMap(
92 result[k] = v.New 122 result[k] = v.New
93 } 123 }
94 124
95 err = mapValuesToPrimitive(result, schema) 125 key := address[len(address)-1]
126 err = mapValuesToPrimitive(key, result, schema)
96 if err != nil { 127 if err != nil {
97 return FieldReadResult{}, nil 128 return FieldReadResult{}, nil
98 } 129 }
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_map.go b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_map.go
index 9533981..054efe0 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_map.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/field_reader_map.go
@@ -61,7 +61,7 @@ func (r *MapFieldReader) readMap(k string, schema *Schema) (FieldReadResult, err
61 return true 61 return true
62 }) 62 })
63 63
64 err := mapValuesToPrimitive(result, schema) 64 err := mapValuesToPrimitive(k, result, schema)
65 if err != nil { 65 if err != nil {
66 return FieldReadResult{}, nil 66 return FieldReadResult{}, nil
67 } 67 }
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/field_writer_map.go b/vendor/github.com/hashicorp/terraform/helper/schema/field_writer_map.go
index 689ed8d..814c7ba 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/field_writer_map.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/field_writer_map.go
@@ -39,6 +39,19 @@ func (w *MapFieldWriter) unsafeWriteField(addr string, value string) {
39 w.result[addr] = value 39 w.result[addr] = value
40} 40}
41 41
42// clearTree clears a field and any sub-fields of the given address out of the
43// map. This should be used to reset some kind of complex structures (namely
44// sets) before writing to make sure that any conflicting data is removed (for
45// example, if the set was previously written to the writer's layer).
46func (w *MapFieldWriter) clearTree(addr []string) {
47 prefix := strings.Join(addr, ".") + "."
48 for k := range w.result {
49 if strings.HasPrefix(k, prefix) {
50 delete(w.result, k)
51 }
52 }
53}
54
42func (w *MapFieldWriter) WriteField(addr []string, value interface{}) error { 55func (w *MapFieldWriter) WriteField(addr []string, value interface{}) error {
43 w.lock.Lock() 56 w.lock.Lock()
44 defer w.lock.Unlock() 57 defer w.lock.Unlock()
@@ -115,6 +128,14 @@ func (w *MapFieldWriter) setList(
115 return fmt.Errorf("%s: %s", k, err) 128 return fmt.Errorf("%s: %s", k, err)
116 } 129 }
117 130
131 // Wipe the set from the current writer prior to writing if it exists.
132 // Multiple writes to the same layer is a lot safer for lists than sets due
133 // to the fact that indexes are always deterministic and the length will
134 // always be updated with the current length on the last write, but making
135 // sure we have a clean namespace removes any chance for edge cases to pop up
136 // and ensures that the last write to the set is the correct value.
137 w.clearTree(addr)
138
118 // Set the entire list. 139 // Set the entire list.
119 var err error 140 var err error
120 for i, elem := range vs { 141 for i, elem := range vs {
@@ -162,6 +183,10 @@ func (w *MapFieldWriter) setMap(
162 vs[mk.String()] = mv.Interface() 183 vs[mk.String()] = mv.Interface()
163 } 184 }
164 185
186 // Wipe this address tree. The contents of the map should always reflect the
187 // last write made to it.
188 w.clearTree(addr)
189
165 // Remove the pure key since we're setting the full map value 190 // Remove the pure key since we're setting the full map value
166 delete(w.result, k) 191 delete(w.result, k)
167 192
@@ -308,6 +333,13 @@ func (w *MapFieldWriter) setSet(
308 value = s 333 value = s
309 } 334 }
310 335
336 // Clear any keys that match the set address first. This is necessary because
337 // it's always possible and sometimes may be necessary to write to a certain
338 // writer layer more than once with different set data each time, which will
339 // lead to different keys being inserted, which can lead to determinism
340 // problems when the old data isn't wiped first.
341 w.clearTree(addr)
342
311 for code, elem := range value.(*Set).m { 343 for code, elem := range value.(*Set).m {
312 if err := w.set(append(addrCopy, code), elem); err != nil { 344 if err := w.set(append(addrCopy, code), elem); err != nil {
313 return err 345 return err
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/getsource_string.go b/vendor/github.com/hashicorp/terraform/helper/schema/getsource_string.go
index 3a97629..38cd8c7 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/getsource_string.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/getsource_string.go
@@ -2,7 +2,7 @@
2 2
3package schema 3package schema
4 4
5import "fmt" 5import "strconv"
6 6
7const ( 7const (
8 _getSource_name_0 = "getSourceStategetSourceConfig" 8 _getSource_name_0 = "getSourceStategetSourceConfig"
@@ -13,8 +13,6 @@ const (
13 13
14var ( 14var (
15 _getSource_index_0 = [...]uint8{0, 14, 29} 15 _getSource_index_0 = [...]uint8{0, 14, 29}
16 _getSource_index_1 = [...]uint8{0, 13}
17 _getSource_index_2 = [...]uint8{0, 12}
18 _getSource_index_3 = [...]uint8{0, 18, 32} 16 _getSource_index_3 = [...]uint8{0, 18, 32}
19) 17)
20 18
@@ -31,6 +29,6 @@ func (i getSource) String() string {
31 i -= 15 29 i -= 15
32 return _getSource_name_3[_getSource_index_3[i]:_getSource_index_3[i+1]] 30 return _getSource_name_3[_getSource_index_3[i]:_getSource_index_3[i+1]]
33 default: 31 default:
34 return fmt.Sprintf("getSource(%d)", i) 32 return "getSource(" + strconv.FormatInt(int64(i), 10) + ")"
35 } 33 }
36} 34}
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/provider.go b/vendor/github.com/hashicorp/terraform/helper/schema/provider.go
index fb28b41..6cd325d 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/provider.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/provider.go
@@ -9,6 +9,7 @@ import (
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/config"
12 "github.com/hashicorp/terraform/config/configschema"
12 "github.com/hashicorp/terraform/terraform" 13 "github.com/hashicorp/terraform/terraform"
13) 14)
14 15
@@ -58,7 +59,7 @@ type Provider struct {
58 59
59 meta interface{} 60 meta interface{}
60 61
61 // a mutex is required because TestReset can directly repalce the stopCtx 62 // a mutex is required because TestReset can directly replace the stopCtx
62 stopMu sync.Mutex 63 stopMu sync.Mutex
63 stopCtx context.Context 64 stopCtx context.Context
64 stopCtxCancel context.CancelFunc 65 stopCtxCancel context.CancelFunc
@@ -185,6 +186,29 @@ func (p *Provider) TestReset() error {
185 return nil 186 return nil
186} 187}
187 188
189// GetSchema implementation of terraform.ResourceProvider interface
190func (p *Provider) GetSchema(req *terraform.ProviderSchemaRequest) (*terraform.ProviderSchema, error) {
191 resourceTypes := map[string]*configschema.Block{}
192 dataSources := map[string]*configschema.Block{}
193
194 for _, name := range req.ResourceTypes {
195 if r, exists := p.ResourcesMap[name]; exists {
196 resourceTypes[name] = r.CoreConfigSchema()
197 }
198 }
199 for _, name := range req.DataSources {
200 if r, exists := p.DataSourcesMap[name]; exists {
201 dataSources[name] = r.CoreConfigSchema()
202 }
203 }
204
205 return &terraform.ProviderSchema{
206 Provider: schemaMap(p.Schema).CoreConfigSchema(),
207 ResourceTypes: resourceTypes,
208 DataSources: dataSources,
209 }, nil
210}
211
188// Input implementation of terraform.ResourceProvider interface. 212// Input implementation of terraform.ResourceProvider interface.
189func (p *Provider) Input( 213func (p *Provider) Input(
190 input terraform.UIInput, 214 input terraform.UIInput,
@@ -227,7 +251,7 @@ func (p *Provider) Configure(c *terraform.ResourceConfig) error {
227 251
228 // Get a ResourceData for this configuration. To do this, we actually 252 // Get a ResourceData for this configuration. To do this, we actually
229 // generate an intermediary "diff" although that is never exposed. 253 // generate an intermediary "diff" although that is never exposed.
230 diff, err := sm.Diff(nil, c) 254 diff, err := sm.Diff(nil, c, nil, p.meta)
231 if err != nil { 255 if err != nil {
232 return err 256 return err
233 } 257 }
@@ -269,7 +293,7 @@ func (p *Provider) Diff(
269 return nil, fmt.Errorf("unknown resource type: %s", info.Type) 293 return nil, fmt.Errorf("unknown resource type: %s", info.Type)
270 } 294 }
271 295
272 return r.Diff(s, c) 296 return r.Diff(s, c, p.meta)
273} 297}
274 298
275// Refresh implementation of terraform.ResourceProvider interface. 299// Refresh implementation of terraform.ResourceProvider interface.
@@ -305,6 +329,10 @@ func (p *Provider) Resources() []terraform.ResourceType {
305 result = append(result, terraform.ResourceType{ 329 result = append(result, terraform.ResourceType{
306 Name: k, 330 Name: k,
307 Importable: resource.Importer != nil, 331 Importable: resource.Importer != nil,
332
333 // Indicates that a provider is compiled against a new enough
334 // version of core to support the GetSchema method.
335 SchemaAvailable: true,
308 }) 336 })
309 } 337 }
310 338
@@ -382,7 +410,7 @@ func (p *Provider) ReadDataDiff(
382 return nil, fmt.Errorf("unknown data source: %s", info.Type) 410 return nil, fmt.Errorf("unknown data source: %s", info.Type)
383 } 411 }
384 412
385 return r.Diff(nil, c) 413 return r.Diff(nil, c, p.meta)
386} 414}
387 415
388// RefreshData implementation of terraform.ResourceProvider interface. 416// RefreshData implementation of terraform.ResourceProvider interface.
@@ -410,6 +438,10 @@ func (p *Provider) DataSources() []terraform.DataSource {
410 for _, k := range keys { 438 for _, k := range keys {
411 result = append(result, terraform.DataSource{ 439 result = append(result, terraform.DataSource{
412 Name: k, 440 Name: k,
441
442 // Indicates that a provider is compiled against a new enough
443 // version of core to support the GetSchema method.
444 SchemaAvailable: true,
413 }) 445 })
414 } 446 }
415 447
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go b/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go
index 476192e..a8d42db 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/provisioner.go
@@ -146,7 +146,7 @@ func (p *Provisioner) Apply(
146 } 146 }
147 147
148 sm := schemaMap(p.ConnSchema) 148 sm := schemaMap(p.ConnSchema)
149 diff, err := sm.Diff(nil, terraform.NewResourceConfig(c)) 149 diff, err := sm.Diff(nil, terraform.NewResourceConfig(c), nil, nil)
150 if err != nil { 150 if err != nil {
151 return err 151 return err
152 } 152 }
@@ -160,7 +160,7 @@ func (p *Provisioner) Apply(
160 // Build the configuration data. Doing this requires making a "diff" 160 // Build the configuration data. Doing this requires making a "diff"
161 // even though that's never used. We use that just to get the correct types. 161 // even though that's never used. We use that just to get the correct types.
162 configMap := schemaMap(p.Schema) 162 configMap := schemaMap(p.Schema)
163 diff, err := configMap.Diff(nil, c) 163 diff, err := configMap.Diff(nil, c, nil, nil)
164 if err != nil { 164 if err != nil {
165 return err 165 return err
166 } 166 }
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/resource.go b/vendor/github.com/hashicorp/terraform/helper/schema/resource.go
index ddba109..d3be2d6 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/resource.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/resource.go
@@ -85,6 +85,37 @@ type Resource struct {
85 Delete DeleteFunc 85 Delete DeleteFunc
86 Exists ExistsFunc 86 Exists ExistsFunc
87 87
88 // CustomizeDiff is a custom function for working with the diff that
89 // Terraform has created for this resource - it can be used to customize the
90 // diff that has been created, diff values not controlled by configuration,
91 // or even veto the diff altogether and abort the plan. It is passed a
92 // *ResourceDiff, a structure similar to ResourceData but lacking most write
93 // functions like Set, while introducing new functions that work with the
94 // diff such as SetNew, SetNewComputed, and ForceNew.
95 //
96 // The phases Terraform runs this in, and the state available via functions
97 // like Get and GetChange, are as follows:
98 //
99 // * New resource: One run with no state
100 // * Existing resource: One run with state
101 // * Existing resource, forced new: One run with state (before ForceNew),
102 // then one run without state (as if new resource)
103 // * Tainted resource: No runs (custom diff logic is skipped)
104 // * Destroy: No runs (standard diff logic is skipped on destroy diffs)
105 //
106 // This function needs to be resilient to support all scenarios.
107 //
108 // If this function needs to access external API resources, remember to flag
109 // the RequiresRefresh attribute mentioned below to ensure that
110 // -refresh=false is blocked when running plan or apply, as this means that
111 // this resource requires refresh-like behaviour to work effectively.
112 //
113 // For the most part, only computed fields can be customized by this
114 // function.
115 //
116 // This function is only allowed on regular resources (not data sources).
117 CustomizeDiff CustomizeDiffFunc
118
88 // Importer is the ResourceImporter implementation for this resource. 119 // Importer is the ResourceImporter implementation for this resource.
89 // If this is nil, then this resource does not support importing. If 120 // If this is nil, then this resource does not support importing. If
90 // this is non-nil, then it supports importing and ResourceImporter 121 // this is non-nil, then it supports importing and ResourceImporter
@@ -93,9 +124,7 @@ type Resource struct {
93 Importer *ResourceImporter 124 Importer *ResourceImporter
94 125
95 // If non-empty, this string is emitted as a warning during Validate. 126 // If non-empty, this string is emitted as a warning during Validate.
96 // This is a private interface for now, for use by DataSourceResourceShim, 127 DeprecationMessage string
97 // and not for general use. (But maybe later...)
98 deprecationMessage string
99 128
100 // Timeouts allow users to specify specific time durations in which an 129 // Timeouts allow users to specify specific time durations in which an
101 // operation should time out, to allow them to extend an action to suit their 130 // operation should time out, to allow them to extend an action to suit their
@@ -126,6 +155,9 @@ type ExistsFunc func(*ResourceData, interface{}) (bool, error)
126type StateMigrateFunc func( 155type StateMigrateFunc func(
127 int, *terraform.InstanceState, interface{}) (*terraform.InstanceState, error) 156 int, *terraform.InstanceState, interface{}) (*terraform.InstanceState, error)
128 157
158// See Resource documentation.
159type CustomizeDiffFunc func(*ResourceDiff, interface{}) error
160
129// Apply creates, updates, and/or deletes a resource. 161// Apply creates, updates, and/or deletes a resource.
130func (r *Resource) Apply( 162func (r *Resource) Apply(
131 s *terraform.InstanceState, 163 s *terraform.InstanceState,
@@ -202,11 +234,11 @@ func (r *Resource) Apply(
202 return r.recordCurrentSchemaVersion(data.State()), err 234 return r.recordCurrentSchemaVersion(data.State()), err
203} 235}
204 236
205// Diff returns a diff of this resource and is API compatible with the 237// Diff returns a diff of this resource.
206// ResourceProvider interface.
207func (r *Resource) Diff( 238func (r *Resource) Diff(
208 s *terraform.InstanceState, 239 s *terraform.InstanceState,
209 c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { 240 c *terraform.ResourceConfig,
241 meta interface{}) (*terraform.InstanceDiff, error) {
210 242
211 t := &ResourceTimeout{} 243 t := &ResourceTimeout{}
212 err := t.ConfigDecode(r, c) 244 err := t.ConfigDecode(r, c)
@@ -215,7 +247,7 @@ func (r *Resource) Diff(
215 return nil, fmt.Errorf("[ERR] Error decoding timeout: %s", err) 247 return nil, fmt.Errorf("[ERR] Error decoding timeout: %s", err)
216 } 248 }
217 249
218 instanceDiff, err := schemaMap(r.Schema).Diff(s, c) 250 instanceDiff, err := schemaMap(r.Schema).Diff(s, c, r.CustomizeDiff, meta)
219 if err != nil { 251 if err != nil {
220 return instanceDiff, err 252 return instanceDiff, err
221 } 253 }
@@ -235,8 +267,8 @@ func (r *Resource) Diff(
235func (r *Resource) Validate(c *terraform.ResourceConfig) ([]string, []error) { 267func (r *Resource) Validate(c *terraform.ResourceConfig) ([]string, []error) {
236 warns, errs := schemaMap(r.Schema).Validate(c) 268 warns, errs := schemaMap(r.Schema).Validate(c)
237 269
238 if r.deprecationMessage != "" { 270 if r.DeprecationMessage != "" {
239 warns = append(warns, r.deprecationMessage) 271 warns = append(warns, r.DeprecationMessage)
240 } 272 }
241 273
242 return warns, errs 274 return warns, errs
@@ -248,7 +280,6 @@ func (r *Resource) ReadDataApply(
248 d *terraform.InstanceDiff, 280 d *terraform.InstanceDiff,
249 meta interface{}, 281 meta interface{},
250) (*terraform.InstanceState, error) { 282) (*terraform.InstanceState, error) {
251
252 // Data sources are always built completely from scratch 283 // Data sources are always built completely from scratch
253 // on each read, so the source state is always nil. 284 // on each read, so the source state is always nil.
254 data, err := schemaMap(r.Schema).Data(nil, d) 285 data, err := schemaMap(r.Schema).Data(nil, d)
@@ -346,6 +377,11 @@ func (r *Resource) InternalValidate(topSchemaMap schemaMap, writable bool) error
346 if r.Create != nil || r.Update != nil || r.Delete != nil { 377 if r.Create != nil || r.Update != nil || r.Delete != nil {
347 return fmt.Errorf("must not implement Create, Update or Delete") 378 return fmt.Errorf("must not implement Create, Update or Delete")
348 } 379 }
380
381 // CustomizeDiff cannot be defined for read-only resources
382 if r.CustomizeDiff != nil {
383 return fmt.Errorf("cannot implement CustomizeDiff")
384 }
349 } 385 }
350 386
351 tsm := topSchemaMap 387 tsm := topSchemaMap
@@ -393,19 +429,43 @@ func (r *Resource) InternalValidate(topSchemaMap schemaMap, writable bool) error
393 return err 429 return err
394 } 430 }
395 } 431 }
432
433 for k, f := range tsm {
434 if isReservedResourceFieldName(k, f) {
435 return fmt.Errorf("%s is a reserved field name", k)
436 }
437 }
396 } 438 }
397 439
398 // Resource-specific checks 440 // Data source
399 for k, _ := range tsm { 441 if r.isTopLevel() && !writable {
400 if isReservedResourceFieldName(k) { 442 tsm = schemaMap(r.Schema)
401 return fmt.Errorf("%s is a reserved field name for a resource", k) 443 for k, _ := range tsm {
444 if isReservedDataSourceFieldName(k) {
445 return fmt.Errorf("%s is a reserved field name", k)
446 }
402 } 447 }
403 } 448 }
404 449
405 return schemaMap(r.Schema).InternalValidate(tsm) 450 return schemaMap(r.Schema).InternalValidate(tsm)
406} 451}
407 452
408func isReservedResourceFieldName(name string) bool { 453func isReservedDataSourceFieldName(name string) bool {
454 for _, reservedName := range config.ReservedDataSourceFields {
455 if name == reservedName {
456 return true
457 }
458 }
459 return false
460}
461
462func isReservedResourceFieldName(name string, s *Schema) bool {
463 // Allow phasing out "id"
464 // See https://github.com/terraform-providers/terraform-provider-aws/pull/1626#issuecomment-328881415
465 if name == "id" && (s.Deprecated != "" || s.Removed != "") {
466 return false
467 }
468
409 for _, reservedName := range config.ReservedResourceFields { 469 for _, reservedName := range config.ReservedResourceFields {
410 if name == reservedName { 470 if name == reservedName {
411 return true 471 return true
@@ -430,6 +490,12 @@ func (r *Resource) Data(s *terraform.InstanceState) *ResourceData {
430 panic(err) 490 panic(err)
431 } 491 }
432 492
493 // load the Resource timeouts
494 result.timeouts = r.Timeouts
495 if result.timeouts == nil {
496 result.timeouts = &ResourceTimeout{}
497 }
498
433 // Set the schema version to latest by default 499 // Set the schema version to latest by default
434 result.meta = map[string]interface{}{ 500 result.meta = map[string]interface{}{
435 "schema_version": strconv.Itoa(r.SchemaVersion), 501 "schema_version": strconv.Itoa(r.SchemaVersion),
@@ -450,7 +516,7 @@ func (r *Resource) TestResourceData() *ResourceData {
450// Returns true if the resource is "top level" i.e. not a sub-resource. 516// Returns true if the resource is "top level" i.e. not a sub-resource.
451func (r *Resource) isTopLevel() bool { 517func (r *Resource) isTopLevel() bool {
452 // TODO: This is a heuristic; replace with a definitive attribute? 518 // TODO: This is a heuristic; replace with a definitive attribute?
453 return r.Create != nil 519 return (r.Create != nil || r.Read != nil)
454} 520}
455 521
456// Determines if a given InstanceState needs to be migrated by checking the 522// Determines if a given InstanceState needs to be migrated by checking the
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/resource_data.go b/vendor/github.com/hashicorp/terraform/helper/schema/resource_data.go
index b2bc8f6..6cc01ee 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/resource_data.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/resource_data.go
@@ -35,6 +35,8 @@ type ResourceData struct {
35 partialMap map[string]struct{} 35 partialMap map[string]struct{}
36 once sync.Once 36 once sync.Once
37 isNew bool 37 isNew bool
38
39 panicOnError bool
38} 40}
39 41
40// getResult is the internal structure that is generated when a Get 42// getResult is the internal structure that is generated when a Get
@@ -104,6 +106,22 @@ func (d *ResourceData) GetOk(key string) (interface{}, bool) {
104 return r.Value, exists 106 return r.Value, exists
105} 107}
106 108
109// GetOkExists returns the data for a given key and whether or not the key
110// has been set to a non-zero value. This is only useful for determining
111// if boolean attributes have been set, if they are Optional but do not
112// have a Default value.
113//
114// This is nearly the same function as GetOk, yet it does not check
115// for the zero value of the attribute's type. This allows for attributes
116// without a default, to fully check for a literal assignment, regardless
117// of the zero-value for that type.
118// This should only be used if absolutely required/needed.
119func (d *ResourceData) GetOkExists(key string) (interface{}, bool) {
120 r := d.getRaw(key, getSourceSet)
121 exists := r.Exists && !r.Computed
122 return r.Value, exists
123}
124
107func (d *ResourceData) getRaw(key string, level getSource) getResult { 125func (d *ResourceData) getRaw(key string, level getSource) getResult {
108 var parts []string 126 var parts []string
109 if key != "" { 127 if key != "" {
@@ -168,7 +186,11 @@ func (d *ResourceData) Set(key string, value interface{}) error {
168 } 186 }
169 } 187 }
170 188
171 return d.setWriter.WriteField(strings.Split(key, "."), value) 189 err := d.setWriter.WriteField(strings.Split(key, "."), value)
190 if err != nil && d.panicOnError {
191 panic(err)
192 }
193 return err
172} 194}
173 195
174// SetPartial adds the key to the final state output while 196// SetPartial adds the key to the final state output while
@@ -293,6 +315,7 @@ func (d *ResourceData) State() *terraform.InstanceState {
293 315
294 mapW := &MapFieldWriter{Schema: d.schema} 316 mapW := &MapFieldWriter{Schema: d.schema}
295 if err := mapW.WriteField(nil, rawMap); err != nil { 317 if err := mapW.WriteField(nil, rawMap); err != nil {
318 log.Printf("[ERR] Error writing fields: %s", err)
296 return nil 319 return nil
297 } 320 }
298 321
@@ -344,6 +367,13 @@ func (d *ResourceData) State() *terraform.InstanceState {
344func (d *ResourceData) Timeout(key string) time.Duration { 367func (d *ResourceData) Timeout(key string) time.Duration {
345 key = strings.ToLower(key) 368 key = strings.ToLower(key)
346 369
370 // System default of 20 minutes
371 defaultTimeout := 20 * time.Minute
372
373 if d.timeouts == nil {
374 return defaultTimeout
375 }
376
347 var timeout *time.Duration 377 var timeout *time.Duration
348 switch key { 378 switch key {
349 case TimeoutCreate: 379 case TimeoutCreate:
@@ -364,8 +394,7 @@ func (d *ResourceData) Timeout(key string) time.Duration {
364 return *d.timeouts.Default 394 return *d.timeouts.Default
365 } 395 }
366 396
367 // Return system default of 20 minutes 397 return defaultTimeout
368 return 20 * time.Minute
369} 398}
370 399
371func (d *ResourceData) init() { 400func (d *ResourceData) init() {
@@ -423,7 +452,7 @@ func (d *ResourceData) init() {
423} 452}
424 453
425func (d *ResourceData) diffChange( 454func (d *ResourceData) diffChange(
426 k string) (interface{}, interface{}, bool, bool) { 455 k string) (interface{}, interface{}, bool, bool, bool) {
427 // Get the change between the state and the config. 456 // Get the change between the state and the config.
428 o, n := d.getChange(k, getSourceState, getSourceConfig|getSourceExact) 457 o, n := d.getChange(k, getSourceState, getSourceConfig|getSourceExact)
429 if !o.Exists { 458 if !o.Exists {
@@ -434,7 +463,7 @@ func (d *ResourceData) diffChange(
434 } 463 }
435 464
436 // Return the old, new, and whether there is a change 465 // Return the old, new, and whether there is a change
437 return o.Value, n.Value, !reflect.DeepEqual(o.Value, n.Value), n.Computed 466 return o.Value, n.Value, !reflect.DeepEqual(o.Value, n.Value), n.Computed, false
438} 467}
439 468
440func (d *ResourceData) getChange( 469func (d *ResourceData) getChange(
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/resource_diff.go b/vendor/github.com/hashicorp/terraform/helper/schema/resource_diff.go
new file mode 100644
index 0000000..7db3dec
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/resource_diff.go
@@ -0,0 +1,559 @@
1package schema
2
3import (
4 "errors"
5 "fmt"
6 "reflect"
7 "strings"
8 "sync"
9
10 "github.com/hashicorp/terraform/terraform"
11)
12
13// newValueWriter is a minor re-implementation of MapFieldWriter to include
14// keys that should be marked as computed, to represent the new part of a
15// pseudo-diff.
16type newValueWriter struct {
17 *MapFieldWriter
18
19 // A list of keys that should be marked as computed.
20 computedKeys map[string]bool
21
22 // A lock to prevent races on writes. The underlying writer will have one as
23 // well - this is for computed keys.
24 lock sync.Mutex
25
26 // To be used with init.
27 once sync.Once
28}
29
30// init performs any initialization tasks for the newValueWriter.
31func (w *newValueWriter) init() {
32 if w.computedKeys == nil {
33 w.computedKeys = make(map[string]bool)
34 }
35}
36
37// WriteField overrides MapValueWriter's WriteField, adding the ability to flag
38// the address as computed.
39func (w *newValueWriter) WriteField(address []string, value interface{}, computed bool) error {
40 // Fail the write if we have a non-nil value and computed is true.
41 // NewComputed values should not have a value when written.
42 if value != nil && computed {
43 return errors.New("Non-nil value with computed set")
44 }
45
46 if err := w.MapFieldWriter.WriteField(address, value); err != nil {
47 return err
48 }
49
50 w.once.Do(w.init)
51
52 w.lock.Lock()
53 defer w.lock.Unlock()
54 if computed {
55 w.computedKeys[strings.Join(address, ".")] = true
56 }
57 return nil
58}
59
60// ComputedKeysMap returns the underlying computed keys map.
61func (w *newValueWriter) ComputedKeysMap() map[string]bool {
62 w.once.Do(w.init)
63 return w.computedKeys
64}
65
66// newValueReader is a minor re-implementation of MapFieldReader and is the
67// read counterpart to MapValueWriter, allowing the read of keys flagged as
68// computed to accommodate the diff override logic in ResourceDiff.
69type newValueReader struct {
70 *MapFieldReader
71
72 // The list of computed keys from a newValueWriter.
73 computedKeys map[string]bool
74}
75
76// ReadField reads the values from the underlying writer, returning the
77// computed value if it is found as well.
78func (r *newValueReader) ReadField(address []string) (FieldReadResult, error) {
79 addrKey := strings.Join(address, ".")
80 v, err := r.MapFieldReader.ReadField(address)
81 if err != nil {
82 return FieldReadResult{}, err
83 }
84 for computedKey := range r.computedKeys {
85 if childAddrOf(addrKey, computedKey) {
86 if strings.HasSuffix(addrKey, ".#") {
87 // This is a count value for a list or set that has been marked as
88 // computed, or a sub-list/sub-set of a complex resource that has
89 // been marked as computed. We need to pass through to other readers
90 // so that an accurate previous count can be fetched for the diff.
91 v.Exists = false
92 }
93 v.Computed = true
94 }
95 }
96
97 return v, nil
98}
99
100// ResourceDiff is used to query and make custom changes to an in-flight diff.
101// It can be used to veto particular changes in the diff, customize the diff
102// that has been created, or diff values not controlled by config.
103//
104// The object functions similar to ResourceData, however most notably lacks
105// Set, SetPartial, and Partial, as it should be used to change diff values
106// only. Most other first-class ResourceData functions exist, namely Get,
107// GetOk, HasChange, and GetChange exist.
108//
109// All functions in ResourceDiff, save for ForceNew, can only be used on
110// computed fields.
111type ResourceDiff struct {
112 // The schema for the resource being worked on.
113 schema map[string]*Schema
114
115 // The current config for this resource.
116 config *terraform.ResourceConfig
117
118 // The state for this resource as it exists post-refresh, after the initial
119 // diff.
120 state *terraform.InstanceState
121
122 // The diff created by Terraform. This diff is used, along with state,
123 // config, and custom-set diff data, to provide a multi-level reader
124 // experience similar to ResourceData.
125 diff *terraform.InstanceDiff
126
127 // The internal reader structure that contains the state, config, the default
128 // diff, and the new diff.
129 multiReader *MultiLevelFieldReader
130
131 // A writer that writes overridden new fields.
132 newWriter *newValueWriter
133
134 // Tracks which keys have been updated by ResourceDiff to ensure that the
135 // diff does not get re-run on keys that were not touched, or diffs that were
136 // just removed (re-running on the latter would just roll back the removal).
137 updatedKeys map[string]bool
138
139 // Tracks which keys were flagged as forceNew. These keys are not saved in
140 // newWriter, but we need to track them so that they can be re-diffed later.
141 forcedNewKeys map[string]bool
142}
143
144// newResourceDiff creates a new ResourceDiff instance.
145func newResourceDiff(schema map[string]*Schema, config *terraform.ResourceConfig, state *terraform.InstanceState, diff *terraform.InstanceDiff) *ResourceDiff {
146 d := &ResourceDiff{
147 config: config,
148 state: state,
149 diff: diff,
150 schema: schema,
151 }
152
153 d.newWriter = &newValueWriter{
154 MapFieldWriter: &MapFieldWriter{Schema: d.schema},
155 }
156 readers := make(map[string]FieldReader)
157 var stateAttributes map[string]string
158 if d.state != nil {
159 stateAttributes = d.state.Attributes
160 readers["state"] = &MapFieldReader{
161 Schema: d.schema,
162 Map: BasicMapReader(stateAttributes),
163 }
164 }
165 if d.config != nil {
166 readers["config"] = &ConfigFieldReader{
167 Schema: d.schema,
168 Config: d.config,
169 }
170 }
171 if d.diff != nil {
172 readers["diff"] = &DiffFieldReader{
173 Schema: d.schema,
174 Diff: d.diff,
175 Source: &MultiLevelFieldReader{
176 Levels: []string{"state", "config"},
177 Readers: readers,
178 },
179 }
180 }
181 readers["newDiff"] = &newValueReader{
182 MapFieldReader: &MapFieldReader{
183 Schema: d.schema,
184 Map: BasicMapReader(d.newWriter.Map()),
185 },
186 computedKeys: d.newWriter.ComputedKeysMap(),
187 }
188 d.multiReader = &MultiLevelFieldReader{
189 Levels: []string{
190 "state",
191 "config",
192 "diff",
193 "newDiff",
194 },
195
196 Readers: readers,
197 }
198
199 d.updatedKeys = make(map[string]bool)
200 d.forcedNewKeys = make(map[string]bool)
201
202 return d
203}
204
205// UpdatedKeys returns the keys that were updated by this ResourceDiff run.
206// These are the only keys that a diff should be re-calculated for.
207//
208// This is the combined result of both keys for which diff values were updated
209// for or cleared, and also keys that were flagged to be re-diffed as a result
210// of ForceNew.
211func (d *ResourceDiff) UpdatedKeys() []string {
212 var s []string
213 for k := range d.updatedKeys {
214 s = append(s, k)
215 }
216 for k := range d.forcedNewKeys {
217 for _, l := range s {
218 if k == l {
219 break
220 }
221 }
222 s = append(s, k)
223 }
224 return s
225}
226
227// Clear wipes the diff for a particular key. It is called by ResourceDiff's
228// functionality to remove any possibility of conflicts, but can be called on
229// its own to just remove a specific key from the diff completely.
230//
231// Note that this does not wipe an override. This function is only allowed on
232// computed keys.
233func (d *ResourceDiff) Clear(key string) error {
234 if err := d.checkKey(key, "Clear", true); err != nil {
235 return err
236 }
237
238 return d.clear(key)
239}
240
241func (d *ResourceDiff) clear(key string) error {
242 // Check the schema to make sure that this key exists first.
243 schemaL := addrToSchema(strings.Split(key, "."), d.schema)
244 if len(schemaL) == 0 {
245 return fmt.Errorf("%s is not a valid key", key)
246 }
247
248 for k := range d.diff.Attributes {
249 if strings.HasPrefix(k, key) {
250 delete(d.diff.Attributes, k)
251 }
252 }
253 return nil
254}
255
256// GetChangedKeysPrefix helps to implement Resource.CustomizeDiff
257// where we need to act on all nested fields
258// without calling out each one separately
259func (d *ResourceDiff) GetChangedKeysPrefix(prefix string) []string {
260 keys := make([]string, 0)
261 for k := range d.diff.Attributes {
262 if strings.HasPrefix(k, prefix) {
263 keys = append(keys, k)
264 }
265 }
266 return keys
267}
268
269// diffChange helps to implement resourceDiffer and derives its change values
270// from ResourceDiff's own change data, in addition to existing diff, config, and state.
271func (d *ResourceDiff) diffChange(key string) (interface{}, interface{}, bool, bool, bool) {
272 old, new, customized := d.getChange(key)
273
274 if !old.Exists {
275 old.Value = nil
276 }
277 if !new.Exists || d.removed(key) {
278 new.Value = nil
279 }
280
281 return old.Value, new.Value, !reflect.DeepEqual(old.Value, new.Value), new.Computed, customized
282}
283
284// SetNew is used to set a new diff value for the mentioned key. The value must
285// be correct for the attribute's schema (mostly relevant for maps, lists, and
286// sets). The original value from the state is used as the old value.
287//
288// This function is only allowed on computed attributes.
289func (d *ResourceDiff) SetNew(key string, value interface{}) error {
290 if err := d.checkKey(key, "SetNew", false); err != nil {
291 return err
292 }
293
294 return d.setDiff(key, value, false)
295}
296
297// SetNewComputed functions like SetNew, except that it blanks out a new value
298// and marks it as computed.
299//
300// This function is only allowed on computed attributes.
301func (d *ResourceDiff) SetNewComputed(key string) error {
302 if err := d.checkKey(key, "SetNewComputed", false); err != nil {
303 return err
304 }
305
306 return d.setDiff(key, nil, true)
307}
308
309// setDiff performs common diff setting behaviour.
310func (d *ResourceDiff) setDiff(key string, new interface{}, computed bool) error {
311 if err := d.clear(key); err != nil {
312 return err
313 }
314
315 if err := d.newWriter.WriteField(strings.Split(key, "."), new, computed); err != nil {
316 return fmt.Errorf("Cannot set new diff value for key %s: %s", key, err)
317 }
318
319 d.updatedKeys[key] = true
320
321 return nil
322}
323
324// ForceNew force-flags ForceNew in the schema for a specific key, and
325// re-calculates its diff, effectively causing this attribute to force a new
326// resource.
327//
328// Keep in mind that forcing a new resource will force a second run of the
329// resource's CustomizeDiff function (with a new ResourceDiff) once the current
330// one has completed. This second run is performed without state. This behavior
331// will be the same as if a new resource is being created and is performed to
332// ensure that the diff looks like the diff for a new resource as much as
333// possible. CustomizeDiff should expect such a scenario and act correctly.
334//
335// This function is a no-op/error if there is no diff.
336//
337// Note that the change to schema is permanent for the lifecycle of this
338// specific ResourceDiff instance.
339func (d *ResourceDiff) ForceNew(key string) error {
340 if !d.HasChange(key) {
341 return fmt.Errorf("ForceNew: No changes for %s", key)
342 }
343
344 keyParts := strings.Split(key, ".")
345 var schema *Schema
346 schemaL := addrToSchema(keyParts, d.schema)
347 if len(schemaL) > 0 {
348 schema = schemaL[len(schemaL)-1]
349 } else {
350 return fmt.Errorf("ForceNew: %s is not a valid key", key)
351 }
352
353 schema.ForceNew = true
354
355 // Flag this for a re-diff. Don't save any values to guarantee that existing
356 // diffs aren't messed with, as this gets messy when dealing with complex
357 // structures, zero values, etc.
358 d.forcedNewKeys[keyParts[0]] = true
359
360 return nil
361}
362
363// Get hands off to ResourceData.Get.
364func (d *ResourceDiff) Get(key string) interface{} {
365 r, _ := d.GetOk(key)
366 return r
367}
368
369// GetChange gets the change between the state and diff, checking first to see
370// if a overridden diff exists.
371//
372// This implementation differs from ResourceData's in the way that we first get
373// results from the exact levels for the new diff, then from state and diff as
374// per normal.
375func (d *ResourceDiff) GetChange(key string) (interface{}, interface{}) {
376 old, new, _ := d.getChange(key)
377 return old.Value, new.Value
378}
379
380// GetOk functions the same way as ResourceData.GetOk, but it also checks the
381// new diff levels to provide data consistent with the current state of the
382// customized diff.
383func (d *ResourceDiff) GetOk(key string) (interface{}, bool) {
384 r := d.get(strings.Split(key, "."), "newDiff")
385 exists := r.Exists && !r.Computed
386 if exists {
387 // If it exists, we also want to verify it is not the zero-value.
388 value := r.Value
389 zero := r.Schema.Type.Zero()
390
391 if eq, ok := value.(Equal); ok {
392 exists = !eq.Equal(zero)
393 } else {
394 exists = !reflect.DeepEqual(value, zero)
395 }
396 }
397
398 return r.Value, exists
399}
400
401// GetOkExists functions the same way as GetOkExists within ResourceData, but
402// it also checks the new diff levels to provide data consistent with the
403// current state of the customized diff.
404//
405// This is nearly the same function as GetOk, yet it does not check
406// for the zero value of the attribute's type. This allows for attributes
407// without a default, to fully check for a literal assignment, regardless
408// of the zero-value for that type.
409func (d *ResourceDiff) GetOkExists(key string) (interface{}, bool) {
410 r := d.get(strings.Split(key, "."), "newDiff")
411 exists := r.Exists && !r.Computed
412 return r.Value, exists
413}
414
415// NewValueKnown returns true if the new value for the given key is available
416// as its final value at diff time. If the return value is false, this means
417// either the value is based of interpolation that was unavailable at diff
418// time, or that the value was explicitly marked as computed by SetNewComputed.
419func (d *ResourceDiff) NewValueKnown(key string) bool {
420 r := d.get(strings.Split(key, "."), "newDiff")
421 return !r.Computed
422}
423
424// HasChange checks to see if there is a change between state and the diff, or
425// in the overridden diff.
426func (d *ResourceDiff) HasChange(key string) bool {
427 old, new := d.GetChange(key)
428
429 // If the type implements the Equal interface, then call that
430 // instead of just doing a reflect.DeepEqual. An example where this is
431 // needed is *Set
432 if eq, ok := old.(Equal); ok {
433 return !eq.Equal(new)
434 }
435
436 return !reflect.DeepEqual(old, new)
437}
438
439// Id returns the ID of this resource.
440//
441// Note that technically, ID does not change during diffs (it either has
442// already changed in the refresh, or will change on update), hence we do not
443// support updating the ID or fetching it from anything else other than state.
444func (d *ResourceDiff) Id() string {
445 var result string
446
447 if d.state != nil {
448 result = d.state.ID
449 }
450 return result
451}
452
453// getChange gets values from two different levels, designed for use in
454// diffChange, HasChange, and GetChange.
455//
456// This implementation differs from ResourceData's in the way that we first get
457// results from the exact levels for the new diff, then from state and diff as
458// per normal.
459func (d *ResourceDiff) getChange(key string) (getResult, getResult, bool) {
460 old := d.get(strings.Split(key, "."), "state")
461 var new getResult
462 for p := range d.updatedKeys {
463 if childAddrOf(key, p) {
464 new = d.getExact(strings.Split(key, "."), "newDiff")
465 return old, new, true
466 }
467 }
468 new = d.get(strings.Split(key, "."), "newDiff")
469 return old, new, false
470}
471
472// removed checks to see if the key is present in the existing, pre-customized
473// diff and if it was marked as NewRemoved.
474func (d *ResourceDiff) removed(k string) bool {
475 diff, ok := d.diff.Attributes[k]
476 if !ok {
477 return false
478 }
479 return diff.NewRemoved
480}
481
482// get performs the appropriate multi-level reader logic for ResourceDiff,
483// starting at source. Refer to newResourceDiff for the level order.
484func (d *ResourceDiff) get(addr []string, source string) getResult {
485 result, err := d.multiReader.ReadFieldMerge(addr, source)
486 if err != nil {
487 panic(err)
488 }
489
490 return d.finalizeResult(addr, result)
491}
492
493// getExact gets an attribute from the exact level referenced by source.
494func (d *ResourceDiff) getExact(addr []string, source string) getResult {
495 result, err := d.multiReader.ReadFieldExact(addr, source)
496 if err != nil {
497 panic(err)
498 }
499
500 return d.finalizeResult(addr, result)
501}
502
503// finalizeResult does some post-processing of the result produced by get and getExact.
504func (d *ResourceDiff) finalizeResult(addr []string, result FieldReadResult) getResult {
505 // If the result doesn't exist, then we set the value to the zero value
506 var schema *Schema
507 if schemaL := addrToSchema(addr, d.schema); len(schemaL) > 0 {
508 schema = schemaL[len(schemaL)-1]
509 }
510
511 if result.Value == nil && schema != nil {
512 result.Value = result.ValueOrZero(schema)
513 }
514
515 // Transform the FieldReadResult into a getResult. It might be worth
516 // merging these two structures one day.
517 return getResult{
518 Value: result.Value,
519 ValueProcessed: result.ValueProcessed,
520 Computed: result.Computed,
521 Exists: result.Exists,
522 Schema: schema,
523 }
524}
525
526// childAddrOf does a comparison of two addresses to see if one is the child of
527// the other.
528func childAddrOf(child, parent string) bool {
529 cs := strings.Split(child, ".")
530 ps := strings.Split(parent, ".")
531 if len(ps) > len(cs) {
532 return false
533 }
534 return reflect.DeepEqual(ps, cs[:len(ps)])
535}
536
537// checkKey checks the key to make sure it exists and is computed.
538func (d *ResourceDiff) checkKey(key, caller string, nested bool) error {
539 var schema *Schema
540 if nested {
541 keyParts := strings.Split(key, ".")
542 schemaL := addrToSchema(keyParts, d.schema)
543 if len(schemaL) > 0 {
544 schema = schemaL[len(schemaL)-1]
545 }
546 } else {
547 s, ok := d.schema[key]
548 if ok {
549 schema = s
550 }
551 }
552 if schema == nil {
553 return fmt.Errorf("%s: invalid key: %s", caller, key)
554 }
555 if !schema.Computed {
556 return fmt.Errorf("%s only operates on computed keys - %s is not one", caller, key)
557 }
558 return nil
559}
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/schema.go b/vendor/github.com/hashicorp/terraform/helper/schema/schema.go
index acb5618..0ea5aad 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/schema.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/schema.go
@@ -21,9 +21,13 @@ import (
21 "strings" 21 "strings"
22 22
23 "github.com/hashicorp/terraform/terraform" 23 "github.com/hashicorp/terraform/terraform"
24 "github.com/mitchellh/copystructure"
24 "github.com/mitchellh/mapstructure" 25 "github.com/mitchellh/mapstructure"
25) 26)
26 27
28// Name of ENV variable which (if not empty) prefers panic over error
29const PanicOnErr = "TF_SCHEMA_PANIC_ON_ERROR"
30
27// type used for schema package context keys 31// type used for schema package context keys
28type contextKey string 32type contextKey string
29 33
@@ -116,12 +120,16 @@ type Schema struct {
116 ForceNew bool 120 ForceNew bool
117 StateFunc SchemaStateFunc 121 StateFunc SchemaStateFunc
118 122
119 // The following fields are only set for a TypeList or TypeSet Type. 123 // The following fields are only set for a TypeList, TypeSet, or TypeMap.
120 // 124 //
121 // Elem must be either a *Schema or a *Resource only if the Type is 125 // Elem represents the element type. For a TypeMap, it must be a *Schema
122 // TypeList, and represents what the element type is. If it is *Schema, 126 // with a Type of TypeString, otherwise it may be either a *Schema or a
123 // the element type is just a simple value. If it is *Resource, the 127 // *Resource. If it is *Schema, the element type is just a simple value.
124 // element type is a complex structure, potentially with its own lifecycle. 128 // If it is *Resource, the element type is a complex structure,
129 // potentially with its own lifecycle.
130 Elem interface{}
131
132 // The following fields are only set for a TypeList or TypeSet.
125 // 133 //
126 // MaxItems defines a maximum amount of items that can exist within a 134 // MaxItems defines a maximum amount of items that can exist within a
127 // TypeSet or TypeList. Specific use cases would be if a TypeSet is being 135 // TypeSet or TypeList. Specific use cases would be if a TypeSet is being
@@ -138,7 +146,6 @@ type Schema struct {
138 // ["foo"] automatically. This is primarily for legacy reasons and the 146 // ["foo"] automatically. This is primarily for legacy reasons and the
139 // ambiguity is not recommended for new usage. Promotion is only allowed 147 // ambiguity is not recommended for new usage. Promotion is only allowed
140 // for primitive element types. 148 // for primitive element types.
141 Elem interface{}
142 MaxItems int 149 MaxItems int
143 MinItems int 150 MinItems int
144 PromoteSingle bool 151 PromoteSingle bool
@@ -192,7 +199,7 @@ type Schema struct {
192 Sensitive bool 199 Sensitive bool
193} 200}
194 201
195// SchemaDiffSuppresFunc is a function which can be used to determine 202// SchemaDiffSuppressFunc is a function which can be used to determine
196// whether a detected diff on a schema element is "valid" or not, and 203// whether a detected diff on a schema element is "valid" or not, and
197// suppress it from the plan if necessary. 204// suppress it from the plan if necessary.
198// 205//
@@ -289,8 +296,7 @@ func (s *Schema) ZeroValue() interface{} {
289 } 296 }
290} 297}
291 298
292func (s *Schema) finalizeDiff( 299func (s *Schema) finalizeDiff(d *terraform.ResourceAttrDiff, customized bool) *terraform.ResourceAttrDiff {
293 d *terraform.ResourceAttrDiff) *terraform.ResourceAttrDiff {
294 if d == nil { 300 if d == nil {
295 return d 301 return d
296 } 302 }
@@ -331,13 +337,20 @@ func (s *Schema) finalizeDiff(
331 } 337 }
332 338
333 if s.Computed { 339 if s.Computed {
334 if d.Old != "" && d.New == "" { 340 // FIXME: This is where the customized bool from getChange finally
335 // This is a computed value with an old value set already, 341 // comes into play. It allows the previously incorrect behavior
336 // just let it go. 342 // of an empty string being used as "unset" when the value is
337 return nil 343 // computed. This should be removed once we can properly
344 // represent an unset/nil value from the configuration.
345 if !customized {
346 if d.Old != "" && d.New == "" {
347 // This is a computed value with an old value set already,
348 // just let it go.
349 return nil
350 }
338 } 351 }
339 352
340 if d.New == "" { 353 if d.New == "" && !d.NewComputed {
341 // Computed attribute without a new value set 354 // Computed attribute without a new value set
342 d.NewComputed = true 355 d.NewComputed = true
343 } 356 }
@@ -354,6 +367,13 @@ func (s *Schema) finalizeDiff(
354// schemaMap is a wrapper that adds nice functions on top of schemas. 367// schemaMap is a wrapper that adds nice functions on top of schemas.
355type schemaMap map[string]*Schema 368type schemaMap map[string]*Schema
356 369
370func (m schemaMap) panicOnError() bool {
371 if os.Getenv(PanicOnErr) != "" {
372 return true
373 }
374 return false
375}
376
357// Data returns a ResourceData for the given schema, state, and diff. 377// Data returns a ResourceData for the given schema, state, and diff.
358// 378//
359// The diff is optional. 379// The diff is optional.
@@ -361,17 +381,30 @@ func (m schemaMap) Data(
361 s *terraform.InstanceState, 381 s *terraform.InstanceState,
362 d *terraform.InstanceDiff) (*ResourceData, error) { 382 d *terraform.InstanceDiff) (*ResourceData, error) {
363 return &ResourceData{ 383 return &ResourceData{
364 schema: m, 384 schema: m,
365 state: s, 385 state: s,
366 diff: d, 386 diff: d,
387 panicOnError: m.panicOnError(),
367 }, nil 388 }, nil
368} 389}
369 390
391// DeepCopy returns a copy of this schemaMap. The copy can be safely modified
392// without affecting the original.
393func (m *schemaMap) DeepCopy() schemaMap {
394 copy, err := copystructure.Config{Lock: true}.Copy(m)
395 if err != nil {
396 panic(err)
397 }
398 return *copy.(*schemaMap)
399}
400
370// Diff returns the diff for a resource given the schema map, 401// Diff returns the diff for a resource given the schema map,
371// state, and configuration. 402// state, and configuration.
372func (m schemaMap) Diff( 403func (m schemaMap) Diff(
373 s *terraform.InstanceState, 404 s *terraform.InstanceState,
374 c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { 405 c *terraform.ResourceConfig,
406 customizeDiff CustomizeDiffFunc,
407 meta interface{}) (*terraform.InstanceDiff, error) {
375 result := new(terraform.InstanceDiff) 408 result := new(terraform.InstanceDiff)
376 result.Attributes = make(map[string]*terraform.ResourceAttrDiff) 409 result.Attributes = make(map[string]*terraform.ResourceAttrDiff)
377 410
@@ -381,9 +414,10 @@ func (m schemaMap) Diff(
381 } 414 }
382 415
383 d := &ResourceData{ 416 d := &ResourceData{
384 schema: m, 417 schema: m,
385 state: s, 418 state: s,
386 config: c, 419 config: c,
420 panicOnError: m.panicOnError(),
387 } 421 }
388 422
389 for k, schema := range m { 423 for k, schema := range m {
@@ -393,6 +427,29 @@ func (m schemaMap) Diff(
393 } 427 }
394 } 428 }
395 429
430 // Remove any nil diffs just to keep things clean
431 for k, v := range result.Attributes {
432 if v == nil {
433 delete(result.Attributes, k)
434 }
435 }
436
437 // If this is a non-destroy diff, call any custom diff logic that has been
438 // defined.
439 if !result.DestroyTainted && customizeDiff != nil {
440 mc := m.DeepCopy()
441 rd := newResourceDiff(mc, c, s, result)
442 if err := customizeDiff(rd, meta); err != nil {
443 return nil, err
444 }
445 for _, k := range rd.UpdatedKeys() {
446 err := m.diff(k, mc[k], result, rd, false)
447 if err != nil {
448 return nil, err
449 }
450 }
451 }
452
396 // If the diff requires a new resource, then we recompute the diff 453 // If the diff requires a new resource, then we recompute the diff
397 // so we have the complete new resource diff, and preserve the 454 // so we have the complete new resource diff, and preserve the
398 // RequiresNew fields where necessary so the user knows exactly what 455 // RequiresNew fields where necessary so the user knows exactly what
@@ -418,6 +475,21 @@ func (m schemaMap) Diff(
418 } 475 }
419 } 476 }
420 477
478 // Re-run customization
479 if !result2.DestroyTainted && customizeDiff != nil {
480 mc := m.DeepCopy()
481 rd := newResourceDiff(mc, c, d.state, result2)
482 if err := customizeDiff(rd, meta); err != nil {
483 return nil, err
484 }
485 for _, k := range rd.UpdatedKeys() {
486 err := m.diff(k, mc[k], result2, rd, false)
487 if err != nil {
488 return nil, err
489 }
490 }
491 }
492
421 // Force all the fields to not force a new since we know what we 493 // Force all the fields to not force a new since we know what we
422 // want to force new. 494 // want to force new.
423 for k, attr := range result2.Attributes { 495 for k, attr := range result2.Attributes {
@@ -456,13 +528,6 @@ func (m schemaMap) Diff(
456 result = result2 528 result = result2
457 } 529 }
458 530
459 // Remove any nil diffs just to keep things clean
460 for k, v := range result.Attributes {
461 if v == nil {
462 delete(result.Attributes, k)
463 }
464 }
465
466 // Go through and detect all of the ComputedWhens now that we've 531 // Go through and detect all of the ComputedWhens now that we've
467 // finished the diff. 532 // finished the diff.
468 // TODO 533 // TODO
@@ -681,11 +746,23 @@ func isValidFieldName(name string) bool {
681 return re.MatchString(name) 746 return re.MatchString(name)
682} 747}
683 748
749// resourceDiffer is an interface that is used by the private diff functions.
750// This helps facilitate diff logic for both ResourceData and ResoureDiff with
751// minimal divergence in code.
752type resourceDiffer interface {
753 diffChange(string) (interface{}, interface{}, bool, bool, bool)
754 Get(string) interface{}
755 GetChange(string) (interface{}, interface{})
756 GetOk(string) (interface{}, bool)
757 HasChange(string) bool
758 Id() string
759}
760
684func (m schemaMap) diff( 761func (m schemaMap) diff(
685 k string, 762 k string,
686 schema *Schema, 763 schema *Schema,
687 diff *terraform.InstanceDiff, 764 diff *terraform.InstanceDiff,
688 d *ResourceData, 765 d resourceDiffer,
689 all bool) error { 766 all bool) error {
690 767
691 unsupressedDiff := new(terraform.InstanceDiff) 768 unsupressedDiff := new(terraform.InstanceDiff)
@@ -706,12 +783,14 @@ func (m schemaMap) diff(
706 } 783 }
707 784
708 for attrK, attrV := range unsupressedDiff.Attributes { 785 for attrK, attrV := range unsupressedDiff.Attributes {
709 if schema.DiffSuppressFunc != nil && 786 switch rd := d.(type) {
710 attrV != nil && 787 case *ResourceData:
711 schema.DiffSuppressFunc(attrK, attrV.Old, attrV.New, d) { 788 if schema.DiffSuppressFunc != nil &&
712 continue 789 attrV != nil &&
790 schema.DiffSuppressFunc(attrK, attrV.Old, attrV.New, rd) {
791 continue
792 }
713 } 793 }
714
715 diff.Attributes[attrK] = attrV 794 diff.Attributes[attrK] = attrV
716 } 795 }
717 796
@@ -722,9 +801,9 @@ func (m schemaMap) diffList(
722 k string, 801 k string,
723 schema *Schema, 802 schema *Schema,
724 diff *terraform.InstanceDiff, 803 diff *terraform.InstanceDiff,
725 d *ResourceData, 804 d resourceDiffer,
726 all bool) error { 805 all bool) error {
727 o, n, _, computedList := d.diffChange(k) 806 o, n, _, computedList, customized := d.diffChange(k)
728 if computedList { 807 if computedList {
729 n = nil 808 n = nil
730 } 809 }
@@ -791,10 +870,13 @@ func (m schemaMap) diffList(
791 oldStr = "" 870 oldStr = ""
792 } 871 }
793 872
794 diff.Attributes[k+".#"] = countSchema.finalizeDiff(&terraform.ResourceAttrDiff{ 873 diff.Attributes[k+".#"] = countSchema.finalizeDiff(
795 Old: oldStr, 874 &terraform.ResourceAttrDiff{
796 New: newStr, 875 Old: oldStr,
797 }) 876 New: newStr,
877 },
878 customized,
879 )
798 } 880 }
799 881
800 // Figure out the maximum 882 // Figure out the maximum
@@ -841,13 +923,13 @@ func (m schemaMap) diffMap(
841 k string, 923 k string,
842 schema *Schema, 924 schema *Schema,
843 diff *terraform.InstanceDiff, 925 diff *terraform.InstanceDiff,
844 d *ResourceData, 926 d resourceDiffer,
845 all bool) error { 927 all bool) error {
846 prefix := k + "." 928 prefix := k + "."
847 929
848 // First get all the values from the state 930 // First get all the values from the state
849 var stateMap, configMap map[string]string 931 var stateMap, configMap map[string]string
850 o, n, _, nComputed := d.diffChange(k) 932 o, n, _, nComputed, customized := d.diffChange(k)
851 if err := mapstructure.WeakDecode(o, &stateMap); err != nil { 933 if err := mapstructure.WeakDecode(o, &stateMap); err != nil {
852 return fmt.Errorf("%s: %s", k, err) 934 return fmt.Errorf("%s: %s", k, err)
853 } 935 }
@@ -899,6 +981,7 @@ func (m schemaMap) diffMap(
899 Old: oldStr, 981 Old: oldStr,
900 New: newStr, 982 New: newStr,
901 }, 983 },
984 customized,
902 ) 985 )
903 } 986 }
904 987
@@ -916,16 +999,22 @@ func (m schemaMap) diffMap(
916 continue 999 continue
917 } 1000 }
918 1001
919 diff.Attributes[prefix+k] = schema.finalizeDiff(&terraform.ResourceAttrDiff{ 1002 diff.Attributes[prefix+k] = schema.finalizeDiff(
920 Old: old, 1003 &terraform.ResourceAttrDiff{
921 New: v, 1004 Old: old,
922 }) 1005 New: v,
1006 },
1007 customized,
1008 )
923 } 1009 }
924 for k, v := range stateMap { 1010 for k, v := range stateMap {
925 diff.Attributes[prefix+k] = schema.finalizeDiff(&terraform.ResourceAttrDiff{ 1011 diff.Attributes[prefix+k] = schema.finalizeDiff(
926 Old: v, 1012 &terraform.ResourceAttrDiff{
927 NewRemoved: true, 1013 Old: v,
928 }) 1014 NewRemoved: true,
1015 },
1016 customized,
1017 )
929 } 1018 }
930 1019
931 return nil 1020 return nil
@@ -935,10 +1024,10 @@ func (m schemaMap) diffSet(
935 k string, 1024 k string,
936 schema *Schema, 1025 schema *Schema,
937 diff *terraform.InstanceDiff, 1026 diff *terraform.InstanceDiff,
938 d *ResourceData, 1027 d resourceDiffer,
939 all bool) error { 1028 all bool) error {
940 1029
941 o, n, _, computedSet := d.diffChange(k) 1030 o, n, _, computedSet, customized := d.diffChange(k)
942 if computedSet { 1031 if computedSet {
943 n = nil 1032 n = nil
944 } 1033 }
@@ -997,20 +1086,26 @@ func (m schemaMap) diffSet(
997 countStr = "" 1086 countStr = ""
998 } 1087 }
999 1088
1000 diff.Attributes[k+".#"] = countSchema.finalizeDiff(&terraform.ResourceAttrDiff{ 1089 diff.Attributes[k+".#"] = countSchema.finalizeDiff(
1001 Old: countStr, 1090 &terraform.ResourceAttrDiff{
1002 NewComputed: true, 1091 Old: countStr,
1003 }) 1092 NewComputed: true,
1093 },
1094 customized,
1095 )
1004 return nil 1096 return nil
1005 } 1097 }
1006 1098
1007 // If the counts are not the same, then record that diff 1099 // If the counts are not the same, then record that diff
1008 changed := oldLen != newLen 1100 changed := oldLen != newLen
1009 if changed || all { 1101 if changed || all {
1010 diff.Attributes[k+".#"] = countSchema.finalizeDiff(&terraform.ResourceAttrDiff{ 1102 diff.Attributes[k+".#"] = countSchema.finalizeDiff(
1011 Old: oldStr, 1103 &terraform.ResourceAttrDiff{
1012 New: newStr, 1104 Old: oldStr,
1013 }) 1105 New: newStr,
1106 },
1107 customized,
1108 )
1014 } 1109 }
1015 1110
1016 // Build the list of codes that will make up our set. This is the 1111 // Build the list of codes that will make up our set. This is the
@@ -1056,11 +1151,11 @@ func (m schemaMap) diffString(
1056 k string, 1151 k string,
1057 schema *Schema, 1152 schema *Schema,
1058 diff *terraform.InstanceDiff, 1153 diff *terraform.InstanceDiff,
1059 d *ResourceData, 1154 d resourceDiffer,
1060 all bool) error { 1155 all bool) error {
1061 var originalN interface{} 1156 var originalN interface{}
1062 var os, ns string 1157 var os, ns string
1063 o, n, _, computed := d.diffChange(k) 1158 o, n, _, computed, customized := d.diffChange(k)
1064 if schema.StateFunc != nil && n != nil { 1159 if schema.StateFunc != nil && n != nil {
1065 originalN = n 1160 originalN = n
1066 n = schema.StateFunc(n) 1161 n = schema.StateFunc(n)
@@ -1090,20 +1185,23 @@ func (m schemaMap) diffString(
1090 } 1185 }
1091 1186
1092 removed := false 1187 removed := false
1093 if o != nil && n == nil { 1188 if o != nil && n == nil && !computed {
1094 removed = true 1189 removed = true
1095 } 1190 }
1096 if removed && schema.Computed { 1191 if removed && schema.Computed {
1097 return nil 1192 return nil
1098 } 1193 }
1099 1194
1100 diff.Attributes[k] = schema.finalizeDiff(&terraform.ResourceAttrDiff{ 1195 diff.Attributes[k] = schema.finalizeDiff(
1101 Old: os, 1196 &terraform.ResourceAttrDiff{
1102 New: ns, 1197 Old: os,
1103 NewExtra: originalN, 1198 New: ns,
1104 NewRemoved: removed, 1199 NewExtra: originalN,
1105 NewComputed: computed, 1200 NewRemoved: removed,
1106 }) 1201 NewComputed: computed,
1202 },
1203 customized,
1204 )
1107 1205
1108 return nil 1206 return nil
1109} 1207}
@@ -1172,9 +1270,9 @@ func (m schemaMap) validateConflictingAttributes(
1172 } 1270 }
1173 1271
1174 for _, conflicting_key := range schema.ConflictsWith { 1272 for _, conflicting_key := range schema.ConflictsWith {
1175 if value, ok := c.Get(conflicting_key); ok { 1273 if _, ok := c.Get(conflicting_key); ok {
1176 return fmt.Errorf( 1274 return fmt.Errorf(
1177 "%q: conflicts with %s (%#v)", k, conflicting_key, value) 1275 "%q: conflicts with %s", k, conflicting_key)
1178 } 1276 }
1179 } 1277 }
1180 1278
@@ -1363,13 +1461,10 @@ func getValueType(k string, schema *Schema) (ValueType, error) {
1363 return vt, nil 1461 return vt, nil
1364 } 1462 }
1365 1463
1464 // If a Schema is provided to a Map, we use the Type of that schema
1465 // as the type for each element in the Map.
1366 if s, ok := schema.Elem.(*Schema); ok { 1466 if s, ok := schema.Elem.(*Schema); ok {
1367 if s.Elem == nil { 1467 return s.Type, nil
1368 return TypeString, nil
1369 }
1370 if vt, ok := s.Elem.(ValueType); ok {
1371 return vt, nil
1372 }
1373 } 1468 }
1374 1469
1375 if _, ok := schema.Elem.(*Resource); ok { 1470 if _, ok := schema.Elem.(*Resource); ok {
@@ -1430,7 +1525,6 @@ func (m schemaMap) validatePrimitive(
1430 raw interface{}, 1525 raw interface{},
1431 schema *Schema, 1526 schema *Schema,
1432 c *terraform.ResourceConfig) ([]string, []error) { 1527 c *terraform.ResourceConfig) ([]string, []error) {
1433
1434 // Catch if the user gave a complex type where a primitive was 1528 // Catch if the user gave a complex type where a primitive was
1435 // expected, so we can return a friendly error message that 1529 // expected, so we can return a friendly error message that
1436 // doesn't contain Go type system terminology. 1530 // doesn't contain Go type system terminology.
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/set.go b/vendor/github.com/hashicorp/terraform/helper/schema/set.go
index de05f40..cba2890 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/set.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/set.go
@@ -17,6 +17,12 @@ func HashString(v interface{}) int {
17 return hashcode.String(v.(string)) 17 return hashcode.String(v.(string))
18} 18}
19 19
20// HashInt hashes integers. If you want a Set of integers, this is the
21// SchemaSetFunc you want.
22func HashInt(v interface{}) int {
23 return hashcode.String(strconv.Itoa(v.(int)))
24}
25
20// HashResource hashes complex structures that are described using 26// HashResource hashes complex structures that are described using
21// a *Resource. This is the default set implementation used when a set's 27// a *Resource. This is the default set implementation used when a set's
22// element type is a full resource. 28// element type is a full resource.
@@ -153,6 +159,31 @@ func (s *Set) Equal(raw interface{}) bool {
153 return reflect.DeepEqual(s.m, other.m) 159 return reflect.DeepEqual(s.m, other.m)
154} 160}
155 161
162// HashEqual simply checks to the keys the top-level map to the keys in the
163// other set's top-level map to see if they are equal. This obviously assumes
164// you have a properly working hash function - use HashResource if in doubt.
165func (s *Set) HashEqual(raw interface{}) bool {
166 other, ok := raw.(*Set)
167 if !ok {
168 return false
169 }
170
171 ks1 := make([]string, 0)
172 ks2 := make([]string, 0)
173
174 for k := range s.m {
175 ks1 = append(ks1, k)
176 }
177 for k := range other.m {
178 ks2 = append(ks2, k)
179 }
180
181 sort.Strings(ks1)
182 sort.Strings(ks2)
183
184 return reflect.DeepEqual(ks1, ks2)
185}
186
156func (s *Set) GoString() string { 187func (s *Set) GoString() string {
157 return fmt.Sprintf("*Set(%#v)", s.m) 188 return fmt.Sprintf("*Set(%#v)", s.m)
158} 189}
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/testing.go b/vendor/github.com/hashicorp/terraform/helper/schema/testing.go
index 9765bdb..da754ac 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/testing.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/testing.go
@@ -10,13 +10,15 @@ import (
10// TestResourceDataRaw creates a ResourceData from a raw configuration map. 10// TestResourceDataRaw creates a ResourceData from a raw configuration map.
11func TestResourceDataRaw( 11func TestResourceDataRaw(
12 t *testing.T, schema map[string]*Schema, raw map[string]interface{}) *ResourceData { 12 t *testing.T, schema map[string]*Schema, raw map[string]interface{}) *ResourceData {
13 t.Helper()
14
13 c, err := config.NewRawConfig(raw) 15 c, err := config.NewRawConfig(raw)
14 if err != nil { 16 if err != nil {
15 t.Fatalf("err: %s", err) 17 t.Fatalf("err: %s", err)
16 } 18 }
17 19
18 sm := schemaMap(schema) 20 sm := schemaMap(schema)
19 diff, err := sm.Diff(nil, terraform.NewResourceConfig(c)) 21 diff, err := sm.Diff(nil, terraform.NewResourceConfig(c), nil, nil)
20 if err != nil { 22 if err != nil {
21 t.Fatalf("err: %s", err) 23 t.Fatalf("err: %s", err)
22 } 24 }
diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/valuetype_string.go b/vendor/github.com/hashicorp/terraform/helper/schema/valuetype_string.go
index 1610cec..3bc3ac4 100644
--- a/vendor/github.com/hashicorp/terraform/helper/schema/valuetype_string.go
+++ b/vendor/github.com/hashicorp/terraform/helper/schema/valuetype_string.go
@@ -2,7 +2,7 @@
2 2
3package schema 3package schema
4 4
5import "fmt" 5import "strconv"
6 6
7const _ValueType_name = "TypeInvalidTypeBoolTypeIntTypeFloatTypeStringTypeListTypeMapTypeSettypeObject" 7const _ValueType_name = "TypeInvalidTypeBoolTypeIntTypeFloatTypeStringTypeListTypeMapTypeSettypeObject"
8 8
@@ -10,7 +10,7 @@ var _ValueType_index = [...]uint8{0, 11, 19, 26, 35, 45, 53, 60, 67, 77}
10 10
11func (i ValueType) String() string { 11func (i ValueType) String() string {
12 if i < 0 || i >= ValueType(len(_ValueType_index)-1) { 12 if i < 0 || i >= ValueType(len(_ValueType_index)-1) {
13 return fmt.Sprintf("ValueType(%d)", i) 13 return "ValueType(" + strconv.FormatInt(int64(i), 10) + ")"
14 } 14 }
15 return _ValueType_name[_ValueType_index[i]:_ValueType_index[i+1]] 15 return _ValueType_name[_ValueType_index[i]:_ValueType_index[i+1]]
16} 16}
diff --git a/vendor/github.com/hashicorp/terraform/helper/shadow/closer.go b/vendor/github.com/hashicorp/terraform/helper/shadow/closer.go
deleted file mode 100644
index edc1e2a..0000000
--- a/vendor/github.com/hashicorp/terraform/helper/shadow/closer.go
+++ /dev/null
@@ -1,83 +0,0 @@
1package shadow
2
3import (
4 "fmt"
5 "io"
6 "reflect"
7
8 "github.com/hashicorp/go-multierror"
9 "github.com/mitchellh/reflectwalk"
10)
11
12// Close will close all shadow values within the given structure.
13//
14// This uses reflection to walk the structure, find all shadow elements,
15// and close them. Currently this will only find struct fields that are
16// shadow values, and not slice elements, etc.
17func Close(v interface{}) error {
18 // We require a pointer so we can address the internal fields
19 val := reflect.ValueOf(v)
20 if val.Kind() != reflect.Ptr {
21 return fmt.Errorf("value must be a pointer")
22 }
23
24 // Walk and close
25 var w closeWalker
26 if err := reflectwalk.Walk(v, &w); err != nil {
27 return err
28 }
29
30 return w.Err
31}
32
33type closeWalker struct {
34 Err error
35}
36
37func (w *closeWalker) Struct(reflect.Value) error {
38 // Do nothing. We implement this for reflectwalk.StructWalker
39 return nil
40}
41
42var closerType = reflect.TypeOf((*io.Closer)(nil)).Elem()
43
44func (w *closeWalker) StructField(f reflect.StructField, v reflect.Value) error {
45 // Not sure why this would be but lets avoid some panics
46 if !v.IsValid() {
47 return nil
48 }
49
50 // Empty for exported, so don't check unexported fields
51 if f.PkgPath != "" {
52 return nil
53 }
54
55 // Verify the io.Closer is in this package
56 typ := v.Type()
57 if typ.PkgPath() != "github.com/hashicorp/terraform/helper/shadow" {
58 return nil
59 }
60
61 var closer io.Closer
62 if v.Type().Implements(closerType) {
63 closer = v.Interface().(io.Closer)
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 }
70 }
71
72 if closer == nil {
73 return reflectwalk.SkipEntry
74 }
75
76 // Close it
77 if err := closer.Close(); err != nil {
78 w.Err = multierror.Append(w.Err, err)
79 }
80
81 // Don't go into the struct field
82 return reflectwalk.SkipEntry
83}
diff --git a/vendor/github.com/hashicorp/terraform/helper/shadow/compared_value.go b/vendor/github.com/hashicorp/terraform/helper/shadow/compared_value.go
deleted file mode 100644
index 4223e92..0000000
--- a/vendor/github.com/hashicorp/terraform/helper/shadow/compared_value.go
+++ /dev/null
@@ -1,128 +0,0 @@
1package shadow
2
3import (
4 "sync"
5)
6
7// ComparedValue is a struct that finds a value by comparing some key
8// to the list of stored values. This is useful when there is no easy
9// uniquely identifying key that works in a map (for that, use KeyedValue).
10//
11// ComparedValue is very expensive, relative to other Value types. Try to
12// limit the number of values stored in a ComparedValue by potentially
13// nesting it within a KeyedValue (a keyed value points to a compared value,
14// for example).
15type ComparedValue struct {
16 // Func is a function that is given the lookup key and a single
17 // stored value. If it matches, it returns true.
18 Func func(k, v interface{}) bool
19
20 lock sync.Mutex
21 once sync.Once
22 closed bool
23 values []interface{}
24 waiters map[interface{}]*Value
25}
26
27// Close closes the value. This can never fail. For a definition of
28// "close" see the ErrClosed docs.
29func (w *ComparedValue) Close() error {
30 w.lock.Lock()
31 defer w.lock.Unlock()
32
33 // Set closed to true always
34 w.closed = true
35
36 // For all waiters, complete with ErrClosed
37 for k, val := range w.waiters {
38 val.SetValue(ErrClosed)
39 delete(w.waiters, k)
40 }
41
42 return nil
43}
44
45// Value returns the value that was set for the given key, or blocks
46// until one is available.
47func (w *ComparedValue) Value(k interface{}) interface{} {
48 v, val := w.valueWaiter(k)
49 if val == nil {
50 return v
51 }
52
53 return val.Value()
54}
55
56// ValueOk gets the value for the given key, returning immediately if the
57// value doesn't exist. The second return argument is true if the value exists.
58func (w *ComparedValue) ValueOk(k interface{}) (interface{}, bool) {
59 v, val := w.valueWaiter(k)
60 return v, val == nil
61}
62
63func (w *ComparedValue) SetValue(v interface{}) {
64 w.lock.Lock()
65 defer w.lock.Unlock()
66 w.once.Do(w.init)
67
68 // Check if we already have this exact value (by simply comparing
69 // with == directly). If we do, then we don't insert it again.
70 found := false
71 for _, v2 := range w.values {
72 if v == v2 {
73 found = true
74 break
75 }
76 }
77
78 if !found {
79 // Set the value, always
80 w.values = append(w.values, v)
81 }
82
83 // Go through the waiters
84 for k, val := range w.waiters {
85 if w.Func(k, v) {
86 val.SetValue(v)
87 delete(w.waiters, k)
88 }
89 }
90}
91
92func (w *ComparedValue) valueWaiter(k interface{}) (interface{}, *Value) {
93 w.lock.Lock()
94 w.once.Do(w.init)
95
96 // Look for a pre-existing value
97 for _, v := range w.values {
98 if w.Func(k, v) {
99 w.lock.Unlock()
100 return v, nil
101 }
102 }
103
104 // If we're closed, return that
105 if w.closed {
106 w.lock.Unlock()
107 return ErrClosed, nil
108 }
109
110 // Pre-existing value doesn't exist, create a waiter
111 val := w.waiters[k]
112 if val == nil {
113 val = new(Value)
114 w.waiters[k] = val
115 }
116 w.lock.Unlock()
117
118 // Return the waiter
119 return nil, val
120}
121
122// Must be called with w.lock held.
123func (w *ComparedValue) init() {
124 w.waiters = make(map[interface{}]*Value)
125 if w.Func == nil {
126 w.Func = func(k, v interface{}) bool { return k == v }
127 }
128}
diff --git a/vendor/github.com/hashicorp/terraform/helper/shadow/keyed_value.go b/vendor/github.com/hashicorp/terraform/helper/shadow/keyed_value.go
deleted file mode 100644
index 432b036..0000000
--- a/vendor/github.com/hashicorp/terraform/helper/shadow/keyed_value.go
+++ /dev/null
@@ -1,151 +0,0 @@
1package shadow
2
3import (
4 "sync"
5)
6
7// KeyedValue is a struct that coordinates a value by key. If a value is
8// not available for a give key, it'll block until it is available.
9type KeyedValue struct {
10 lock sync.Mutex
11 once sync.Once
12 values map[string]interface{}
13 waiters map[string]*Value
14 closed bool
15}
16
17// Close closes the value. This can never fail. For a definition of
18// "close" see the ErrClosed docs.
19func (w *KeyedValue) Close() error {
20 w.lock.Lock()
21 defer w.lock.Unlock()
22
23 // Set closed to true always
24 w.closed = true
25
26 // For all waiters, complete with ErrClosed
27 for k, val := range w.waiters {
28 val.SetValue(ErrClosed)
29 delete(w.waiters, k)
30 }
31
32 return nil
33}
34
35// Value returns the value that was set for the given key, or blocks
36// until one is available.
37func (w *KeyedValue) Value(k string) interface{} {
38 w.lock.Lock()
39 v, val := w.valueWaiter(k)
40 w.lock.Unlock()
41
42 // If we have no waiter, then return the value
43 if val == nil {
44 return v
45 }
46
47 // We have a waiter, so wait
48 return val.Value()
49}
50
51// WaitForChange waits for the value with the given key to be set again.
52// If the key isn't set, it'll wait for an initial value. Note that while
53// it is called "WaitForChange", the value isn't guaranteed to _change_;
54// this will return when a SetValue is called for the given k.
55func (w *KeyedValue) WaitForChange(k string) interface{} {
56 w.lock.Lock()
57 w.once.Do(w.init)
58
59 // If we're closed, we're closed
60 if w.closed {
61 w.lock.Unlock()
62 return ErrClosed
63 }
64
65 // Check for an active waiter. If there isn't one, make it
66 val := w.waiters[k]
67 if val == nil {
68 val = new(Value)
69 w.waiters[k] = val
70 }
71 w.lock.Unlock()
72
73 // And wait
74 return val.Value()
75}
76
77// ValueOk gets the value for the given key, returning immediately if the
78// value doesn't exist. The second return argument is true if the value exists.
79func (w *KeyedValue) ValueOk(k string) (interface{}, bool) {
80 w.lock.Lock()
81 defer w.lock.Unlock()
82
83 v, val := w.valueWaiter(k)
84 return v, val == nil
85}
86
87func (w *KeyedValue) SetValue(k string, v interface{}) {
88 w.lock.Lock()
89 defer w.lock.Unlock()
90 w.setValue(k, v)
91}
92
93// Init will initialize the key to a given value only if the key has
94// not been set before. This is safe to call multiple times and in parallel.
95func (w *KeyedValue) Init(k string, v interface{}) {
96 w.lock.Lock()
97 defer w.lock.Unlock()
98
99 // If we have a waiter, set the value.
100 _, val := w.valueWaiter(k)
101 if val != nil {
102 w.setValue(k, v)
103 }
104}
105
106// Must be called with w.lock held.
107func (w *KeyedValue) init() {
108 w.values = make(map[string]interface{})
109 w.waiters = make(map[string]*Value)
110}
111
112// setValue is like SetValue but assumes the lock is held.
113func (w *KeyedValue) setValue(k string, v interface{}) {
114 w.once.Do(w.init)
115
116 // Set the value, always
117 w.values[k] = v
118
119 // If we have a waiter, set it
120 if val, ok := w.waiters[k]; ok {
121 val.SetValue(v)
122 delete(w.waiters, k)
123 }
124}
125
126// valueWaiter gets the value or the Value waiter for a given key.
127//
128// This must be called with lock held.
129func (w *KeyedValue) valueWaiter(k string) (interface{}, *Value) {
130 w.once.Do(w.init)
131
132 // If we have this value already, return it
133 if v, ok := w.values[k]; ok {
134 return v, nil
135 }
136
137 // If we're closed, return that
138 if w.closed {
139 return ErrClosed, nil
140 }
141
142 // No pending value, check for a waiter
143 val := w.waiters[k]
144 if val == nil {
145 val = new(Value)
146 w.waiters[k] = val
147 }
148
149 // Return the waiter
150 return nil, val
151}
diff --git a/vendor/github.com/hashicorp/terraform/helper/shadow/ordered_value.go b/vendor/github.com/hashicorp/terraform/helper/shadow/ordered_value.go
deleted file mode 100644
index 0a43d4d..0000000
--- a/vendor/github.com/hashicorp/terraform/helper/shadow/ordered_value.go
+++ /dev/null
@@ -1,66 +0,0 @@
1package shadow
2
3import (
4 "container/list"
5 "sync"
6)
7
8// OrderedValue is a struct that keeps track of a value in the order
9// it is set. Each time Value() is called, it will return the most recent
10// calls value then discard it.
11//
12// This is unlike Value that returns the same value once it is set.
13type OrderedValue struct {
14 lock sync.Mutex
15 values *list.List
16 waiters *list.List
17}
18
19// Value returns the last value that was set, or blocks until one
20// is received.
21func (w *OrderedValue) Value() interface{} {
22 w.lock.Lock()
23
24 // If we have a pending value already, use it
25 if w.values != nil && w.values.Len() > 0 {
26 front := w.values.Front()
27 w.values.Remove(front)
28 w.lock.Unlock()
29 return front.Value
30 }
31
32 // No pending value, create a waiter
33 if w.waiters == nil {
34 w.waiters = list.New()
35 }
36
37 var val Value
38 w.waiters.PushBack(&val)
39 w.lock.Unlock()
40
41 // Return the value once we have it
42 return val.Value()
43}
44
45// SetValue sets the latest value.
46func (w *OrderedValue) SetValue(v interface{}) {
47 w.lock.Lock()
48 defer w.lock.Unlock()
49
50 // If we have a waiter, notify it
51 if w.waiters != nil && w.waiters.Len() > 0 {
52 front := w.waiters.Front()
53 w.waiters.Remove(front)
54
55 val := front.Value.(*Value)
56 val.SetValue(v)
57 return
58 }
59
60 // Add it to the list of values
61 if w.values == nil {
62 w.values = list.New()
63 }
64
65 w.values.PushBack(v)
66}
diff --git a/vendor/github.com/hashicorp/terraform/helper/shadow/value.go b/vendor/github.com/hashicorp/terraform/helper/shadow/value.go
deleted file mode 100644
index 178b7e7..0000000
--- a/vendor/github.com/hashicorp/terraform/helper/shadow/value.go
+++ /dev/null
@@ -1,87 +0,0 @@
1package shadow
2
3import (
4 "errors"
5 "sync"
6)
7
8// ErrClosed is returned by any closed values.
9//
10// A "closed value" is when the shadow has been notified that the real
11// side is complete and any blocking values will _never_ be satisfied
12// in the future. In this case, this error is returned. If a value is already
13// available, that is still returned.
14var ErrClosed = errors.New("shadow closed")
15
16// Value is a struct that coordinates a value between two
17// parallel routines. It is similar to atomic.Value except that when
18// Value is called if it isn't set it will wait for it.
19//
20// The Value can be closed with Close, which will cause any future
21// blocking operations to return immediately with ErrClosed.
22type Value struct {
23 lock sync.Mutex
24 cond *sync.Cond
25 value interface{}
26 valueSet bool
27}
28
29func (v *Value) Lock() {
30 v.lock.Lock()
31}
32
33func (v *Value) Unlock() {
34 v.lock.Unlock()
35}
36
37// Close closes the value. This can never fail. For a definition of
38// "close" see the struct docs.
39func (w *Value) Close() error {
40 w.lock.Lock()
41 set := w.valueSet
42 w.lock.Unlock()
43
44 // If we haven't set the value, set it
45 if !set {
46 w.SetValue(ErrClosed)
47 }
48
49 // Done
50 return nil
51}
52
53// Value returns the value that was set.
54func (w *Value) Value() interface{} {
55 w.lock.Lock()
56 defer w.lock.Unlock()
57
58 // If we already have a value just return
59 for !w.valueSet {
60 // No value, setup the condition variable if we have to
61 if w.cond == nil {
62 w.cond = sync.NewCond(&w.lock)
63 }
64
65 // Wait on it
66 w.cond.Wait()
67 }
68
69 // Return the value
70 return w.value
71}
72
73// SetValue sets the value.
74func (w *Value) SetValue(v interface{}) {
75 w.lock.Lock()
76 defer w.lock.Unlock()
77
78 // Set the value
79 w.valueSet = true
80 w.value = v
81
82 // If we have a condition, clear it
83 if w.cond != nil {
84 w.cond.Broadcast()
85 w.cond = nil
86 }
87}