From f473396501960cda6a8c09483e1ea4fd21ca2351 Mon Sep 17 00:00:00 2001 From: Nicholas Bering Date: Wed, 18 Apr 2018 22:14:03 -0400 Subject: [PATCH] Update vendored terraform dependencies to v0.11.7 --- .../hashicorp/terraform/helper/resource/id.go | 5 ++ .../terraform/helper/resource/testing.go | 21 ++++- .../terraform/helper/resource/wait.go | 2 +- .../terraform/helper/schema/field_reader.go | 11 +-- .../helper/schema/field_reader_config.go | 2 +- .../helper/schema/field_reader_diff.go | 3 +- .../helper/schema/field_reader_map.go | 2 +- .../terraform/helper/schema/resource.go | 6 ++ .../terraform/helper/schema/resource_data.go | 10 ++- .../terraform/helper/schema/resource_diff.go | 89 +++++++++++++++++-- .../terraform/helper/schema/schema.go | 29 +++--- .../hashicorp/terraform/httpclient/client.go | 18 ++++ .../terraform/httpclient/useragent.go | 40 +++++++++ .../terraform/plugin/discovery/get.go | 16 +++- .../hashicorp/terraform/terraform/context.go | 14 +++ .../terraform/terraform/eval_apply.go | 7 +- .../terraform/terraform/eval_validate.go | 3 + .../terraform/graph_builder_apply.go | 12 ++- .../terraform/terraform/interpolate.go | 26 +++++- .../terraform/terraform/node_local.go | 36 +------- .../terraform/terraform/node_output.go | 66 ++++++++++++-- .../terraform/node_resource_apply.go | 10 ++- .../terraform/node_resource_refresh.go | 8 +- .../hashicorp/terraform/terraform/state.go | 23 +++-- .../terraform/terraform/transform_output.go | 46 ++++++++-- .../terraform/transform_reference.go | 68 +++++++++++--- .../terraform/terraform/transform_targets.go | 6 ++ .../terraform/terraform/user_agent.go | 13 ++- vendor/vendor.json | 54 ++++++----- 29 files changed, 504 insertions(+), 142 deletions(-) create mode 100644 vendor/github.com/hashicorp/terraform/httpclient/client.go create mode 100644 vendor/github.com/hashicorp/terraform/httpclient/useragent.go 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 { return PrefixedUniqueId(UniqueIdPrefix) } +// UniqueIDSuffixLength is the string length of the suffix generated by +// PrefixedUniqueId. This can be used by length validation functions to +// ensure prefixes are the correct length for the target field. +const UniqueIDSuffixLength = 26 + // Helper for a resource to generate a unique identifier w/ given prefix // // After the prefix, the ID consists of an incrementing 26 digit value (to match diff --git a/vendor/github.com/hashicorp/terraform/helper/resource/testing.go b/vendor/github.com/hashicorp/terraform/helper/resource/testing.go index aaaddf5..27bfc9b 100644 --- a/vendor/github.com/hashicorp/terraform/helper/resource/testing.go +++ b/vendor/github.com/hashicorp/terraform/helper/resource/testing.go @@ -310,6 +310,11 @@ type TestStep struct { // no-op plans PlanOnly bool + // PreventDiskCleanup can be set to true for testing terraform modules which + // require access to disk at runtime. Note that this will leave files in the + // temp folder + PreventDiskCleanup bool + // PreventPostDestroyRefresh can be set to true for cases where data sources // are tested alongside real resources PreventPostDestroyRefresh bool @@ -564,6 +569,7 @@ func Test(t TestT, c TestCase) { Config: lastStep.Config, Check: c.CheckDestroy, Destroy: true, + PreventDiskCleanup: lastStep.PreventDiskCleanup, PreventPostDestroyRefresh: c.PreventPostDestroyRefresh, } @@ -730,9 +736,7 @@ func testIDOnlyRefresh(c TestCase, opts terraform.ContextOpts, step TestStep, r return nil } -func testModule( - opts terraform.ContextOpts, - step TestStep) (*module.Tree, error) { +func testModule(opts terraform.ContextOpts, step TestStep) (*module.Tree, error) { if step.PreConfig != nil { step.PreConfig() } @@ -742,7 +746,12 @@ func testModule( return nil, fmt.Errorf( "Error creating temporary directory for config: %s", err) } - defer os.RemoveAll(cfgPath) + + if step.PreventDiskCleanup { + log.Printf("[INFO] Skipping defer os.RemoveAll call") + } else { + defer os.RemoveAll(cfgPath) + } // Write the configuration cfgF, err := os.Create(filepath.Join(cfgPath, "main.tf")) @@ -1135,6 +1144,10 @@ func modulePrimaryInstanceState(s *terraform.State, ms *terraform.ModuleState, n // given resource name in a given module path. func modulePathPrimaryInstanceState(s *terraform.State, mp []string, name string) (*terraform.InstanceState, error) { ms := s.ModuleByPath(mp) + if ms == nil { + return nil, fmt.Errorf("No module found at: %s", mp) + } + return modulePrimaryInstanceState(s, ms, name) } 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 { return &RetryError{Err: err, Retryable: true} } -// NonRetryableError is a helper to create a RetryError that's _not)_ retryable +// NonRetryableError is a helper to create a RetryError that's _not_ retryable // from a given error. func NonRetryableError(err error) *RetryError { if err == nil { 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 { switch v := current.Elem.(type) { case ValueType: current = &Schema{Type: v} + case *Schema: + current, _ = current.Elem.(*Schema) default: // maps default to string values. This is all we can have // if this is nested in another list or map. @@ -249,11 +251,10 @@ func readObjectField( } // convert map values to the proper primitive type based on schema.Elem -func mapValuesToPrimitive(m map[string]interface{}, schema *Schema) error { - - elemType := TypeString - if et, ok := schema.Elem.(ValueType); ok { - elemType = et +func mapValuesToPrimitive(k string, m map[string]interface{}, schema *Schema) error { + elemType, err := getValueType(k, schema) + if err != nil { + return err } 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, panic(fmt.Sprintf("unknown type: %#v", mraw)) } - err := mapValuesToPrimitive(result, schema) + err := mapValuesToPrimitive(k, result, schema) if err != nil { return FieldReadResult{}, nil } 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 644b93e..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 @@ -122,7 +122,8 @@ func (r *DiffFieldReader) readMap( result[k] = v.New } - err = mapValuesToPrimitive(result, schema) + key := address[len(address)-1] + err = mapValuesToPrimitive(key, result, schema) if err != nil { return FieldReadResult{}, nil } 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 return true }) - err := mapValuesToPrimitive(result, schema) + err := mapValuesToPrimitive(k, result, schema) if err != nil { return FieldReadResult{}, nil } diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/resource.go b/vendor/github.com/hashicorp/terraform/helper/schema/resource.go index c8e99b9..8f726bf 100644 --- a/vendor/github.com/hashicorp/terraform/helper/schema/resource.go +++ b/vendor/github.com/hashicorp/terraform/helper/schema/resource.go @@ -492,6 +492,12 @@ func (r *Resource) Data(s *terraform.InstanceState) *ResourceData { panic(err) } + // load the Resource timeouts + result.timeouts = r.Timeouts + if result.timeouts == nil { + result.timeouts = &ResourceTimeout{} + } + // Set the schema version to latest by default result.meta = map[string]interface{}{ "schema_version": strconv.Itoa(r.SchemaVersion), 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 9ab8bcc..22d57a5 100644 --- a/vendor/github.com/hashicorp/terraform/helper/schema/resource_data.go +++ b/vendor/github.com/hashicorp/terraform/helper/schema/resource_data.go @@ -366,6 +366,13 @@ func (d *ResourceData) State() *terraform.InstanceState { func (d *ResourceData) Timeout(key string) time.Duration { key = strings.ToLower(key) + // System default of 20 minutes + defaultTimeout := 20 * time.Minute + + if d.timeouts == nil { + return defaultTimeout + } + var timeout *time.Duration switch key { case TimeoutCreate: @@ -386,8 +393,7 @@ func (d *ResourceData) Timeout(key string) time.Duration { return *d.timeouts.Default } - // Return system default of 20 minutes - return 20 * time.Minute + return defaultTimeout } func (d *ResourceData) init() { diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/resource_diff.go b/vendor/github.com/hashicorp/terraform/helper/schema/resource_diff.go index 822d0dc..92b891f 100644 --- a/vendor/github.com/hashicorp/terraform/helper/schema/resource_diff.go +++ b/vendor/github.com/hashicorp/terraform/helper/schema/resource_diff.go @@ -135,6 +135,10 @@ type ResourceDiff struct { // diff does not get re-run on keys that were not touched, or diffs that were // just removed (re-running on the latter would just roll back the removal). updatedKeys map[string]bool + + // Tracks which keys were flagged as forceNew. These keys are not saved in + // newWriter, but we need to track them so that they can be re-diffed later. + forcedNewKeys map[string]bool } // newResourceDiff creates a new ResourceDiff instance. @@ -193,17 +197,30 @@ func newResourceDiff(schema map[string]*Schema, config *terraform.ResourceConfig } d.updatedKeys = make(map[string]bool) + d.forcedNewKeys = make(map[string]bool) return d } // UpdatedKeys returns the keys that were updated by this ResourceDiff run. // These are the only keys that a diff should be re-calculated for. +// +// This is the combined result of both keys for which diff values were updated +// for or cleared, and also keys that were flagged to be re-diffed as a result +// of ForceNew. func (d *ResourceDiff) UpdatedKeys() []string { var s []string for k := range d.updatedKeys { s = append(s, k) } + for k := range d.forcedNewKeys { + for _, l := range s { + if k == l { + break + } + } + s = append(s, k) + } return s } @@ -223,9 +240,11 @@ func (d *ResourceDiff) Clear(key string) error { func (d *ResourceDiff) clear(key string) error { // Check the schema to make sure that this key exists first. - if _, ok := d.schema[key]; !ok { + schemaL := addrToSchema(strings.Split(key, "."), d.schema) + if len(schemaL) == 0 { return fmt.Errorf("%s is not a valid key", key) } + for k := range d.diff.Attributes { if strings.HasPrefix(k, key) { delete(d.diff.Attributes, k) @@ -234,6 +253,19 @@ func (d *ResourceDiff) clear(key string) error { return nil } +// GetChangedKeysPrefix helps to implement Resource.CustomizeDiff +// where we need to act on all nested fields +// without calling out each one separately +func (d *ResourceDiff) GetChangedKeysPrefix(prefix string) []string { + keys := make([]string, 0) + for k := range d.diff.Attributes { + if strings.HasPrefix(k, prefix) { + keys = append(keys, k) + } + } + return keys +} + // diffChange helps to implement resourceDiffer and derives its change values // from ResourceDiff's own change data, in addition to existing diff, config, and state. func (d *ResourceDiff) diffChange(key string) (interface{}, interface{}, bool, bool, bool) { @@ -242,7 +274,7 @@ func (d *ResourceDiff) diffChange(key string) (interface{}, interface{}, bool, b if !old.Exists { old.Value = nil } - if !new.Exists { + if !new.Exists || d.removed(key) { new.Value = nil } @@ -309,9 +341,23 @@ func (d *ResourceDiff) ForceNew(key string) error { return fmt.Errorf("ForceNew: No changes for %s", key) } - _, new := d.GetChange(key) - d.schema[key].ForceNew = true - return d.setDiff(key, new, false) + keyParts := strings.Split(key, ".") + var schema *Schema + schemaL := addrToSchema(keyParts, d.schema) + if len(schemaL) > 0 { + schema = schemaL[len(schemaL)-1] + } else { + return fmt.Errorf("ForceNew: %s is not a valid key", key) + } + + schema.ForceNew = true + + // Flag this for a re-diff. Don't save any values to guarantee that existing + // diffs aren't messed with, as this gets messy when dealing with complex + // structures, zero values, etc. + d.forcedNewKeys[keyParts[0]] = true + + return nil } // Get hands off to ResourceData.Get. @@ -352,6 +398,29 @@ func (d *ResourceDiff) GetOk(key string) (interface{}, bool) { return r.Value, exists } +// GetOkExists functions the same way as GetOkExists within ResourceData, but +// it also checks the new diff levels to provide data consistent with the +// current state of the customized diff. +// +// This is nearly the same function as GetOk, yet it does not check +// for the zero value of the attribute's type. This allows for attributes +// without a default, to fully check for a literal assignment, regardless +// of the zero-value for that type. +func (d *ResourceDiff) GetOkExists(key string) (interface{}, bool) { + r := d.get(strings.Split(key, "."), "newDiff") + exists := r.Exists && !r.Computed + return r.Value, exists +} + +// NewValueKnown returns true if the new value for the given key is available +// as its final value at diff time. If the return value is false, this means +// either the value is based of interpolation that was unavailable at diff +// time, or that the value was explicitly marked as computed by SetNewComputed. +func (d *ResourceDiff) NewValueKnown(key string) bool { + r := d.get(strings.Split(key, "."), "newDiff") + return !r.Computed +} + // HasChange checks to see if there is a change between state and the diff, or // in the overridden diff. func (d *ResourceDiff) HasChange(key string) bool { @@ -400,6 +469,16 @@ func (d *ResourceDiff) getChange(key string) (getResult, getResult, bool) { return old, new, false } +// removed checks to see if the key is present in the existing, pre-customized +// diff and if it was marked as NewRemoved. +func (d *ResourceDiff) removed(k string) bool { + diff, ok := d.diff.Attributes[k] + if !ok { + return false + } + return diff.NewRemoved +} + // get performs the appropriate multi-level reader logic for ResourceDiff, // starting at source. Refer to newResourceDiff for the level order. func (d *ResourceDiff) get(addr []string, source string) getResult { diff --git a/vendor/github.com/hashicorp/terraform/helper/schema/schema.go b/vendor/github.com/hashicorp/terraform/helper/schema/schema.go index 6773fe5..f44010e 100644 --- a/vendor/github.com/hashicorp/terraform/helper/schema/schema.go +++ b/vendor/github.com/hashicorp/terraform/helper/schema/schema.go @@ -395,7 +395,7 @@ func (m *schemaMap) DeepCopy() schemaMap { if err != nil { panic(err) } - return copy.(schemaMap) + return *copy.(*schemaMap) } // Diff returns the diff for a resource given the schema map, @@ -427,6 +427,13 @@ func (m schemaMap) Diff( } } + // Remove any nil diffs just to keep things clean + for k, v := range result.Attributes { + if v == nil { + delete(result.Attributes, k) + } + } + // If this is a non-destroy diff, call any custom diff logic that has been // defined. if !result.DestroyTainted && customizeDiff != nil { @@ -521,13 +528,6 @@ func (m schemaMap) Diff( result = result2 } - // Remove any nil diffs just to keep things clean - for k, v := range result.Attributes { - if v == nil { - delete(result.Attributes, k) - } - } - // Go through and detect all of the ComputedWhens now that we've // finished the diff. // TODO @@ -1270,9 +1270,9 @@ func (m schemaMap) validateConflictingAttributes( } for _, conflicting_key := range schema.ConflictsWith { - if value, ok := c.Get(conflicting_key); ok { + if _, ok := c.Get(conflicting_key); ok { return fmt.Errorf( - "%q: conflicts with %s (%#v)", k, conflicting_key, value) + "%q: conflicts with %s", k, conflicting_key) } } @@ -1461,13 +1461,10 @@ func getValueType(k string, schema *Schema) (ValueType, error) { return vt, nil } + // If a Schema is provided to a Map, we use the Type of that schema + // as the type for each element in the Map. if s, ok := schema.Elem.(*Schema); ok { - if s.Elem == nil { - return TypeString, nil - } - if vt, ok := s.Elem.(ValueType); ok { - return vt, nil - } + return s.Type, nil } if _, ok := schema.Elem.(*Resource); ok { diff --git a/vendor/github.com/hashicorp/terraform/httpclient/client.go b/vendor/github.com/hashicorp/terraform/httpclient/client.go new file mode 100644 index 0000000..bb06beb --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/httpclient/client.go @@ -0,0 +1,18 @@ +package httpclient + +import ( + "net/http" + + cleanhttp "github.com/hashicorp/go-cleanhttp" +) + +// New returns the DefaultPooledClient from the cleanhttp +// package that will also send a Terraform User-Agent string. +func New() *http.Client { + cli := cleanhttp.DefaultPooledClient() + cli.Transport = &userAgentRoundTripper{ + userAgent: UserAgentString(), + inner: cli.Transport, + } + return cli +} diff --git a/vendor/github.com/hashicorp/terraform/httpclient/useragent.go b/vendor/github.com/hashicorp/terraform/httpclient/useragent.go new file mode 100644 index 0000000..5e28017 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/httpclient/useragent.go @@ -0,0 +1,40 @@ +package httpclient + +import ( + "fmt" + "log" + "net/http" + "os" + "strings" + + "github.com/hashicorp/terraform/version" +) + +const userAgentFormat = "Terraform/%s" +const uaEnvVar = "TF_APPEND_USER_AGENT" + +func UserAgentString() string { + ua := fmt.Sprintf(userAgentFormat, version.Version) + + if add := os.Getenv(uaEnvVar); add != "" { + add = strings.TrimSpace(add) + if len(add) > 0 { + ua += " " + add + log.Printf("[DEBUG] Using modified User-Agent: %s", ua) + } + } + + return ua +} + +type userAgentRoundTripper struct { + inner http.RoundTripper + userAgent string +} + +func (rt *userAgentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + if _, ok := req.Header["User-Agent"]; !ok { + req.Header.Set("User-Agent", rt.userAgent) + } + return rt.inner.RoundTrip(req) +} diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go index f523c36..815640f 100644 --- a/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go @@ -15,9 +15,9 @@ import ( "golang.org/x/net/html" - cleanhttp "github.com/hashicorp/go-cleanhttp" getter "github.com/hashicorp/go-getter" multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform/httpclient" "github.com/mitchellh/cli" ) @@ -33,7 +33,19 @@ const protocolVersionHeader = "x-terraform-protocol-version" var releaseHost = "https://releases.hashicorp.com" -var httpClient = cleanhttp.DefaultPooledClient() +var httpClient *http.Client + +func init() { + httpClient = httpclient.New() + + httpGetter := &getter.HttpGetter{ + Client: httpClient, + Netrc: true, + } + + getter.Getters["http"] = httpGetter + getter.Getters["https"] = httpGetter +} // An Installer maintains a local cache of plugins by downloading plugins // from an online repository. diff --git a/vendor/github.com/hashicorp/terraform/terraform/context.go b/vendor/github.com/hashicorp/terraform/terraform/context.go index 53a1231..f133cc2 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/context.go +++ b/vendor/github.com/hashicorp/terraform/terraform/context.go @@ -487,6 +487,13 @@ func (c *Context) Input(mode InputMode) error { func (c *Context) Apply() (*State, error) { defer c.acquireRun("apply")() + // Check there are no empty target parameter values + for _, target := range c.targets { + if target == "" { + return nil, fmt.Errorf("Target parameter must not have empty value") + } + } + // Copy our own state c.state = c.state.DeepCopy() @@ -524,6 +531,13 @@ func (c *Context) Apply() (*State, error) { func (c *Context) Plan() (*Plan, error) { defer c.acquireRun("plan")() + // Check there are no empty target parameter values + for _, target := range c.targets { + if target == "" { + return nil, fmt.Errorf("Target parameter must not have empty value") + } + } + p := &Plan{ Module: c.module, Vars: c.variables, diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go b/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go index 36c9845..b9b4806 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go +++ b/vendor/github.com/hashicorp/terraform/terraform/eval_apply.go @@ -227,11 +227,8 @@ func (n *EvalApplyProvisioners) Eval(ctx EvalContext) (interface{}, error) { state.Tainted = true } - if n.Error != nil { - *n.Error = multierror.Append(*n.Error, err) - } else { - return nil, err - } + *n.Error = multierror.Append(*n.Error, err) + return nil, err } { diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go b/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go index e48af84..3e5a84c 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go +++ b/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go @@ -144,8 +144,10 @@ func (n *EvalValidateProvisioner) validateConnConfig(connConfig *ResourceConfig) // For type=ssh only (enforced in ssh communicator) PrivateKey interface{} `mapstructure:"private_key"` + HostKey interface{} `mapstructure:"host_key"` Agent interface{} `mapstructure:"agent"` BastionHost interface{} `mapstructure:"bastion_host"` + BastionHostKey interface{} `mapstructure:"bastion_host_key"` BastionPort interface{} `mapstructure:"bastion_port"` BastionUser interface{} `mapstructure:"bastion_user"` BastionPassword interface{} `mapstructure:"bastion_password"` @@ -155,6 +157,7 @@ func (n *EvalValidateProvisioner) validateConnConfig(connConfig *ResourceConfig) // For type=winrm only (enforced in winrm communicator) HTTPS interface{} `mapstructure:"https"` Insecure interface{} `mapstructure:"insecure"` + NTLM interface{} `mapstructure:"use_ntlm"` CACert interface{} `mapstructure:"cacert"` } diff --git a/vendor/github.com/hashicorp/terraform/terraform/graph_builder_apply.go b/vendor/github.com/hashicorp/terraform/terraform/graph_builder_apply.go index 1f826e1..0c2b233 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/graph_builder_apply.go +++ b/vendor/github.com/hashicorp/terraform/terraform/graph_builder_apply.go @@ -119,11 +119,19 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer { // Connect references so ordering is correct &ReferenceTransformer{}, - // Reverse the edges to outputs and locals, so that + // Handle destroy time transformations for output and local values. + // Reverse the edges from outputs and locals, so that // interpolations don't fail during destroy. + // Create a destroy node for outputs to remove them from the state. + // Prune unreferenced values, which may have interpolations that can't + // be resolved. GraphTransformIf( func() bool { return b.Destroy }, - &DestroyValueReferenceTransformer{}, + GraphTransformMulti( + &DestroyValueReferenceTransformer{}, + &DestroyOutputTransformer{}, + &PruneUnusedValuesTransformer{}, + ), ), // Add the node to fix the state count boundaries diff --git a/vendor/github.com/hashicorp/terraform/terraform/interpolate.go b/vendor/github.com/hashicorp/terraform/terraform/interpolate.go index 456e7e3..4f4e178 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/interpolate.go +++ b/vendor/github.com/hashicorp/terraform/terraform/interpolate.go @@ -518,6 +518,16 @@ func (i *Interpolater) computeResourceVariable( return &v, err } + // special case for the "id" field which is usually also an attribute + if v.Field == "id" && r.Primary.ID != "" { + // This is usually pulled from the attributes, but is sometimes missing + // during destroy. We can return the ID field in this case. + // FIXME: there should only be one ID to rule them all. + log.Printf("[WARN] resource %s missing 'id' attribute", v.ResourceId()) + v, err := hil.InterfaceToVariable(r.Primary.ID) + return &v, err + } + // computed list or map attribute _, isList = r.Primary.Attributes[v.Field+".#"] _, isMap = r.Primary.Attributes[v.Field+".%"] @@ -655,6 +665,11 @@ func (i *Interpolater) computeResourceMultiVariable( continue } + if v.Field == "id" && r.Primary.ID != "" { + log.Printf("[WARN] resource %s missing 'id' attribute", v.ResourceId()) + values = append(values, r.Primary.ID) + } + // computed list or map attribute _, isList := r.Primary.Attributes[v.Field+".#"] _, isMap := r.Primary.Attributes[v.Field+".%"] @@ -774,7 +789,8 @@ func (i *Interpolater) resourceCountMax( // If we're NOT applying, then we assume we can read the count // from the state. Plan and so on may not have any state yet so // we do a full interpolation. - if i.Operation != walkApply { + // Don't forget walkDestroy, which is a special case of walkApply + if !(i.Operation == walkApply || i.Operation == walkDestroy) { if cr == nil { return 0, nil } @@ -805,7 +821,13 @@ func (i *Interpolater) resourceCountMax( // use "cr.Count()" but that doesn't work if the count is interpolated // and we can't guarantee that so we instead depend on the state. max := -1 - for k, _ := range ms.Resources { + for k, s := range ms.Resources { + // This resource may have been just removed, in which case the Primary + // may be nil, or just empty. + if s == nil || s.Primary == nil || len(s.Primary.Attributes) == 0 { + continue + } + // Get the index number for this resource index := "" if k == id { diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_local.go b/vendor/github.com/hashicorp/terraform/terraform/node_local.go index e58f1f9..d387222 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/node_local.go +++ b/vendor/github.com/hashicorp/terraform/terraform/node_local.go @@ -59,38 +59,8 @@ func (n *NodeLocal) References() []string { // GraphNodeEvalable func (n *NodeLocal) EvalTree() EvalNode { - return &EvalSequence{ - Nodes: []EvalNode{ - &EvalOpFilter{ - Ops: []walkOperation{ - walkInput, - walkValidate, - walkRefresh, - walkPlan, - walkApply, - }, - Node: &EvalSequence{ - Nodes: []EvalNode{ - &EvalLocal{ - Name: n.Config.Name, - Value: n.Config.RawConfig, - }, - }, - }, - }, - &EvalOpFilter{ - Ops: []walkOperation{ - walkPlanDestroy, - walkDestroy, - }, - Node: &EvalSequence{ - Nodes: []EvalNode{ - &EvalDeleteLocal{ - Name: n.Config.Name, - }, - }, - }, - }, - }, + return &EvalLocal{ + Name: n.Config.Name, + Value: n.Config.RawConfig, } } diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_output.go b/vendor/github.com/hashicorp/terraform/terraform/node_output.go index 4fd246a..83e9925 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/node_output.go +++ b/vendor/github.com/hashicorp/terraform/terraform/node_output.go @@ -83,19 +83,71 @@ func (n *NodeApplyableOutput) EvalTree() EvalNode { }, }, &EvalOpFilter{ - Ops: []walkOperation{walkRefresh, walkPlan, walkApply, walkValidate}, + Ops: []walkOperation{walkRefresh, walkPlan, walkApply, walkValidate, walkDestroy, walkPlanDestroy}, Node: &EvalWriteOutput{ Name: n.Config.Name, Sensitive: n.Config.Sensitive, Value: n.Config.RawConfig, }, }, - &EvalOpFilter{ - Ops: []walkOperation{walkDestroy, walkPlanDestroy}, - Node: &EvalDeleteOutput{ - Name: n.Config.Name, - }, - }, }, } } + +// NodeDestroyableOutput represents an output that is "destroybale": +// its application will remove the output from the state. +type NodeDestroyableOutput struct { + PathValue []string + Config *config.Output // Config is the output in the config +} + +func (n *NodeDestroyableOutput) Name() string { + result := fmt.Sprintf("output.%s (destroy)", n.Config.Name) + if len(n.PathValue) > 1 { + result = fmt.Sprintf("%s.%s", modulePrefixStr(n.PathValue), result) + } + + return result +} + +// GraphNodeSubPath +func (n *NodeDestroyableOutput) Path() []string { + return n.PathValue +} + +// RemovableIfNotTargeted +func (n *NodeDestroyableOutput) RemoveIfNotTargeted() bool { + // We need to add this so that this node will be removed if + // it isn't targeted or a dependency of a target. + return true +} + +// This will keep the destroy node in the graph if its corresponding output +// node is also in the destroy graph. +func (n *NodeDestroyableOutput) TargetDownstream(targetedDeps, untargetedDeps *dag.Set) bool { + return true +} + +// GraphNodeReferencer +func (n *NodeDestroyableOutput) References() []string { + var result []string + result = append(result, n.Config.DependsOn...) + result = append(result, ReferencesFromConfig(n.Config.RawConfig)...) + for _, v := range result { + split := strings.Split(v, "/") + for i, s := range split { + split[i] = s + ".destroy" + } + + result = append(result, strings.Join(split, "/")) + } + + return result +} + +// GraphNodeEvalable +func (n *NodeDestroyableOutput) EvalTree() EvalNode { + return &EvalDeleteOutput{ + Name: n.Config.Name, + } +} diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply.go index 9044806..40ee1cf 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply.go +++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply.go @@ -140,7 +140,10 @@ func (n *NodeApplyableResource) evalTreeDataResource( // Here we are just populating the interpolated value in-place // inside this RawConfig object, like we would in // NodeAbstractCountResource. - &EvalInterpolate{Config: n.Config.RawCount}, + &EvalInterpolate{ + Config: n.Config.RawCount, + ContinueOnErr: true, + }, // We need to re-interpolate the config here, rather than // just using the diff's values directly, because we've @@ -271,7 +274,10 @@ func (n *NodeApplyableResource) evalTreeManagedResource( // Here we are just populating the interpolated value in-place // inside this RawConfig object, like we would in // NodeAbstractCountResource. - &EvalInterpolate{Config: n.Config.RawCount}, + &EvalInterpolate{ + Config: n.Config.RawCount, + ContinueOnErr: true, + }, &EvalInterpolate{ Config: n.Config.RawConfig.Copy(), diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go index dbb64ed..697bd49 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go +++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_refresh.go @@ -213,10 +213,16 @@ func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResourceNoState( // Determine the dependencies for the state. stateDeps := n.StateReferences() + // n.Config can be nil if the config and state don't match + var raw *config.RawConfig + if n.Config != nil { + raw = n.Config.RawConfig.Copy() + } + return &EvalSequence{ Nodes: []EvalNode{ &EvalInterpolate{ - Config: n.Config.RawConfig.Copy(), + Config: raw, Resource: resource, Output: &resourceConfig, }, diff --git a/vendor/github.com/hashicorp/terraform/terraform/state.go b/vendor/github.com/hashicorp/terraform/terraform/state.go index 6a36348..04b14a6 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/state.go +++ b/vendor/github.com/hashicorp/terraform/terraform/state.go @@ -9,6 +9,7 @@ import ( "io" "io/ioutil" "log" + "os" "reflect" "sort" "strconv" @@ -16,10 +17,10 @@ import ( "sync" "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-uuid" "github.com/hashicorp/go-version" "github.com/hashicorp/terraform/config" "github.com/mitchellh/copystructure" - "github.com/satori/go.uuid" tfversion "github.com/hashicorp/terraform/version" ) @@ -706,7 +707,11 @@ func (s *State) EnsureHasLineage() { func (s *State) ensureHasLineage() { if s.Lineage == "" { - s.Lineage = uuid.NewV4().String() + lineage, err := uuid.GenerateUUID() + if err != nil { + panic(fmt.Errorf("Failed to generate lineage: %v", err)) + } + s.Lineage = lineage log.Printf("[DEBUG] New state was assigned lineage %q\n", s.Lineage) } else { log.Printf("[TRACE] Preserving existing state lineage %q\n", s.Lineage) @@ -1872,11 +1877,19 @@ var ErrNoState = errors.New("no state") // ReadState reads a state structure out of a reader in the format that // was written by WriteState. func ReadState(src io.Reader) (*State, error) { + // check for a nil file specifically, since that produces a platform + // specific error if we try to use it in a bufio.Reader. + if f, ok := src.(*os.File); ok && f == nil { + return nil, ErrNoState + } + buf := bufio.NewReader(src) + if _, err := buf.Peek(1); err != nil { - // the error is either io.EOF or "invalid argument", and both are from - // an empty state. - return nil, ErrNoState + if err == io.EOF { + return nil, ErrNoState + } + return nil, err } if err := testForV0State(buf); err != nil { diff --git a/vendor/github.com/hashicorp/terraform/terraform/transform_output.go b/vendor/github.com/hashicorp/terraform/terraform/transform_output.go index b260f4c..faa25e4 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/transform_output.go +++ b/vendor/github.com/hashicorp/terraform/terraform/transform_output.go @@ -1,7 +1,10 @@ package terraform import ( + "log" + "github.com/hashicorp/terraform/config/module" + "github.com/hashicorp/terraform/dag" ) // OutputTransformer is a GraphTransformer that adds all the outputs @@ -41,11 +44,6 @@ func (t *OutputTransformer) transform(g *Graph, m *module.Tree) error { // Add all outputs here for _, o := range os { - // Build the node. - // - // NOTE: For now this is just an "applyable" output. As we build - // new graph builders for the other operations I suspect we'll - // find a way to parameterize this, require new transforms, etc. node := &NodeApplyableOutput{ PathValue: normalizeModulePath(m.Path()), Config: o, @@ -57,3 +55,41 @@ func (t *OutputTransformer) transform(g *Graph, m *module.Tree) error { return nil } + +// DestroyOutputTransformer is a GraphTransformer that adds nodes to delete +// outputs during destroy. We need to do this to ensure that no stale outputs +// are ever left in the state. +type DestroyOutputTransformer struct { +} + +func (t *DestroyOutputTransformer) Transform(g *Graph) error { + for _, v := range g.Vertices() { + output, ok := v.(*NodeApplyableOutput) + if !ok { + continue + } + + // create the destroy node for this output + node := &NodeDestroyableOutput{ + PathValue: output.PathValue, + Config: output.Config, + } + + log.Printf("[TRACE] creating %s", node.Name()) + g.Add(node) + + deps, err := g.Descendents(v) + if err != nil { + return err + } + + // the destroy node must depend on the eval node + deps.Add(v) + + for _, d := range deps.List() { + log.Printf("[TRACE] %s depends on %s", node.Name(), dag.VertexName(d)) + g.Connect(dag.BasicEdge(node, d)) + } + } + return nil +} diff --git a/vendor/github.com/hashicorp/terraform/terraform/transform_reference.go b/vendor/github.com/hashicorp/terraform/terraform/transform_reference.go index 85a82a6..be8c7f9 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/transform_reference.go +++ b/vendor/github.com/hashicorp/terraform/terraform/transform_reference.go @@ -77,15 +77,14 @@ func (t *ReferenceTransformer) Transform(g *Graph) error { } // DestroyReferenceTransformer is a GraphTransformer that reverses the edges -// for nodes that depend on an Output or Local value. Output and local nodes are -// removed during destroy, so anything which depends on them must be evaluated -// first. These can't be interpolated during destroy, so the stored value must -// be used anyway hence they don't need to be re-evaluated. +// for locals and outputs that depend on other nodes which will be +// removed during destroy. If a destroy node is evaluated before the local or +// output value, it will be removed from the state, and the later interpolation +// will fail. type DestroyValueReferenceTransformer struct{} func (t *DestroyValueReferenceTransformer) Transform(g *Graph) error { vs := g.Vertices() - for _, v := range vs { switch v.(type) { case *NodeApplyableOutput, *NodeLocal: @@ -94,13 +93,62 @@ func (t *DestroyValueReferenceTransformer) Transform(g *Graph) error { continue } - // reverse any incoming edges so that the value is removed last - for _, e := range g.EdgesTo(v) { - source := e.Source() - log.Printf("[TRACE] output dep: %s", dag.VertexName(source)) + // reverse any outgoing edges so that the value is evaluated first. + for _, e := range g.EdgesFrom(v) { + target := e.Target() + + // only destroy nodes will be evaluated in reverse + if _, ok := target.(GraphNodeDestroyer); !ok { + continue + } + + log.Printf("[TRACE] output dep: %s", dag.VertexName(target)) g.RemoveEdge(e) - g.Connect(&DestroyEdge{S: v, T: source}) + g.Connect(&DestroyEdge{S: target, T: v}) + } + } + + return nil +} + +// PruneUnusedValuesTransformer is s GraphTransformer that removes local and +// output values which are not referenced in the graph. Since outputs and +// locals always need to be evaluated, if they reference a resource that is not +// available in the state the interpolation could fail. +type PruneUnusedValuesTransformer struct{} + +func (t *PruneUnusedValuesTransformer) Transform(g *Graph) error { + // this might need multiple runs in order to ensure that pruning a value + // doesn't effect a previously checked value. + for removed := 0; ; removed = 0 { + for _, v := range g.Vertices() { + switch v.(type) { + case *NodeApplyableOutput, *NodeLocal: + // OK + default: + continue + } + + dependants := g.UpEdges(v) + + switch dependants.Len() { + case 0: + // nothing at all depends on this + g.Remove(v) + removed++ + case 1: + // because an output's destroy node always depends on the output, + // we need to check for the case of a single destroy node. + d := dependants.List()[0] + if _, ok := d.(*NodeDestroyableOutput); ok { + g.Remove(v) + removed++ + } + } + } + if removed == 0 { + break } } diff --git a/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go b/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go index 0cfcb0a..af6defe 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go +++ b/vendor/github.com/hashicorp/terraform/terraform/transform_targets.go @@ -217,6 +217,12 @@ func filterPartialOutputs(v interface{}, targetedNodes *dag.Set, g *Graph) bool if _, ok := d.(*NodeCountBoundary); ok { continue } + + if !targetedNodes.Include(d) { + // this one is going to be removed, so it doesn't count + continue + } + // as soon as we see a real dependency, we mark this as // non-removable return true diff --git a/vendor/github.com/hashicorp/terraform/terraform/user_agent.go b/vendor/github.com/hashicorp/terraform/terraform/user_agent.go index 76bdae0..a42613e 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/user_agent.go +++ b/vendor/github.com/hashicorp/terraform/terraform/user_agent.go @@ -1,16 +1,13 @@ package terraform import ( - "fmt" - "runtime" - - "github.com/hashicorp/terraform/version" + "github.com/hashicorp/terraform/httpclient" ) -// The standard Terraform User-Agent format -const UserAgent = "Terraform %s (%s)" - // Generate a UserAgent string +// +// Deprecated: Use httpclient.UserAgentString if you are setting your +// own User-Agent header. func UserAgentString() string { - return fmt.Sprintf(UserAgent, version.String(), runtime.Version()) + return httpclient.UserAgentString() } diff --git a/vendor/vendor.json b/vendor/vendor.json index d532f22..714ab12 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -491,20 +491,26 @@ "versionExact": "v0.11.3" }, { - "checksumSHA1": "9d4zouxtH24HFa6RuUdq7lG3tgQ=", + "checksumSHA1": "ryCWu7RtMlYrAfSevaI7RtaXe98=", "path": "github.com/hashicorp/terraform/helper/resource", - "revision": "3802b14260603f90c7a1faf55994dcc8933e2069", - "revisionTime": "2018-01-31T20:48:39Z", - "version": "v0.11.3", - "versionExact": "v0.11.3" + "revision": "41e50bd32a8825a84535e353c3674af8ce799161", + "revisionTime": "2018-04-10T16:50:42Z", + "version": "v0.11.7", + "versionExact": "v0.11.7" }, { - "checksumSHA1": "Hnaw+m7E6HQ+me3G/p6pMLU7SXk=", + "checksumSHA1": "JHxGzmxcIS8NyLX9pGhK5beIra4=", "path": "github.com/hashicorp/terraform/helper/schema", - "revision": "3802b14260603f90c7a1faf55994dcc8933e2069", - "revisionTime": "2018-01-31T20:48:39Z", - "version": "v0.11.3", - "versionExact": "v0.11.3" + "revision": "41e50bd32a8825a84535e353c3674af8ce799161", + "revisionTime": "2018-04-10T16:50:42Z", + "version": "v0.11.7", + "versionExact": "v0.11.7" + }, + { + "checksumSHA1": "kD1ayilNruf2cES1LDfNZjYRscQ=", + "path": "github.com/hashicorp/terraform/httpclient", + "revision": "8d3bcd4f87f046b267959873e64aef7a36023005", + "revisionTime": "2018-04-16T23:27:52Z" }, { "checksumSHA1": "yFWmdS6yEJZpRJzUqd/mULqCYGk=", @@ -517,18 +523,18 @@ { "checksumSHA1": "DqaoG++NXRCfvH/OloneLWrM+3k=", "path": "github.com/hashicorp/terraform/plugin", - "revision": "3802b14260603f90c7a1faf55994dcc8933e2069", - "revisionTime": "2018-01-31T20:48:39Z", - "version": "v0.11.3", - "versionExact": "v0.11.3" + "revision": "41e50bd32a8825a84535e353c3674af8ce799161", + "revisionTime": "2018-04-10T16:50:42Z", + "version": "v0.11.7", + "versionExact": "v0.11.7" }, { - "checksumSHA1": "zSwwe4v/eJEBO1m1fLIeroxRbxE=", + "checksumSHA1": "tx5xrdiUWdAHqoRV5aEfALgT1aU=", "path": "github.com/hashicorp/terraform/plugin/discovery", - "revision": "3802b14260603f90c7a1faf55994dcc8933e2069", - "revisionTime": "2018-01-31T20:48:39Z", - "version": "v0.11.3", - "versionExact": "v0.11.3" + "revision": "41e50bd32a8825a84535e353c3674af8ce799161", + "revisionTime": "2018-04-10T16:50:42Z", + "version": "v0.11.7", + "versionExact": "v0.11.7" }, { "checksumSHA1": "JO9S/lHcLONtP+lUbr+8M6w4pzk=", @@ -579,12 +585,12 @@ "versionExact": "v0.11.3" }, { - "checksumSHA1": "4iyhUJFJqtCont3sddyqSD3DFWg=", + "checksumSHA1": "lHCKONqlaHsn5cEaYltad7dvRq8=", "path": "github.com/hashicorp/terraform/terraform", - "revision": "3802b14260603f90c7a1faf55994dcc8933e2069", - "revisionTime": "2018-01-31T20:48:39Z", - "version": "v0.11.3", - "versionExact": "v0.11.3" + "revision": "41e50bd32a8825a84535e353c3674af8ce799161", + "revisionTime": "2018-04-10T16:50:42Z", + "version": "v0.11.7", + "versionExact": "v0.11.7" }, { "checksumSHA1": "+K+oz9mMTmQMxIA3KVkGRfjvm9I=",