aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/config
diff options
context:
space:
mode:
authorNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
committerNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
commit107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch)
treeca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/github.com/hashicorp/terraform/config
parent844b5a68d8af4791755b8f0ad293cc99f5959183 (diff)
downloadterraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip
Upgrade to 0.12
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/config')
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/decoder_spec.go97
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/doc.go14
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/implied_type.go21
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/internal_validate.go92
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/nestingmode_string.go16
-rw-r--r--vendor/github.com/hashicorp/terraform/config/configschema/schema.go107
-rw-r--r--vendor/github.com/hashicorp/terraform/config/hcl2shim/flatmap.go424
-rw-r--r--vendor/github.com/hashicorp/terraform/config/hcl2shim/paths.go276
-rw-r--r--vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go109
-rw-r--r--vendor/github.com/hashicorp/terraform/config/hcl2shim/values_equiv.go214
-rw-r--r--vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go185
-rw-r--r--vendor/github.com/hashicorp/terraform/config/module/storage.go23
-rw-r--r--vendor/github.com/hashicorp/terraform/config/resource_mode_string.go8
13 files changed, 1128 insertions, 458 deletions
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/decoder_spec.go b/vendor/github.com/hashicorp/terraform/config/configschema/decoder_spec.go
deleted file mode 100644
index 2b1b0ca..0000000
--- a/vendor/github.com/hashicorp/terraform/config/configschema/decoder_spec.go
+++ /dev/null
@@ -1,97 +0,0 @@
1package configschema
2
3import (
4 "github.com/hashicorp/hcl2/hcldec"
5 "github.com/zclconf/go-cty/cty"
6)
7
8var mapLabelNames = []string{"key"}
9
10// DecoderSpec returns a hcldec.Spec that can be used to decode a HCL Body
11// using the facilities in the hcldec package.
12//
13// The returned specification is guaranteed to return a value of the same type
14// returned by method ImpliedType, but it may contain null or unknown values if
15// any of the block attributes are defined as optional and/or computed
16// respectively.
17func (b *Block) DecoderSpec() hcldec.Spec {
18 ret := hcldec.ObjectSpec{}
19 if b == nil {
20 return ret
21 }
22
23 for name, attrS := range b.Attributes {
24 switch {
25 case attrS.Computed && attrS.Optional:
26 // In this special case we use an unknown value as a default
27 // to get the intended behavior that the result is computed
28 // unless it has been explicitly set in config.
29 ret[name] = &hcldec.DefaultSpec{
30 Primary: &hcldec.AttrSpec{
31 Name: name,
32 Type: attrS.Type,
33 },
34 Default: &hcldec.LiteralSpec{
35 Value: cty.UnknownVal(attrS.Type),
36 },
37 }
38 case attrS.Computed:
39 ret[name] = &hcldec.LiteralSpec{
40 Value: cty.UnknownVal(attrS.Type),
41 }
42 default:
43 ret[name] = &hcldec.AttrSpec{
44 Name: name,
45 Type: attrS.Type,
46 Required: attrS.Required,
47 }
48 }
49 }
50
51 for name, blockS := range b.BlockTypes {
52 if _, exists := ret[name]; exists {
53 // This indicates an invalid schema, since it's not valid to
54 // define both an attribute and a block type of the same name.
55 // However, we don't raise this here since it's checked by
56 // InternalValidate.
57 continue
58 }
59
60 childSpec := blockS.Block.DecoderSpec()
61
62 switch blockS.Nesting {
63 case NestingSingle:
64 ret[name] = &hcldec.BlockSpec{
65 TypeName: name,
66 Nested: childSpec,
67 Required: blockS.MinItems == 1 && blockS.MaxItems >= 1,
68 }
69 case NestingList:
70 ret[name] = &hcldec.BlockListSpec{
71 TypeName: name,
72 Nested: childSpec,
73 MinItems: blockS.MinItems,
74 MaxItems: blockS.MaxItems,
75 }
76 case NestingSet:
77 ret[name] = &hcldec.BlockSetSpec{
78 TypeName: name,
79 Nested: childSpec,
80 MinItems: blockS.MinItems,
81 MaxItems: blockS.MaxItems,
82 }
83 case NestingMap:
84 ret[name] = &hcldec.BlockMapSpec{
85 TypeName: name,
86 Nested: childSpec,
87 LabelNames: mapLabelNames,
88 }
89 default:
90 // Invalid nesting type is just ignored. It's checked by
91 // InternalValidate.
92 continue
93 }
94 }
95
96 return ret
97}
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/doc.go b/vendor/github.com/hashicorp/terraform/config/configschema/doc.go
deleted file mode 100644
index caf8d73..0000000
--- a/vendor/github.com/hashicorp/terraform/config/configschema/doc.go
+++ /dev/null
@@ -1,14 +0,0 @@
1// Package configschema contains types for describing the expected structure
2// of a configuration block whose shape is not known until runtime.
3//
4// For example, this is used to describe the expected contents of a resource
5// configuration block, which is defined by the corresponding provider plugin
6// and thus not compiled into Terraform core.
7//
8// A configschema primarily describes the shape of configuration, but it is
9// also suitable for use with other structures derived from the configuration,
10// such as the cached state of a resource or a resource diff.
11//
12// This package should not be confused with the package helper/schema, which
13// is the higher-level helper library used to implement providers themselves.
14package configschema
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/implied_type.go b/vendor/github.com/hashicorp/terraform/config/configschema/implied_type.go
deleted file mode 100644
index 67324eb..0000000
--- a/vendor/github.com/hashicorp/terraform/config/configschema/implied_type.go
+++ /dev/null
@@ -1,21 +0,0 @@
1package configschema
2
3import (
4 "github.com/hashicorp/hcl2/hcldec"
5 "github.com/zclconf/go-cty/cty"
6)
7
8// ImpliedType returns the cty.Type that would result from decoding a
9// configuration block using the receiving block schema.
10//
11// ImpliedType always returns a result, even if the given schema is
12// inconsistent. Code that creates configschema.Block objects should be
13// tested using the InternalValidate method to detect any inconsistencies
14// that would cause this method to fall back on defaults and assumptions.
15func (b *Block) ImpliedType() cty.Type {
16 if b == nil {
17 return cty.EmptyObject
18 }
19
20 return hcldec.ImpliedType(b.DecoderSpec())
21}
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/internal_validate.go b/vendor/github.com/hashicorp/terraform/config/configschema/internal_validate.go
deleted file mode 100644
index 33cbe88..0000000
--- a/vendor/github.com/hashicorp/terraform/config/configschema/internal_validate.go
+++ /dev/null
@@ -1,92 +0,0 @@
1package configschema
2
3import (
4 "fmt"
5 "regexp"
6
7 "github.com/zclconf/go-cty/cty"
8
9 multierror "github.com/hashicorp/go-multierror"
10)
11
12var validName = regexp.MustCompile(`^[a-z0-9_]+$`)
13
14// InternalValidate returns an error if the receiving block and its child
15// schema definitions have any consistencies with the documented rules for
16// valid schema.
17//
18// This is intended to be used within unit tests to detect when a given
19// schema is invalid.
20func (b *Block) InternalValidate() error {
21 if b == nil {
22 return fmt.Errorf("top-level block schema is nil")
23 }
24 return b.internalValidate("", nil)
25
26}
27
28func (b *Block) internalValidate(prefix string, err error) error {
29 for name, attrS := range b.Attributes {
30 if attrS == nil {
31 err = multierror.Append(err, fmt.Errorf("%s%s: attribute schema is nil", prefix, name))
32 continue
33 }
34 if !validName.MatchString(name) {
35 err = multierror.Append(err, fmt.Errorf("%s%s: name may contain only lowercase letters, digits and underscores", prefix, name))
36 }
37 if attrS.Optional == false && attrS.Required == false && attrS.Computed == false {
38 err = multierror.Append(err, fmt.Errorf("%s%s: must set Optional, Required or Computed", prefix, name))
39 }
40 if attrS.Optional && attrS.Required {
41 err = multierror.Append(err, fmt.Errorf("%s%s: cannot set both Optional and Required", prefix, name))
42 }
43 if attrS.Computed && attrS.Required {
44 err = multierror.Append(err, fmt.Errorf("%s%s: cannot set both Computed and Required", prefix, name))
45 }
46 if attrS.Type == cty.NilType {
47 err = multierror.Append(err, fmt.Errorf("%s%s: Type must be set to something other than cty.NilType", prefix, name))
48 }
49 }
50
51 for name, blockS := range b.BlockTypes {
52 if blockS == nil {
53 err = multierror.Append(err, fmt.Errorf("%s%s: block schema is nil", prefix, name))
54 continue
55 }
56
57 if _, isAttr := b.Attributes[name]; isAttr {
58 err = multierror.Append(err, fmt.Errorf("%s%s: name defined as both attribute and child block type", prefix, name))
59 } else if !validName.MatchString(name) {
60 err = multierror.Append(err, fmt.Errorf("%s%s: name may contain only lowercase letters, digits and underscores", prefix, name))
61 }
62
63 if blockS.MinItems < 0 || blockS.MaxItems < 0 {
64 err = multierror.Append(err, fmt.Errorf("%s%s: MinItems and MaxItems must both be greater than zero", prefix, name))
65 }
66
67 switch blockS.Nesting {
68 case NestingSingle:
69 switch {
70 case blockS.MinItems != blockS.MaxItems:
71 err = multierror.Append(err, fmt.Errorf("%s%s: MinItems and MaxItems must match in NestingSingle mode", prefix, name))
72 case blockS.MinItems < 0 || blockS.MinItems > 1:
73 err = multierror.Append(err, fmt.Errorf("%s%s: MinItems and MaxItems must be set to either 0 or 1 in NestingSingle mode", prefix, name))
74 }
75 case NestingList, NestingSet:
76 if blockS.MinItems > blockS.MaxItems && blockS.MaxItems != 0 {
77 err = multierror.Append(err, fmt.Errorf("%s%s: MinItems must be less than or equal to MaxItems in %s mode", prefix, name, blockS.Nesting))
78 }
79 case NestingMap:
80 if blockS.MinItems != 0 || blockS.MaxItems != 0 {
81 err = multierror.Append(err, fmt.Errorf("%s%s: MinItems and MaxItems must both be 0 in NestingMap mode", prefix, name))
82 }
83 default:
84 err = multierror.Append(err, fmt.Errorf("%s%s: invalid nesting mode %s", prefix, name, blockS.Nesting))
85 }
86
87 subPrefix := prefix + name + "."
88 err = blockS.Block.internalValidate(subPrefix, err)
89 }
90
91 return err
92}
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/nestingmode_string.go b/vendor/github.com/hashicorp/terraform/config/configschema/nestingmode_string.go
deleted file mode 100644
index 6cb9313..0000000
--- a/vendor/github.com/hashicorp/terraform/config/configschema/nestingmode_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
1// Code generated by "stringer -type=NestingMode"; DO NOT EDIT.
2
3package configschema
4
5import "strconv"
6
7const _NestingMode_name = "nestingModeInvalidNestingSingleNestingListNestingSetNestingMap"
8
9var _NestingMode_index = [...]uint8{0, 18, 31, 42, 52, 62}
10
11func (i NestingMode) String() string {
12 if i < 0 || i >= NestingMode(len(_NestingMode_index)-1) {
13 return "NestingMode(" + strconv.FormatInt(int64(i), 10) + ")"
14 }
15 return _NestingMode_name[_NestingMode_index[i]:_NestingMode_index[i+1]]
16}
diff --git a/vendor/github.com/hashicorp/terraform/config/configschema/schema.go b/vendor/github.com/hashicorp/terraform/config/configschema/schema.go
deleted file mode 100644
index 9a8ee55..0000000
--- a/vendor/github.com/hashicorp/terraform/config/configschema/schema.go
+++ /dev/null
@@ -1,107 +0,0 @@
1package configschema
2
3import (
4 "github.com/zclconf/go-cty/cty"
5)
6
7// Block represents a configuration block.
8//
9// "Block" here is a logical grouping construct, though it happens to map
10// directly onto the physical block syntax of Terraform's native configuration
11// syntax. It may be a more a matter of convention in other syntaxes, such as
12// JSON.
13//
14// When converted to a value, a Block always becomes an instance of an object
15// type derived from its defined attributes and nested blocks
16type Block struct {
17 // Attributes describes any attributes that may appear directly inside
18 // the block.
19 Attributes map[string]*Attribute
20
21 // BlockTypes describes any nested block types that may appear directly
22 // inside the block.
23 BlockTypes map[string]*NestedBlock
24}
25
26// Attribute represents a configuration attribute, within a block.
27type Attribute struct {
28 // Type is a type specification that the attribute's value must conform to.
29 Type cty.Type
30
31 // Required, if set to true, specifies that an omitted or null value is
32 // not permitted.
33 Required bool
34
35 // Optional, if set to true, specifies that an omitted or null value is
36 // permitted. This field conflicts with Required.
37 Optional bool
38
39 // Computed, if set to true, specifies that the value comes from the
40 // provider rather than from configuration. If combined with Optional,
41 // then the config may optionally provide an overridden value.
42 Computed bool
43
44 // Sensitive, if set to true, indicates that an attribute may contain
45 // sensitive information.
46 //
47 // At present nothing is done with this information, but callers are
48 // encouraged to set it where appropriate so that it may be used in the
49 // future to help Terraform mask sensitive information. (Terraform
50 // currently achieves this in a limited sense via other mechanisms.)
51 Sensitive bool
52}
53
54// NestedBlock represents the embedding of one block within another.
55type NestedBlock struct {
56 // Block is the description of the block that's nested.
57 Block
58
59 // Nesting provides the nesting mode for the child block, which determines
60 // how many instances of the block are allowed, how many labels it expects,
61 // and how the resulting data will be converted into a data structure.
62 Nesting NestingMode
63
64 // MinItems and MaxItems set, for the NestingList and NestingSet nesting
65 // modes, lower and upper limits on the number of child blocks allowed
66 // of the given type. If both are left at zero, no limit is applied.
67 //
68 // As a special case, both values can be set to 1 for NestingSingle in
69 // order to indicate that a particular single block is required.
70 //
71 // These fields are ignored for other nesting modes and must both be left
72 // at zero.
73 MinItems, MaxItems int
74}
75
76// NestingMode is an enumeration of modes for nesting blocks inside other
77// blocks.
78type NestingMode int
79
80//go:generate stringer -type=NestingMode
81
82const (
83 nestingModeInvalid NestingMode = iota
84
85 // NestingSingle indicates that only a single instance of a given
86 // block type is permitted, with no labels, and its content should be
87 // provided directly as an object value.
88 NestingSingle
89
90 // NestingList indicates that multiple blocks of the given type are
91 // permitted, with no labels, and that their corresponding objects should
92 // be provided in a list.
93 NestingList
94
95 // NestingSet indicates that multiple blocks of the given type are
96 // permitted, with no labels, and that their corresponding objects should
97 // be provided in a set.
98 NestingSet
99
100 // NestingMap indicates that multiple blocks of the given type are
101 // permitted, each with a single label, and that their corresponding
102 // objects should be provided in a map whose keys are the labels.
103 //
104 // It's an error, therefore, to use the same label value on multiple
105 // blocks.
106 NestingMap
107)
diff --git a/vendor/github.com/hashicorp/terraform/config/hcl2shim/flatmap.go b/vendor/github.com/hashicorp/terraform/config/hcl2shim/flatmap.go
new file mode 100644
index 0000000..bb4228d
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/hcl2shim/flatmap.go
@@ -0,0 +1,424 @@
1package hcl2shim
2
3import (
4 "fmt"
5 "strconv"
6 "strings"
7
8 "github.com/zclconf/go-cty/cty/convert"
9
10 "github.com/zclconf/go-cty/cty"
11)
12
13// FlatmapValueFromHCL2 converts a value from HCL2 (really, from the cty dynamic
14// types library that HCL2 uses) to a map compatible with what would be
15// produced by the "flatmap" package.
16//
17// The type of the given value informs the structure of the resulting map.
18// The value must be of an object type or this function will panic.
19//
20// Flatmap values can only represent maps when they are of primitive types,
21// so the given value must not have any maps of complex types or the result
22// is undefined.
23func FlatmapValueFromHCL2(v cty.Value) map[string]string {
24 if v.IsNull() {
25 return nil
26 }
27
28 if !v.Type().IsObjectType() {
29 panic(fmt.Sprintf("HCL2ValueFromFlatmap called on %#v", v.Type()))
30 }
31
32 m := make(map[string]string)
33 flatmapValueFromHCL2Map(m, "", v)
34 return m
35}
36
37func flatmapValueFromHCL2Value(m map[string]string, key string, val cty.Value) {
38 ty := val.Type()
39 switch {
40 case ty.IsPrimitiveType() || ty == cty.DynamicPseudoType:
41 flatmapValueFromHCL2Primitive(m, key, val)
42 case ty.IsObjectType() || ty.IsMapType():
43 flatmapValueFromHCL2Map(m, key+".", val)
44 case ty.IsTupleType() || ty.IsListType() || ty.IsSetType():
45 flatmapValueFromHCL2Seq(m, key+".", val)
46 default:
47 panic(fmt.Sprintf("cannot encode %s to flatmap", ty.FriendlyName()))
48 }
49}
50
51func flatmapValueFromHCL2Primitive(m map[string]string, key string, val cty.Value) {
52 if !val.IsKnown() {
53 m[key] = UnknownVariableValue
54 return
55 }
56 if val.IsNull() {
57 // Omit entirely
58 return
59 }
60
61 var err error
62 val, err = convert.Convert(val, cty.String)
63 if err != nil {
64 // Should not be possible, since all primitive types can convert to string.
65 panic(fmt.Sprintf("invalid primitive encoding to flatmap: %s", err))
66 }
67 m[key] = val.AsString()
68}
69
70func flatmapValueFromHCL2Map(m map[string]string, prefix string, val cty.Value) {
71 if val.IsNull() {
72 // Omit entirely
73 return
74 }
75 if !val.IsKnown() {
76 switch {
77 case val.Type().IsObjectType():
78 // Whole objects can't be unknown in flatmap, so instead we'll
79 // just write all of the attribute values out as unknown.
80 for name, aty := range val.Type().AttributeTypes() {
81 flatmapValueFromHCL2Value(m, prefix+name, cty.UnknownVal(aty))
82 }
83 default:
84 m[prefix+"%"] = UnknownVariableValue
85 }
86 return
87 }
88
89 len := 0
90 for it := val.ElementIterator(); it.Next(); {
91 ak, av := it.Element()
92 name := ak.AsString()
93 flatmapValueFromHCL2Value(m, prefix+name, av)
94 len++
95 }
96 if !val.Type().IsObjectType() { // objects don't have an explicit count included, since their attribute count is fixed
97 m[prefix+"%"] = strconv.Itoa(len)
98 }
99}
100
101func flatmapValueFromHCL2Seq(m map[string]string, prefix string, val cty.Value) {
102 if val.IsNull() {
103 // Omit entirely
104 return
105 }
106 if !val.IsKnown() {
107 m[prefix+"#"] = UnknownVariableValue
108 return
109 }
110
111 // For sets this won't actually generate exactly what helper/schema would've
112 // generated, because we don't have access to the set key function it
113 // would've used. However, in practice it doesn't actually matter what the
114 // keys are as long as they are unique, so we'll just generate sequential
115 // indexes for them as if it were a list.
116 //
117 // An important implication of this, however, is that the set ordering will
118 // not be consistent across mutations and so different keys may be assigned
119 // to the same value when round-tripping. Since this shim is intended to
120 // be short-lived and not used for round-tripping, we accept this.
121 i := 0
122 for it := val.ElementIterator(); it.Next(); {
123 _, av := it.Element()
124 key := prefix + strconv.Itoa(i)
125 flatmapValueFromHCL2Value(m, key, av)
126 i++
127 }
128 m[prefix+"#"] = strconv.Itoa(i)
129}
130
131// HCL2ValueFromFlatmap converts a map compatible with what would be produced
132// by the "flatmap" package to a HCL2 (really, the cty dynamic types library
133// that HCL2 uses) object type.
134//
135// The intended result type must be provided in order to guide how the
136// map contents are decoded. This must be an object type or this function
137// will panic.
138//
139// Flatmap values can only represent maps when they are of primitive types,
140// so the given type must not have any maps of complex types or the result
141// is undefined.
142//
143// The result may contain null values if the given map does not contain keys
144// for all of the different key paths implied by the given type.
145func HCL2ValueFromFlatmap(m map[string]string, ty cty.Type) (cty.Value, error) {
146 if m == nil {
147 return cty.NullVal(ty), nil
148 }
149 if !ty.IsObjectType() {
150 panic(fmt.Sprintf("HCL2ValueFromFlatmap called on %#v", ty))
151 }
152
153 return hcl2ValueFromFlatmapObject(m, "", ty.AttributeTypes())
154}
155
156func hcl2ValueFromFlatmapValue(m map[string]string, key string, ty cty.Type) (cty.Value, error) {
157 var val cty.Value
158 var err error
159 switch {
160 case ty.IsPrimitiveType():
161 val, err = hcl2ValueFromFlatmapPrimitive(m, key, ty)
162 case ty.IsObjectType():
163 val, err = hcl2ValueFromFlatmapObject(m, key+".", ty.AttributeTypes())
164 case ty.IsTupleType():
165 val, err = hcl2ValueFromFlatmapTuple(m, key+".", ty.TupleElementTypes())
166 case ty.IsMapType():
167 val, err = hcl2ValueFromFlatmapMap(m, key+".", ty)
168 case ty.IsListType():
169 val, err = hcl2ValueFromFlatmapList(m, key+".", ty)
170 case ty.IsSetType():
171 val, err = hcl2ValueFromFlatmapSet(m, key+".", ty)
172 default:
173 err = fmt.Errorf("cannot decode %s from flatmap", ty.FriendlyName())
174 }
175
176 if err != nil {
177 return cty.DynamicVal, err
178 }
179 return val, nil
180}
181
182func hcl2ValueFromFlatmapPrimitive(m map[string]string, key string, ty cty.Type) (cty.Value, error) {
183 rawVal, exists := m[key]
184 if !exists {
185 return cty.NullVal(ty), nil
186 }
187 if rawVal == UnknownVariableValue {
188 return cty.UnknownVal(ty), nil
189 }
190
191 var err error
192 val := cty.StringVal(rawVal)
193 val, err = convert.Convert(val, ty)
194 if err != nil {
195 // This should never happen for _valid_ input, but flatmap data might
196 // be tampered with by the user and become invalid.
197 return cty.DynamicVal, fmt.Errorf("invalid value for %q in state: %s", key, err)
198 }
199
200 return val, nil
201}
202
203func hcl2ValueFromFlatmapObject(m map[string]string, prefix string, atys map[string]cty.Type) (cty.Value, error) {
204 vals := make(map[string]cty.Value)
205 for name, aty := range atys {
206 val, err := hcl2ValueFromFlatmapValue(m, prefix+name, aty)
207 if err != nil {
208 return cty.DynamicVal, err
209 }
210 vals[name] = val
211 }
212 return cty.ObjectVal(vals), nil
213}
214
215func hcl2ValueFromFlatmapTuple(m map[string]string, prefix string, etys []cty.Type) (cty.Value, error) {
216 var vals []cty.Value
217
218 // if the container is unknown, there is no count string
219 listName := strings.TrimRight(prefix, ".")
220 if m[listName] == UnknownVariableValue {
221 return cty.UnknownVal(cty.Tuple(etys)), nil
222 }
223
224 countStr, exists := m[prefix+"#"]
225 if !exists {
226 return cty.NullVal(cty.Tuple(etys)), nil
227 }
228 if countStr == UnknownVariableValue {
229 return cty.UnknownVal(cty.Tuple(etys)), nil
230 }
231
232 count, err := strconv.Atoi(countStr)
233 if err != nil {
234 return cty.DynamicVal, fmt.Errorf("invalid count value for %q in state: %s", prefix, err)
235 }
236 if count != len(etys) {
237 return cty.DynamicVal, fmt.Errorf("wrong number of values for %q in state: got %d, but need %d", prefix, count, len(etys))
238 }
239
240 vals = make([]cty.Value, len(etys))
241 for i, ety := range etys {
242 key := prefix + strconv.Itoa(i)
243 val, err := hcl2ValueFromFlatmapValue(m, key, ety)
244 if err != nil {
245 return cty.DynamicVal, err
246 }
247 vals[i] = val
248 }
249 return cty.TupleVal(vals), nil
250}
251
252func hcl2ValueFromFlatmapMap(m map[string]string, prefix string, ty cty.Type) (cty.Value, error) {
253 vals := make(map[string]cty.Value)
254 ety := ty.ElementType()
255
256 // if the container is unknown, there is no count string
257 listName := strings.TrimRight(prefix, ".")
258 if m[listName] == UnknownVariableValue {
259 return cty.UnknownVal(ty), nil
260 }
261
262 // We actually don't really care about the "count" of a map for our
263 // purposes here, but we do need to check if it _exists_ in order to
264 // recognize the difference between null (not set at all) and empty.
265 if strCount, exists := m[prefix+"%"]; !exists {
266 return cty.NullVal(ty), nil
267 } else if strCount == UnknownVariableValue {
268 return cty.UnknownVal(ty), nil
269 }
270
271 for fullKey := range m {
272 if !strings.HasPrefix(fullKey, prefix) {
273 continue
274 }
275
276 // The flatmap format doesn't allow us to distinguish between keys
277 // that contain periods and nested objects, so by convention a
278 // map is only ever of primitive type in flatmap, and we just assume
279 // that the remainder of the raw key (dots and all) is the key we
280 // want in the result value.
281 key := fullKey[len(prefix):]
282 if key == "%" {
283 // Ignore the "count" key
284 continue
285 }
286
287 val, err := hcl2ValueFromFlatmapValue(m, fullKey, ety)
288 if err != nil {
289 return cty.DynamicVal, err
290 }
291 vals[key] = val
292 }
293
294 if len(vals) == 0 {
295 return cty.MapValEmpty(ety), nil
296 }
297 return cty.MapVal(vals), nil
298}
299
300func hcl2ValueFromFlatmapList(m map[string]string, prefix string, ty cty.Type) (cty.Value, error) {
301 var vals []cty.Value
302
303 // if the container is unknown, there is no count string
304 listName := strings.TrimRight(prefix, ".")
305 if m[listName] == UnknownVariableValue {
306 return cty.UnknownVal(ty), nil
307 }
308
309 countStr, exists := m[prefix+"#"]
310 if !exists {
311 return cty.NullVal(ty), nil
312 }
313 if countStr == UnknownVariableValue {
314 return cty.UnknownVal(ty), nil
315 }
316
317 count, err := strconv.Atoi(countStr)
318 if err != nil {
319 return cty.DynamicVal, fmt.Errorf("invalid count value for %q in state: %s", prefix, err)
320 }
321
322 ety := ty.ElementType()
323 if count == 0 {
324 return cty.ListValEmpty(ety), nil
325 }
326
327 vals = make([]cty.Value, count)
328 for i := 0; i < count; i++ {
329 key := prefix + strconv.Itoa(i)
330 val, err := hcl2ValueFromFlatmapValue(m, key, ety)
331 if err != nil {
332 return cty.DynamicVal, err
333 }
334 vals[i] = val
335 }
336
337 return cty.ListVal(vals), nil
338}
339
340func hcl2ValueFromFlatmapSet(m map[string]string, prefix string, ty cty.Type) (cty.Value, error) {
341 var vals []cty.Value
342 ety := ty.ElementType()
343
344 // if the container is unknown, there is no count string
345 listName := strings.TrimRight(prefix, ".")
346 if m[listName] == UnknownVariableValue {
347 return cty.UnknownVal(ty), nil
348 }
349
350 strCount, exists := m[prefix+"#"]
351 if !exists {
352 return cty.NullVal(ty), nil
353 } else if strCount == UnknownVariableValue {
354 return cty.UnknownVal(ty), nil
355 }
356
357 // Keep track of keys we've seen, se we don't add the same set value
358 // multiple times. The cty.Set will normally de-duplicate values, but we may
359 // have unknown values that would not show as equivalent.
360 seen := map[string]bool{}
361
362 for fullKey := range m {
363 if !strings.HasPrefix(fullKey, prefix) {
364 continue
365 }
366 subKey := fullKey[len(prefix):]
367 if subKey == "#" {
368 // Ignore the "count" key
369 continue
370 }
371 key := fullKey
372 if dot := strings.IndexByte(subKey, '.'); dot != -1 {
373 key = fullKey[:dot+len(prefix)]
374 }
375
376 if seen[key] {
377 continue
378 }
379
380 seen[key] = true
381
382 // The flatmap format doesn't allow us to distinguish between keys
383 // that contain periods and nested objects, so by convention a
384 // map is only ever of primitive type in flatmap, and we just assume
385 // that the remainder of the raw key (dots and all) is the key we
386 // want in the result value.
387
388 val, err := hcl2ValueFromFlatmapValue(m, key, ety)
389 if err != nil {
390 return cty.DynamicVal, err
391 }
392 vals = append(vals, val)
393 }
394
395 if len(vals) == 0 && strCount == "1" {
396 // An empty set wouldn't be represented in the flatmap, so this must be
397 // a single empty object since the count is actually 1.
398 // Add an appropriately typed null value to the set.
399 var val cty.Value
400 switch {
401 case ety.IsMapType():
402 val = cty.MapValEmpty(ety)
403 case ety.IsListType():
404 val = cty.ListValEmpty(ety)
405 case ety.IsSetType():
406 val = cty.SetValEmpty(ety)
407 case ety.IsObjectType():
408 // TODO: cty.ObjectValEmpty
409 objectMap := map[string]cty.Value{}
410 for attr, ty := range ety.AttributeTypes() {
411 objectMap[attr] = cty.NullVal(ty)
412 }
413 val = cty.ObjectVal(objectMap)
414 default:
415 val = cty.NullVal(ety)
416 }
417 vals = append(vals, val)
418
419 } else if len(vals) == 0 {
420 return cty.SetValEmpty(ety), nil
421 }
422
423 return cty.SetVal(vals), nil
424}
diff --git a/vendor/github.com/hashicorp/terraform/config/hcl2shim/paths.go b/vendor/github.com/hashicorp/terraform/config/hcl2shim/paths.go
new file mode 100644
index 0000000..3403c02
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/hcl2shim/paths.go
@@ -0,0 +1,276 @@
1package hcl2shim
2
3import (
4 "fmt"
5 "reflect"
6 "strconv"
7 "strings"
8
9 "github.com/zclconf/go-cty/cty"
10)
11
12// RequiresReplace takes a list of flatmapped paths from a
13// InstanceDiff.Attributes along with the corresponding cty.Type, and returns
14// the list of the cty.Paths that are flagged as causing the resource
15// replacement (RequiresNew).
16// This will filter out redundant paths, paths that refer to flatmapped indexes
17// (e.g. "#", "%"), and will return any changes within a set as the path to the
18// set itself.
19func RequiresReplace(attrs []string, ty cty.Type) ([]cty.Path, error) {
20 var paths []cty.Path
21
22 for _, attr := range attrs {
23 p, err := requiresReplacePath(attr, ty)
24 if err != nil {
25 return nil, err
26 }
27
28 paths = append(paths, p)
29 }
30
31 // now trim off any trailing paths that aren't GetAttrSteps, since only an
32 // attribute itself can require replacement
33 paths = trimPaths(paths)
34
35 // There may be redundant paths due to set elements or index attributes
36 // Do some ugly n^2 filtering, but these are always fairly small sets.
37 for i := 0; i < len(paths)-1; i++ {
38 for j := i + 1; j < len(paths); j++ {
39 if reflect.DeepEqual(paths[i], paths[j]) {
40 // swap the tail and slice it off
41 paths[j], paths[len(paths)-1] = paths[len(paths)-1], paths[j]
42 paths = paths[:len(paths)-1]
43 j--
44 }
45 }
46 }
47
48 return paths, nil
49}
50
51// trimPaths removes any trailing steps that aren't of type GetAttrSet, since
52// only an attribute itself can require replacement
53func trimPaths(paths []cty.Path) []cty.Path {
54 var trimmed []cty.Path
55 for _, path := range paths {
56 path = trimPath(path)
57 if len(path) > 0 {
58 trimmed = append(trimmed, path)
59 }
60 }
61 return trimmed
62}
63
64func trimPath(path cty.Path) cty.Path {
65 for len(path) > 0 {
66 _, isGetAttr := path[len(path)-1].(cty.GetAttrStep)
67 if isGetAttr {
68 break
69 }
70 path = path[:len(path)-1]
71 }
72 return path
73}
74
75// requiresReplacePath takes a key from a flatmap along with the cty.Type
76// describing the structure, and returns the cty.Path that would be used to
77// reference the nested value in the data structure.
78// This is used specifically to record the RequiresReplace attributes from a
79// ResourceInstanceDiff.
80func requiresReplacePath(k string, ty cty.Type) (cty.Path, error) {
81 if k == "" {
82 return nil, nil
83 }
84 if !ty.IsObjectType() {
85 panic(fmt.Sprintf("requires replace path on non-object type: %#v", ty))
86 }
87
88 path, err := pathFromFlatmapKeyObject(k, ty.AttributeTypes())
89 if err != nil {
90 return path, fmt.Errorf("[%s] %s", k, err)
91 }
92 return path, nil
93}
94
95func pathSplit(p string) (string, string) {
96 parts := strings.SplitN(p, ".", 2)
97 head := parts[0]
98 rest := ""
99 if len(parts) > 1 {
100 rest = parts[1]
101 }
102 return head, rest
103}
104
105func pathFromFlatmapKeyObject(key string, atys map[string]cty.Type) (cty.Path, error) {
106 k, rest := pathSplit(key)
107
108 path := cty.Path{cty.GetAttrStep{Name: k}}
109
110 ty, ok := atys[k]
111 if !ok {
112 return path, fmt.Errorf("attribute %q not found", k)
113 }
114
115 if rest == "" {
116 return path, nil
117 }
118
119 p, err := pathFromFlatmapKeyValue(rest, ty)
120 if err != nil {
121 return path, err
122 }
123
124 return append(path, p...), nil
125}
126
127func pathFromFlatmapKeyValue(key string, ty cty.Type) (cty.Path, error) {
128 var path cty.Path
129 var err error
130
131 switch {
132 case ty.IsPrimitiveType():
133 err = fmt.Errorf("invalid step %q with type %#v", key, ty)
134 case ty.IsObjectType():
135 path, err = pathFromFlatmapKeyObject(key, ty.AttributeTypes())
136 case ty.IsTupleType():
137 path, err = pathFromFlatmapKeyTuple(key, ty.TupleElementTypes())
138 case ty.IsMapType():
139 path, err = pathFromFlatmapKeyMap(key, ty)
140 case ty.IsListType():
141 path, err = pathFromFlatmapKeyList(key, ty)
142 case ty.IsSetType():
143 path, err = pathFromFlatmapKeySet(key, ty)
144 default:
145 err = fmt.Errorf("unrecognized type: %s", ty.FriendlyName())
146 }
147
148 if err != nil {
149 return path, err
150 }
151
152 return path, nil
153}
154
155func pathFromFlatmapKeyTuple(key string, etys []cty.Type) (cty.Path, error) {
156 var path cty.Path
157 var err error
158
159 k, rest := pathSplit(key)
160
161 // we don't need to convert the index keys to paths
162 if k == "#" {
163 return path, nil
164 }
165
166 idx, err := strconv.Atoi(k)
167 if err != nil {
168 return path, err
169 }
170
171 path = cty.Path{cty.IndexStep{Key: cty.NumberIntVal(int64(idx))}}
172
173 if idx >= len(etys) {
174 return path, fmt.Errorf("index %s out of range in %#v", key, etys)
175 }
176
177 if rest == "" {
178 return path, nil
179 }
180
181 ty := etys[idx]
182
183 p, err := pathFromFlatmapKeyValue(rest, ty.ElementType())
184 if err != nil {
185 return path, err
186 }
187
188 return append(path, p...), nil
189}
190
191func pathFromFlatmapKeyMap(key string, ty cty.Type) (cty.Path, error) {
192 var path cty.Path
193 var err error
194
195 k, rest := key, ""
196 if !ty.ElementType().IsPrimitiveType() {
197 k, rest = pathSplit(key)
198 }
199
200 // we don't need to convert the index keys to paths
201 if k == "%" {
202 return path, nil
203 }
204
205 path = cty.Path{cty.IndexStep{Key: cty.StringVal(k)}}
206
207 if rest == "" {
208 return path, nil
209 }
210
211 p, err := pathFromFlatmapKeyValue(rest, ty.ElementType())
212 if err != nil {
213 return path, err
214 }
215
216 return append(path, p...), nil
217}
218
219func pathFromFlatmapKeyList(key string, ty cty.Type) (cty.Path, error) {
220 var path cty.Path
221 var err error
222
223 k, rest := pathSplit(key)
224
225 // we don't need to convert the index keys to paths
226 if key == "#" {
227 return path, nil
228 }
229
230 idx, err := strconv.Atoi(k)
231 if err != nil {
232 return path, err
233 }
234
235 path = cty.Path{cty.IndexStep{Key: cty.NumberIntVal(int64(idx))}}
236
237 if rest == "" {
238 return path, nil
239 }
240
241 p, err := pathFromFlatmapKeyValue(rest, ty.ElementType())
242 if err != nil {
243 return path, err
244 }
245
246 return append(path, p...), nil
247}
248
249func pathFromFlatmapKeySet(key string, ty cty.Type) (cty.Path, error) {
250 // once we hit a set, we can't return consistent paths, so just mark the
251 // set as a whole changed.
252 return nil, nil
253}
254
255// FlatmapKeyFromPath returns the flatmap equivalent of the given cty.Path for
256// use in generating legacy style diffs.
257func FlatmapKeyFromPath(path cty.Path) string {
258 var parts []string
259
260 for _, step := range path {
261 switch step := step.(type) {
262 case cty.GetAttrStep:
263 parts = append(parts, step.Name)
264 case cty.IndexStep:
265 switch ty := step.Key.Type(); {
266 case ty == cty.String:
267 parts = append(parts, step.Key.AsString())
268 case ty == cty.Number:
269 i, _ := step.Key.AsBigFloat().Int64()
270 parts = append(parts, strconv.Itoa(int(i)))
271 }
272 }
273 }
274
275 return strings.Join(parts, ".")
276}
diff --git a/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go b/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go
index 0b697a5..daeb0b8 100644
--- a/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go
+++ b/vendor/github.com/hashicorp/terraform/config/hcl2shim/values.go
@@ -6,6 +6,8 @@ import (
6 6
7 "github.com/hashicorp/hil/ast" 7 "github.com/hashicorp/hil/ast"
8 "github.com/zclconf/go-cty/cty" 8 "github.com/zclconf/go-cty/cty"
9
10 "github.com/hashicorp/terraform/configs/configschema"
9) 11)
10 12
11// UnknownVariableValue is a sentinel value that can be used 13// UnknownVariableValue is a sentinel value that can be used
@@ -14,6 +16,108 @@ import (
14// unknown keys. 16// unknown keys.
15const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66" 17const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66"
16 18
19// ConfigValueFromHCL2Block is like ConfigValueFromHCL2 but it works only for
20// known object values and uses the provided block schema to perform some
21// additional normalization to better mimic the shape of value that the old
22// HCL1/HIL-based codepaths would've produced.
23//
24// In particular, it discards the collections that we use to represent nested
25// blocks (other than NestingSingle) if they are empty, which better mimics
26// the HCL1 behavior because HCL1 had no knowledge of the schema and so didn't
27// know that an unspecified block _could_ exist.
28//
29// The given object value must conform to the schema's implied type or this
30// function will panic or produce incorrect results.
31//
32// This is primarily useful for the final transition from new-style values to
33// terraform.ResourceConfig before calling to a legacy provider, since
34// helper/schema (the old provider SDK) is particularly sensitive to these
35// subtle differences within its validation code.
36func ConfigValueFromHCL2Block(v cty.Value, schema *configschema.Block) map[string]interface{} {
37 if v.IsNull() {
38 return nil
39 }
40 if !v.IsKnown() {
41 panic("ConfigValueFromHCL2Block used with unknown value")
42 }
43 if !v.Type().IsObjectType() {
44 panic(fmt.Sprintf("ConfigValueFromHCL2Block used with non-object value %#v", v))
45 }
46
47 atys := v.Type().AttributeTypes()
48 ret := make(map[string]interface{})
49
50 for name := range schema.Attributes {
51 if _, exists := atys[name]; !exists {
52 continue
53 }
54
55 av := v.GetAttr(name)
56 if av.IsNull() {
57 // Skip nulls altogether, to better mimic how HCL1 would behave
58 continue
59 }
60 ret[name] = ConfigValueFromHCL2(av)
61 }
62
63 for name, blockS := range schema.BlockTypes {
64 if _, exists := atys[name]; !exists {
65 continue
66 }
67 bv := v.GetAttr(name)
68 if !bv.IsKnown() {
69 ret[name] = UnknownVariableValue
70 continue
71 }
72 if bv.IsNull() {
73 continue
74 }
75
76 switch blockS.Nesting {
77
78 case configschema.NestingSingle, configschema.NestingGroup:
79 ret[name] = ConfigValueFromHCL2Block(bv, &blockS.Block)
80
81 case configschema.NestingList, configschema.NestingSet:
82 l := bv.LengthInt()
83 if l == 0 {
84 // skip empty collections to better mimic how HCL1 would behave
85 continue
86 }
87
88 elems := make([]interface{}, 0, l)
89 for it := bv.ElementIterator(); it.Next(); {
90 _, ev := it.Element()
91 if !ev.IsKnown() {
92 elems = append(elems, UnknownVariableValue)
93 continue
94 }
95 elems = append(elems, ConfigValueFromHCL2Block(ev, &blockS.Block))
96 }
97 ret[name] = elems
98
99 case configschema.NestingMap:
100 if bv.LengthInt() == 0 {
101 // skip empty collections to better mimic how HCL1 would behave
102 continue
103 }
104
105 elems := make(map[string]interface{})
106 for it := bv.ElementIterator(); it.Next(); {
107 ek, ev := it.Element()
108 if !ev.IsKnown() {
109 elems[ek.AsString()] = UnknownVariableValue
110 continue
111 }
112 elems[ek.AsString()] = ConfigValueFromHCL2Block(ev, &blockS.Block)
113 }
114 ret[name] = elems
115 }
116 }
117
118 return ret
119}
120
17// ConfigValueFromHCL2 converts a value from HCL2 (really, from the cty dynamic 121// ConfigValueFromHCL2 converts a value from HCL2 (really, from the cty dynamic
18// types library that HCL2 uses) to a value type that matches what would've 122// types library that HCL2 uses) to a value type that matches what would've
19// been produced from the HCL-based interpolator for an equivalent structure. 123// been produced from the HCL-based interpolator for an equivalent structure.
@@ -73,7 +177,10 @@ func ConfigValueFromHCL2(v cty.Value) interface{} {
73 it := v.ElementIterator() 177 it := v.ElementIterator()
74 for it.Next() { 178 for it.Next() {
75 ek, ev := it.Element() 179 ek, ev := it.Element()
76 l[ek.AsString()] = ConfigValueFromHCL2(ev) 180 cv := ConfigValueFromHCL2(ev)
181 if cv != nil {
182 l[ek.AsString()] = cv
183 }
77 } 184 }
78 return l 185 return l
79 } 186 }
diff --git a/vendor/github.com/hashicorp/terraform/config/hcl2shim/values_equiv.go b/vendor/github.com/hashicorp/terraform/config/hcl2shim/values_equiv.go
new file mode 100644
index 0000000..92f0213
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/config/hcl2shim/values_equiv.go
@@ -0,0 +1,214 @@
1package hcl2shim
2
3import (
4 "github.com/zclconf/go-cty/cty"
5)
6
7// ValuesSDKEquivalent returns true if both of the given values seem equivalent
8// as far as the legacy SDK diffing code would be concerned.
9//
10// Since SDK diffing is a fuzzy, inexact operation, this function is also
11// fuzzy and inexact. It will err on the side of returning false if it
12// encounters an ambiguous situation. Ambiguity is most common in the presence
13// of sets because in practice it is impossible to exactly correlate
14// nonequal-but-equivalent set elements because they have no identity separate
15// from their value.
16//
17// This must be used _only_ for comparing values for equivalence within the
18// SDK planning code. It is only meaningful to compare the "prior state"
19// provided by Terraform Core with the "planned new state" produced by the
20// legacy SDK code via shims. In particular it is not valid to use this
21// function with their the config value or the "proposed new state" value
22// because they contain only the subset of data that Terraform Core itself is
23// able to determine.
24func ValuesSDKEquivalent(a, b cty.Value) bool {
25 if a == cty.NilVal || b == cty.NilVal {
26 // We don't generally expect nils to appear, but we'll allow them
27 // for robustness since the data structures produced by legacy SDK code
28 // can sometimes be non-ideal.
29 return a == b // equivalent if they are _both_ nil
30 }
31 if a.RawEquals(b) {
32 // Easy case. We use RawEquals because we want two unknowns to be
33 // considered equal here, whereas "Equals" would return unknown.
34 return true
35 }
36 if !a.IsKnown() || !b.IsKnown() {
37 // Two unknown values are equivalent regardless of type. A known is
38 // never equivalent to an unknown.
39 return a.IsKnown() == b.IsKnown()
40 }
41 if aZero, bZero := valuesSDKEquivalentIsNullOrZero(a), valuesSDKEquivalentIsNullOrZero(b); aZero || bZero {
42 // Two null/zero values are equivalent regardless of type. A non-zero is
43 // never equivalent to a zero.
44 return aZero == bZero
45 }
46
47 // If we get down here then we are guaranteed that both a and b are known,
48 // non-null values.
49
50 aTy := a.Type()
51 bTy := b.Type()
52 switch {
53 case aTy.IsSetType() && bTy.IsSetType():
54 return valuesSDKEquivalentSets(a, b)
55 case aTy.IsListType() && bTy.IsListType():
56 return valuesSDKEquivalentSequences(a, b)
57 case aTy.IsTupleType() && bTy.IsTupleType():
58 return valuesSDKEquivalentSequences(a, b)
59 case aTy.IsMapType() && bTy.IsMapType():
60 return valuesSDKEquivalentMappings(a, b)
61 case aTy.IsObjectType() && bTy.IsObjectType():
62 return valuesSDKEquivalentMappings(a, b)
63 case aTy == cty.Number && bTy == cty.Number:
64 return valuesSDKEquivalentNumbers(a, b)
65 default:
66 // We've now covered all the interesting cases, so anything that falls
67 // down here cannot be equivalent.
68 return false
69 }
70}
71
72// valuesSDKEquivalentIsNullOrZero returns true if the given value is either
73// null or is the "zero value" (in the SDK/Go sense) for its type.
74func valuesSDKEquivalentIsNullOrZero(v cty.Value) bool {
75 if v == cty.NilVal {
76 return true
77 }
78
79 ty := v.Type()
80 switch {
81 case !v.IsKnown():
82 return false
83 case v.IsNull():
84 return true
85
86 // After this point, v is always known and non-null
87 case ty.IsListType() || ty.IsSetType() || ty.IsMapType() || ty.IsObjectType() || ty.IsTupleType():
88 return v.LengthInt() == 0
89 case ty == cty.String:
90 return v.RawEquals(cty.StringVal(""))
91 case ty == cty.Number:
92 return v.RawEquals(cty.Zero)
93 case ty == cty.Bool:
94 return v.RawEquals(cty.False)
95 default:
96 // The above is exhaustive, but for robustness we'll consider anything
97 // else to _not_ be zero unless it is null.
98 return false
99 }
100}
101
102// valuesSDKEquivalentSets returns true only if each of the elements in a can
103// be correlated with at least one equivalent element in b and vice-versa.
104// This is a fuzzy operation that prefers to signal non-equivalence if it cannot
105// be certain that all elements are accounted for.
106func valuesSDKEquivalentSets(a, b cty.Value) bool {
107 if aLen, bLen := a.LengthInt(), b.LengthInt(); aLen != bLen {
108 return false
109 }
110
111 // Our methodology here is a little tricky, to deal with the fact that
112 // it's impossible to directly correlate two non-equal set elements because
113 // they don't have identities separate from their values.
114 // The approach is to count the number of equivalent elements each element
115 // of a has in b and vice-versa, and then return true only if each element
116 // in both sets has at least one equivalent.
117 as := a.AsValueSlice()
118 bs := b.AsValueSlice()
119 aeqs := make([]bool, len(as))
120 beqs := make([]bool, len(bs))
121 for ai, av := range as {
122 for bi, bv := range bs {
123 if ValuesSDKEquivalent(av, bv) {
124 aeqs[ai] = true
125 beqs[bi] = true
126 }
127 }
128 }
129
130 for _, eq := range aeqs {
131 if !eq {
132 return false
133 }
134 }
135 for _, eq := range beqs {
136 if !eq {
137 return false
138 }
139 }
140 return true
141}
142
143// valuesSDKEquivalentSequences decides equivalence for two sequence values
144// (lists or tuples).
145func valuesSDKEquivalentSequences(a, b cty.Value) bool {
146 as := a.AsValueSlice()
147 bs := b.AsValueSlice()
148 if len(as) != len(bs) {
149 return false
150 }
151
152 for i := range as {
153 if !ValuesSDKEquivalent(as[i], bs[i]) {
154 return false
155 }
156 }
157 return true
158}
159
160// valuesSDKEquivalentMappings decides equivalence for two mapping values
161// (maps or objects).
162func valuesSDKEquivalentMappings(a, b cty.Value) bool {
163 as := a.AsValueMap()
164 bs := b.AsValueMap()
165 if len(as) != len(bs) {
166 return false
167 }
168
169 for k, av := range as {
170 bv, ok := bs[k]
171 if !ok {
172 return false
173 }
174 if !ValuesSDKEquivalent(av, bv) {
175 return false
176 }
177 }
178 return true
179}
180
181// valuesSDKEquivalentNumbers decides equivalence for two number values based
182// on the fact that the SDK uses int and float64 representations while
183// cty (and thus Terraform Core) uses big.Float, and so we expect to lose
184// precision in the round-trip.
185//
186// This does _not_ attempt to allow for an epsilon difference that may be
187// caused by accumulated innacuracy in a float calculation, under the
188// expectation that providers generally do not actually do compuations on
189// floats and instead just pass string representations of them on verbatim
190// to remote APIs. A remote API _itself_ may introduce inaccuracy, but that's
191// a problem for the provider itself to deal with, based on its knowledge of
192// the remote system, e.g. using DiffSuppressFunc.
193func valuesSDKEquivalentNumbers(a, b cty.Value) bool {
194 if a.RawEquals(b) {
195 return true // easy
196 }
197
198 af := a.AsBigFloat()
199 bf := b.AsBigFloat()
200
201 if af.IsInt() != bf.IsInt() {
202 return false
203 }
204 if af.IsInt() && bf.IsInt() {
205 return false // a.RawEquals(b) test above is good enough for integers
206 }
207
208 // The SDK supports only int and float64, so if it's not an integer
209 // we know that only a float64-level of precision can possibly be
210 // significant.
211 af64, _ := af.Float64()
212 bf64, _ := bf.Float64()
213 return af64 == bf64
214}
diff --git a/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go b/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go
index 421edb0..6a2050c 100644
--- a/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go
+++ b/vendor/github.com/hashicorp/terraform/config/interpolate_funcs.go
@@ -47,6 +47,20 @@ func stringSliceToVariableValue(values []string) []ast.Variable {
47 return output 47 return output
48} 48}
49 49
50// listVariableSliceToVariableValue converts a list of lists into the value
51// required to be returned from interpolation functions which return TypeList.
52func listVariableSliceToVariableValue(values [][]ast.Variable) []ast.Variable {
53 output := make([]ast.Variable, len(values))
54
55 for index, value := range values {
56 output[index] = ast.Variable{
57 Type: ast.TypeList,
58 Value: value,
59 }
60 }
61 return output
62}
63
50func listVariableValueToStringSlice(values []ast.Variable) ([]string, error) { 64func listVariableValueToStringSlice(values []ast.Variable) ([]string, error) {
51 output := make([]string, len(values)) 65 output := make([]string, len(values))
52 for index, value := range values { 66 for index, value := range values {
@@ -61,74 +75,69 @@ func listVariableValueToStringSlice(values []ast.Variable) ([]string, error) {
61// Funcs is the mapping of built-in functions for configuration. 75// Funcs is the mapping of built-in functions for configuration.
62func Funcs() map[string]ast.Function { 76func Funcs() map[string]ast.Function {
63 return map[string]ast.Function{ 77 return map[string]ast.Function{
64 "abs": interpolationFuncAbs(), 78 "abs": interpolationFuncAbs(),
65 "basename": interpolationFuncBasename(), 79 "basename": interpolationFuncBasename(),
66 "base64decode": interpolationFuncBase64Decode(), 80 "base64decode": interpolationFuncBase64Decode(),
67 "base64encode": interpolationFuncBase64Encode(), 81 "base64encode": interpolationFuncBase64Encode(),
68 "base64gzip": interpolationFuncBase64Gzip(), 82 "base64gzip": interpolationFuncBase64Gzip(),
69 "base64sha256": interpolationFuncBase64Sha256(), 83 "base64sha256": interpolationFuncBase64Sha256(),
70 "base64sha512": interpolationFuncBase64Sha512(), 84 "base64sha512": interpolationFuncBase64Sha512(),
71 "bcrypt": interpolationFuncBcrypt(), 85 "bcrypt": interpolationFuncBcrypt(),
72 "ceil": interpolationFuncCeil(), 86 "ceil": interpolationFuncCeil(),
73 "chomp": interpolationFuncChomp(), 87 "chomp": interpolationFuncChomp(),
74 "cidrhost": interpolationFuncCidrHost(), 88 "cidrhost": interpolationFuncCidrHost(),
75 "cidrnetmask": interpolationFuncCidrNetmask(), 89 "cidrnetmask": interpolationFuncCidrNetmask(),
76 "cidrsubnet": interpolationFuncCidrSubnet(), 90 "cidrsubnet": interpolationFuncCidrSubnet(),
77 "coalesce": interpolationFuncCoalesce(), 91 "coalesce": interpolationFuncCoalesce(),
78 "coalescelist": interpolationFuncCoalesceList(), 92 "coalescelist": interpolationFuncCoalesceList(),
79 "compact": interpolationFuncCompact(), 93 "compact": interpolationFuncCompact(),
80 "concat": interpolationFuncConcat(), 94 "concat": interpolationFuncConcat(),
81 "contains": interpolationFuncContains(), 95 "contains": interpolationFuncContains(),
82 "dirname": interpolationFuncDirname(), 96 "dirname": interpolationFuncDirname(),
83 "distinct": interpolationFuncDistinct(), 97 "distinct": interpolationFuncDistinct(),
84 "element": interpolationFuncElement(), 98 "element": interpolationFuncElement(),
85 "chunklist": interpolationFuncChunklist(), 99 "chunklist": interpolationFuncChunklist(),
86 "file": interpolationFuncFile(), 100 "file": interpolationFuncFile(),
87 "filebase64sha256": interpolationFuncMakeFileHash(interpolationFuncBase64Sha256()), 101 "matchkeys": interpolationFuncMatchKeys(),
88 "filebase64sha512": interpolationFuncMakeFileHash(interpolationFuncBase64Sha512()), 102 "flatten": interpolationFuncFlatten(),
89 "filemd5": interpolationFuncMakeFileHash(interpolationFuncMd5()), 103 "floor": interpolationFuncFloor(),
90 "filesha1": interpolationFuncMakeFileHash(interpolationFuncSha1()), 104 "format": interpolationFuncFormat(),
91 "filesha256": interpolationFuncMakeFileHash(interpolationFuncSha256()), 105 "formatlist": interpolationFuncFormatList(),
92 "filesha512": interpolationFuncMakeFileHash(interpolationFuncSha512()), 106 "indent": interpolationFuncIndent(),
93 "matchkeys": interpolationFuncMatchKeys(), 107 "index": interpolationFuncIndex(),
94 "flatten": interpolationFuncFlatten(), 108 "join": interpolationFuncJoin(),
95 "floor": interpolationFuncFloor(), 109 "jsonencode": interpolationFuncJSONEncode(),
96 "format": interpolationFuncFormat(), 110 "length": interpolationFuncLength(),
97 "formatlist": interpolationFuncFormatList(), 111 "list": interpolationFuncList(),
98 "indent": interpolationFuncIndent(), 112 "log": interpolationFuncLog(),
99 "index": interpolationFuncIndex(), 113 "lower": interpolationFuncLower(),
100 "join": interpolationFuncJoin(), 114 "map": interpolationFuncMap(),
101 "jsonencode": interpolationFuncJSONEncode(), 115 "max": interpolationFuncMax(),
102 "length": interpolationFuncLength(), 116 "md5": interpolationFuncMd5(),
103 "list": interpolationFuncList(), 117 "merge": interpolationFuncMerge(),
104 "log": interpolationFuncLog(), 118 "min": interpolationFuncMin(),
105 "lower": interpolationFuncLower(), 119 "pathexpand": interpolationFuncPathExpand(),
106 "map": interpolationFuncMap(), 120 "pow": interpolationFuncPow(),
107 "max": interpolationFuncMax(), 121 "uuid": interpolationFuncUUID(),
108 "md5": interpolationFuncMd5(), 122 "replace": interpolationFuncReplace(),
109 "merge": interpolationFuncMerge(), 123 "reverse": interpolationFuncReverse(),
110 "min": interpolationFuncMin(), 124 "rsadecrypt": interpolationFuncRsaDecrypt(),
111 "pathexpand": interpolationFuncPathExpand(), 125 "sha1": interpolationFuncSha1(),
112 "pow": interpolationFuncPow(), 126 "sha256": interpolationFuncSha256(),
113 "uuid": interpolationFuncUUID(), 127 "sha512": interpolationFuncSha512(),
114 "replace": interpolationFuncReplace(), 128 "signum": interpolationFuncSignum(),
115 "rsadecrypt": interpolationFuncRsaDecrypt(), 129 "slice": interpolationFuncSlice(),
116 "sha1": interpolationFuncSha1(), 130 "sort": interpolationFuncSort(),
117 "sha256": interpolationFuncSha256(), 131 "split": interpolationFuncSplit(),
118 "sha512": interpolationFuncSha512(), 132 "substr": interpolationFuncSubstr(),
119 "signum": interpolationFuncSignum(), 133 "timestamp": interpolationFuncTimestamp(),
120 "slice": interpolationFuncSlice(), 134 "timeadd": interpolationFuncTimeAdd(),
121 "sort": interpolationFuncSort(), 135 "title": interpolationFuncTitle(),
122 "split": interpolationFuncSplit(), 136 "transpose": interpolationFuncTranspose(),
123 "substr": interpolationFuncSubstr(), 137 "trimspace": interpolationFuncTrimSpace(),
124 "timestamp": interpolationFuncTimestamp(), 138 "upper": interpolationFuncUpper(),
125 "timeadd": interpolationFuncTimeAdd(), 139 "urlencode": interpolationFuncURLEncode(),
126 "title": interpolationFuncTitle(), 140 "zipmap": interpolationFuncZipMap(),
127 "transpose": interpolationFuncTranspose(),
128 "trimspace": interpolationFuncTrimSpace(),
129 "upper": interpolationFuncUpper(),
130 "urlencode": interpolationFuncURLEncode(),
131 "zipmap": interpolationFuncZipMap(),
132 } 141 }
133} 142}
134 143
@@ -947,6 +956,25 @@ func interpolationFuncReplace() ast.Function {
947 } 956 }
948} 957}
949 958
959// interpolationFuncReverse implements the "reverse" function that does list reversal
960func interpolationFuncReverse() ast.Function {
961 return ast.Function{
962 ArgTypes: []ast.Type{ast.TypeList},
963 ReturnType: ast.TypeList,
964 Variadic: false,
965 Callback: func(args []interface{}) (interface{}, error) {
966 inputList := args[0].([]ast.Variable)
967
968 reversedList := make([]ast.Variable, len(inputList))
969 for idx := range inputList {
970 reversedList[len(inputList)-1-idx] = inputList[idx]
971 }
972
973 return reversedList, nil
974 },
975 }
976}
977
950func interpolationFuncLength() ast.Function { 978func interpolationFuncLength() ast.Function {
951 return ast.Function{ 979 return ast.Function{
952 ArgTypes: []ast.Type{ast.TypeAny}, 980 ArgTypes: []ast.Type{ast.TypeAny},
@@ -1731,24 +1759,3 @@ func interpolationFuncRsaDecrypt() ast.Function {
1731 }, 1759 },
1732 } 1760 }
1733} 1761}
1734
1735// interpolationFuncMakeFileHash constructs a function that hashes the contents
1736// of a file by combining the implementations of the file(...) function and
1737// a given other function that is assumed to take a single string argument and
1738// return a hash value.
1739func interpolationFuncMakeFileHash(hashFunc ast.Function) ast.Function {
1740 fileFunc := interpolationFuncFile()
1741
1742 return ast.Function{
1743 ArgTypes: []ast.Type{ast.TypeString},
1744 ReturnType: ast.TypeString,
1745 Callback: func(args []interface{}) (interface{}, error) {
1746 filename := args[0].(string)
1747 contents, err := fileFunc.Callback([]interface{}{filename})
1748 if err != nil {
1749 return nil, err
1750 }
1751 return hashFunc.Callback([]interface{}{contents})
1752 },
1753 }
1754}
diff --git a/vendor/github.com/hashicorp/terraform/config/module/storage.go b/vendor/github.com/hashicorp/terraform/config/module/storage.go
index 58e3a10..7734cbc 100644
--- a/vendor/github.com/hashicorp/terraform/config/module/storage.go
+++ b/vendor/github.com/hashicorp/terraform/config/module/storage.go
@@ -7,7 +7,6 @@ import (
7 "log" 7 "log"
8 "os" 8 "os"
9 "path/filepath" 9 "path/filepath"
10 "strings"
11 10
12 getter "github.com/hashicorp/go-getter" 11 getter "github.com/hashicorp/go-getter"
13 "github.com/hashicorp/terraform/registry" 12 "github.com/hashicorp/terraform/registry"
@@ -101,21 +100,6 @@ func (s Storage) loadManifest() (moduleManifest, error) {
101 if err := json.Unmarshal(data, &manifest); err != nil { 100 if err := json.Unmarshal(data, &manifest); err != nil {
102 return manifest, err 101 return manifest, err
103 } 102 }
104
105 for i, rec := range manifest.Modules {
106 // If the path was recorded before we changed to always using a
107 // slash as separator, we delete the record from the manifest so
108 // it can be discovered again and will be recorded using a slash.
109 if strings.Contains(rec.Dir, "\\") {
110 manifest.Modules[i] = manifest.Modules[len(manifest.Modules)-1]
111 manifest.Modules = manifest.Modules[:len(manifest.Modules)-1]
112 continue
113 }
114
115 // Make sure we use the correct path separator.
116 rec.Dir = filepath.FromSlash(rec.Dir)
117 }
118
119 return manifest, nil 103 return manifest, nil
120} 104}
121 105
@@ -146,9 +130,6 @@ func (s Storage) recordModule(rec moduleRecord) error {
146 } 130 }
147 } 131 }
148 132
149 // Make sure we always use a slash separator.
150 rec.Dir = filepath.ToSlash(rec.Dir)
151
152 manifest.Modules = append(manifest.Modules, rec) 133 manifest.Modules = append(manifest.Modules, rec)
153 134
154 js, err := json.Marshal(manifest) 135 js, err := json.Marshal(manifest)
@@ -331,7 +312,7 @@ func (s Storage) findRegistryModule(mSource, constraint string) (moduleRecord, e
331 // we need to lookup available versions 312 // we need to lookup available versions
332 // Only on Get if it's not found, on unconditionally on Update 313 // Only on Get if it's not found, on unconditionally on Update
333 if (s.Mode == GetModeGet && !found) || (s.Mode == GetModeUpdate) { 314 if (s.Mode == GetModeGet && !found) || (s.Mode == GetModeUpdate) {
334 resp, err := s.registry.Versions(mod) 315 resp, err := s.registry.ModuleVersions(mod)
335 if err != nil { 316 if err != nil {
336 return rec, err 317 return rec, err
337 } 318 }
@@ -351,7 +332,7 @@ func (s Storage) findRegistryModule(mSource, constraint string) (moduleRecord, e
351 332
352 rec.Version = match.Version 333 rec.Version = match.Version
353 334
354 rec.url, err = s.registry.Location(mod, rec.Version) 335 rec.url, err = s.registry.ModuleLocation(mod, rec.Version)
355 if err != nil { 336 if err != nil {
356 return rec, err 337 return rec, err
357 } 338 }
diff --git a/vendor/github.com/hashicorp/terraform/config/resource_mode_string.go b/vendor/github.com/hashicorp/terraform/config/resource_mode_string.go
index 8a55e06..0105278 100644
--- a/vendor/github.com/hashicorp/terraform/config/resource_mode_string.go
+++ b/vendor/github.com/hashicorp/terraform/config/resource_mode_string.go
@@ -4,6 +4,14 @@ package config
4 4
5import "strconv" 5import "strconv"
6 6
7func _() {
8 // An "invalid array index" compiler error signifies that the constant values have changed.
9 // Re-run the stringer command to generate them again.
10 var x [1]struct{}
11 _ = x[ManagedResourceMode-0]
12 _ = x[DataResourceMode-1]
13}
14
7const _ResourceMode_name = "ManagedResourceModeDataResourceMode" 15const _ResourceMode_name = "ManagedResourceModeDataResourceMode"
8 16
9var _ResourceMode_index = [...]uint8{0, 19, 35} 17var _ResourceMode_index = [...]uint8{0, 19, 35}