prune NewResourceConfig and update tests

This commit is contained in:
Alex Pilon 2019-07-31 00:05:09 -04:00
parent e9f8f92fce
commit 83aa07f907
No known key found for this signature in database
GPG Key ID: 95659F6AEFC48D7E
24 changed files with 380 additions and 2271 deletions

View File

@ -6,7 +6,6 @@ import (
"testing"
"github.com/hashicorp/terraform/communicator"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
@ -432,10 +431,5 @@ func TestResourceProvider_configureVaults(t *testing.T) {
}
func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
r, err := config.NewRawConfig(c)
if err != nil {
t.Fatalf("bad: %s", err)
}
return terraform.NewResourceConfig(r)
return terraform.NewResourceConfigRaw(c)
}

View File

@ -3,7 +3,6 @@ package file
import (
"testing"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
@ -109,10 +108,5 @@ func TestResourceProvider_Validate_bad_to_many_src(t *testing.T) {
}
func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
r, err := config.NewRawConfig(c)
if err != nil {
t.Fatalf("bad: %s", err)
}
return terraform.NewResourceConfig(r)
return terraform.NewResourceConfigRaw(c)
}

View File

@ -3,7 +3,6 @@ package habitat
import (
"testing"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)
@ -48,10 +47,16 @@ func TestResourceProvisioner_Validate_bad(t *testing.T) {
}
}
/* FIXME panic: interface conversion: interface {} is []interface {}, not []map[string]interface {}
func TestResourceProvisioner_Validate_bad_service_config(t *testing.T) {
c := testConfig(t, map[string]interface{}{
"service": []map[string]interface{}{
map[string]interface{}{"name": "core/foo", "strategy": "bar", "topology": "baz", "url": "badurl"},
"service": []interface{}{
map[string]interface{}{
"name": "core/foo",
"strategy": "bar",
"topology": "baz",
"url": "badurl",
},
},
})
@ -63,12 +68,8 @@ func TestResourceProvisioner_Validate_bad_service_config(t *testing.T) {
t.Fatalf("Should have three errors")
}
}
*/
func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
r, err := config.NewRawConfig(c)
if err != nil {
t.Fatalf("config error: %s", err)
}
return terraform.NewResourceConfig(r)
return terraform.NewResourceConfigRaw(c)
}

View File

@ -7,7 +7,6 @@ import (
"testing"
"time"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)
@ -118,12 +117,7 @@ func TestResourceProvider_Validate_missing(t *testing.T) {
}
func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
r, err := config.NewRawConfig(c)
if err != nil {
t.Fatalf("bad: %s", err)
}
return terraform.NewResourceConfig(r)
return terraform.NewResourceConfigRaw(c)
}
func TestResourceProvider_ApplyCustomInterpreter(t *testing.T) {

View File

@ -3,7 +3,6 @@ package puppet
import (
"testing"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)
@ -120,10 +119,5 @@ func TestProvisioner_Validate_good_bolt_timeout(t *testing.T) {
}
func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
r, err := config.NewRawConfig(c)
if err != nil {
t.Fatalf("bad: %s", err)
}
return terraform.NewResourceConfig(r)
return terraform.NewResourceConfigRaw(c)
}

View File

@ -11,7 +11,6 @@ import (
"github.com/hashicorp/terraform/communicator"
"github.com/hashicorp/terraform/communicator/remote"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)
@ -264,10 +263,5 @@ func TestProvisionerTimeout(t *testing.T) {
}
func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
r, err := config.NewRawConfig(c)
if err != nil {
t.Fatalf("bad: %s", err)
}
return terraform.NewResourceConfig(r)
return terraform.NewResourceConfigRaw(c)
}

View File

@ -6,18 +6,12 @@ import (
"strings"
"testing"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)
func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
r, err := config.NewRawConfig(c)
if err != nil {
t.Fatalf("bad: %s", err)
}
return terraform.NewResourceConfig(r)
return terraform.NewResourceConfigRaw(c)
}
func TestResourceProvisioner_impl(t *testing.T) {

View File

@ -4,7 +4,6 @@ import (
"fmt"
"testing"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/terraform"
)
@ -81,7 +80,7 @@ func TestValidator_complex(t *testing.T) {
// Valid
c = testConfig(t, map[string]interface{}{
"foo": "bar",
"nested": []map[string]interface{}{
"nested": []interface{}{
map[string]interface{}{"foo": "bar"},
},
})
@ -111,7 +110,7 @@ func TestValidator_complexNested(t *testing.T) {
// Valid
c = testConfig(t, map[string]interface{}{
"ingress": []map[string]interface{}{
"ingress": []interface{}{
map[string]interface{}{
"from_port": "80",
},
@ -121,7 +120,7 @@ func TestValidator_complexNested(t *testing.T) {
// Valid
c = testConfig(t, map[string]interface{}{
"ingress": []map[string]interface{}{
"ingress": []interface{}{
map[string]interface{}{
"from_port": "80",
"cidr_blocks": []interface{}{"foo"},
@ -144,7 +143,7 @@ func TestValidator_complexDeepRequired(t *testing.T) {
// Valid
c = testConfig(t, map[string]interface{}{
"foo": "bar",
"nested": []map[string]interface{}{
"nested": []interface{}{
map[string]interface{}{"foo": "bar"},
},
})
@ -164,15 +163,8 @@ func TestValidator_complexDeepRequired(t *testing.T) {
testInvalid(v, c)
}
func testConfig(
t *testing.T,
c map[string]interface{}) *terraform.ResourceConfig {
r, err := config.NewRawConfig(c)
if err != nil {
t.Fatalf("bad: %s", err)
}
return terraform.NewResourceConfig(r)
func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
return terraform.NewResourceConfigRaw(c)
}
func testInvalid(v *Validator, c *terraform.ResourceConfig) {

View File

@ -1,92 +0,0 @@
package diff
import (
"bytes"
"fmt"
"sort"
"strings"
"testing"
"github.com/hashicorp/hil/ast"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/terraform"
)
func testConfig(
t *testing.T,
c map[string]interface{},
vs map[string]string) *terraform.ResourceConfig {
rc, err := config.NewRawConfig(c)
if err != nil {
t.Fatalf("err: %s", err)
}
if len(vs) > 0 {
vars := make(map[string]ast.Variable)
for k, v := range vs {
vars[k] = ast.Variable{Value: v, Type: ast.TypeString}
}
if err := rc.Interpolate(vars); err != nil {
t.Fatalf("err: %s", err)
}
}
return terraform.NewResourceConfig(rc)
}
func testResourceDiffStr(rd *terraform.InstanceDiff) string {
var buf bytes.Buffer
crud := "UPDATE"
if rd.RequiresNew() {
crud = "CREATE"
}
buf.WriteString(fmt.Sprintf(
"%s\n",
crud))
keyLen := 0
keys := make([]string, 0, len(rd.Attributes))
for key, _ := range rd.Attributes {
keys = append(keys, key)
if len(key) > keyLen {
keyLen = len(key)
}
}
sort.Strings(keys)
for _, attrK := range keys {
attrDiff := rd.Attributes[attrK]
v := attrDiff.New
if attrDiff.NewComputed {
v = "<computed>"
}
if attrDiff.NewRemoved {
v = "<removed>"
}
newResource := ""
if attrDiff.RequiresNew {
newResource = " (forces new resource)"
}
inOut := "IN "
if attrDiff.Type == terraform.DiffAttrOutput {
inOut = "OUT"
}
buf.WriteString(fmt.Sprintf(
" %s %s:%s %#v => %#v%s\n",
inOut,
attrK,
strings.Repeat(" ", keyLen-len(attrK)),
attrDiff.Old,
v,
newResource))
}
return buf.String()
}

View File

@ -1,219 +0,0 @@
package diff
import (
"strings"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/flatmap"
"github.com/hashicorp/terraform/terraform"
)
// AttrType is an enum that tells the ResourceBuilder what type of attribute
// an attribute is, affecting the overall diff output.
//
// The valid values are:
//
// * AttrTypeCreate - This attribute can only be set or updated on create.
// This means that if this attribute is changed, it will require a new
// resource to be created if it is already created.
//
// * AttrTypeUpdate - This attribute can be set at create time or updated
// in-place. Changing this attribute does not require a new resource.
//
type AttrType byte
const (
AttrTypeUnknown AttrType = iota
AttrTypeCreate
AttrTypeUpdate
)
// ResourceBuilder is a helper that knows about how a single resource
// changes and how those changes affect the diff.
type ResourceBuilder struct {
// Attrs are the mapping of attributes that can be set from the
// configuration, and the affect they have. See the documentation for
// AttrType for more info.
//
// Sometimes attributes in here are also computed. For example, an
// "availability_zone" might be optional, but will be chosen for you
// by AWS. In that case, specify it both here and in ComputedAttrs.
// This will make sure that the absence of the configuration won't
// cause a diff by setting it to the empty string.
Attrs map[string]AttrType
// ComputedAttrs are the attributes that are computed at
// resource creation time.
ComputedAttrs []string
// ComputedAttrsUpdate are the attributes that are computed
// at resource update time (this includes creation).
ComputedAttrsUpdate []string
// PreProcess is a mapping of exact keys that are sent through
// a pre-processor before comparing values. The original value will
// be put in the "NewExtra" field of the diff.
PreProcess map[string]PreProcessFunc
}
// PreProcessFunc is used with the PreProcess field in a ResourceBuilder
type PreProcessFunc func(string) string
// Diff returns the ResourceDiff for a resource given its state and
// configuration.
func (b *ResourceBuilder) Diff(
s *terraform.InstanceState,
c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
attrs := make(map[string]*terraform.ResourceAttrDiff)
// We require a new resource if the ID is empty. Or, later, we set
// this to true if any configuration changed that triggers a new resource.
requiresNew := s.ID == ""
// Flatten the raw and processed configuration
flatRaw := flatmap.Flatten(c.Raw)
flatConfig := flatmap.Flatten(c.Config)
for ak, at := range b.Attrs {
// Keep track of all the keys we saw in the raw structure
// so that we can prune our attributes later.
seenKeys := make([]string, 0)
// Go through and find the added/changed keys in flatRaw
for k, v := range flatRaw {
// Find only the attributes that match our prefix
if !strings.HasPrefix(k, ak) {
continue
}
// Track that we saw this key
seenKeys = append(seenKeys, k)
// We keep track of this in case we have a pre-processor
// so that we can store the original value still.
originalV := v
// If this key is in the cleaned config, then use that value
// because it'll have its variables properly interpolated
if cleanV, ok := flatConfig[k]; ok && cleanV != hcl2shim.UnknownVariableValue {
v = cleanV
originalV = v
// If we have a pre-processor for this, run it.
if pp, ok := b.PreProcess[k]; ok {
v = pp(v)
}
}
oldV, ok := s.Attributes[k]
// If there is an old value and they're the same, no change
if ok && oldV == v {
continue
}
// Record the change
attrs[k] = &terraform.ResourceAttrDiff{
Old: oldV,
New: v,
NewExtra: originalV,
Type: terraform.DiffAttrInput,
}
// If this requires a new resource, record that and flag our
// boolean.
if at == AttrTypeCreate {
attrs[k].RequiresNew = true
requiresNew = true
}
}
// Find all the keys that are in our attributes right now that
// we also care about.
matchingKeys := make(map[string]struct{})
for k, _ := range s.Attributes {
// Find only the attributes that match our prefix
if !strings.HasPrefix(k, ak) {
continue
}
// If this key is computed, then we don't ever delete it
comp := false
for _, ck := range b.ComputedAttrs {
if ck == k {
comp = true
break
}
// If the key is prefixed with the computed key, don't
// mark it for delete, ever.
if strings.HasPrefix(k, ck+".") {
comp = true
break
}
}
if comp {
continue
}
matchingKeys[k] = struct{}{}
}
// Delete the keys we saw in the configuration from the keys
// that are currently set.
for _, k := range seenKeys {
delete(matchingKeys, k)
}
for k, _ := range matchingKeys {
attrs[k] = &terraform.ResourceAttrDiff{
Old: s.Attributes[k],
NewRemoved: true,
Type: terraform.DiffAttrInput,
}
}
}
// If we require a new resource, then process all the attributes
// that will be changing due to the creation of the resource.
if requiresNew {
for _, k := range b.ComputedAttrs {
if _, ok := attrs[k]; ok {
continue
}
old := s.Attributes[k]
attrs[k] = &terraform.ResourceAttrDiff{
Old: old,
NewComputed: true,
Type: terraform.DiffAttrOutput,
}
}
}
// If we're changing anything, then mark the updated
// attributes.
if len(attrs) > 0 {
for _, k := range b.ComputedAttrsUpdate {
if _, ok := attrs[k]; ok {
continue
}
old := s.Attributes[k]
attrs[k] = &terraform.ResourceAttrDiff{
Old: old,
NewComputed: true,
Type: terraform.DiffAttrOutput,
}
}
}
// Build our resulting diff if we had attributes change
var result *terraform.InstanceDiff
if len(attrs) > 0 {
result = &terraform.InstanceDiff{
Attributes: attrs,
}
}
return result, nil
}

View File

@ -1,471 +0,0 @@
package diff
import (
"testing"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/terraform"
)
func TestResourceBuilder_attrSetComputed(t *testing.T) {
rb := &ResourceBuilder{
Attrs: map[string]AttrType{
"foo": AttrTypeCreate,
},
ComputedAttrs: []string{
"foo",
},
}
state := &terraform.InstanceState{}
c := testConfig(t, map[string]interface{}{
"foo": "bar",
}, nil)
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff == nil {
t.Fatal("diff shold not be nil")
}
actual := testResourceDiffStr(diff)
expected := testRBAttrSetComputedDiff
if actual != expected {
t.Fatalf("bad: %s", actual)
}
}
func TestResourceBuilder_attrSetComputedComplex(t *testing.T) {
rb := &ResourceBuilder{
Attrs: map[string]AttrType{
"foo": AttrTypeCreate,
},
ComputedAttrs: []string{
"foo",
},
}
state := &terraform.InstanceState{
ID: "foo",
Attributes: map[string]string{
"foo.#": "0",
},
}
c := testConfig(t, map[string]interface{}{}, nil)
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff != nil {
t.Fatalf("diff shold be nil: %#v", diff)
}
}
func TestResourceBuilder_replaceComputed(t *testing.T) {
rb := &ResourceBuilder{
Attrs: map[string]AttrType{
"foo": AttrTypeCreate,
},
ComputedAttrs: []string{
"foo",
},
}
state := &terraform.InstanceState{
ID: "foo",
Attributes: map[string]string{
"foo": "bar",
},
}
c := testConfig(t, nil, nil)
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff != nil {
t.Fatalf("should be nil: %#v", diff)
}
}
func TestResourceBuilder_complex(t *testing.T) {
rb := &ResourceBuilder{
Attrs: map[string]AttrType{
"listener": AttrTypeUpdate,
},
}
state := &terraform.InstanceState{
ID: "foo",
Attributes: map[string]string{
"ignore": "1",
"listener.#": "1",
"listener.0.port": "80",
},
}
c := testConfig(t, map[string]interface{}{
"listener": []interface{}{
map[interface{}]interface{}{
"port": 3000,
},
},
}, nil)
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff == nil {
t.Fatal("should not be nil")
}
actual := testResourceDiffStr(diff)
expected := testRBComplexDiff
if actual != expected {
t.Fatalf("bad: %s", actual)
}
}
func TestResourceBuilder_complexReplace(t *testing.T) {
rb := &ResourceBuilder{
Attrs: map[string]AttrType{
"listener": AttrTypeUpdate,
},
}
state := &terraform.InstanceState{
ID: "foo",
Attributes: map[string]string{
"ignore": "1",
"listener.#": "1",
"listener.0.port": "80",
},
}
c := testConfig(t, map[string]interface{}{
"listener": []interface{}{
map[interface{}]interface{}{
"value": "50",
},
},
}, nil)
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff == nil {
t.Fatal("should not be nil")
}
actual := testResourceDiffStr(diff)
expected := testRBComplexReplaceDiff
if actual != expected {
t.Fatalf("bad: %s", actual)
}
}
func TestResourceBuilder_computedAttrsUpdate(t *testing.T) {
rb := &ResourceBuilder{
Attrs: map[string]AttrType{
"foo": AttrTypeUpdate,
},
ComputedAttrsUpdate: []string{
"bar",
},
}
state := &terraform.InstanceState{
Attributes: map[string]string{"foo": "foo"},
}
c := testConfig(t, map[string]interface{}{
"foo": "bar",
}, nil)
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff == nil {
t.Fatal("diff shold not be nil")
}
actual := testResourceDiffStr(diff)
expected := testRBComputedAttrUpdate
if actual != expected {
t.Fatalf("bad: %s", actual)
}
}
func TestResourceBuilder_new(t *testing.T) {
rb := &ResourceBuilder{
Attrs: map[string]AttrType{
"foo": AttrTypeUpdate,
},
ComputedAttrs: []string{"private_ip"},
}
state := &terraform.InstanceState{}
c := testConfig(t, map[string]interface{}{
"foo": "bar",
}, nil)
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff == nil {
t.Fatal("should not be nil")
}
actual := testResourceDiffStr(diff)
expected := testRBNewDiff
if actual != expected {
t.Fatalf("bad: %s", actual)
}
}
func TestResourceBuilder_preProcess(t *testing.T) {
rb := &ResourceBuilder{
Attrs: map[string]AttrType{
"foo": AttrTypeCreate,
},
PreProcess: map[string]PreProcessFunc{
"foo": func(v string) string {
return "bar" + v
},
},
}
state := &terraform.InstanceState{}
c := testConfig(t, map[string]interface{}{
"foo": "foo",
}, nil)
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff == nil {
t.Fatal("diff shold not be nil")
}
actual := testResourceDiffStr(diff)
expected := testRBPreProcessDiff
if actual != expected {
t.Fatalf("bad: %s", actual)
}
actual = diff.Attributes["foo"].NewExtra.(string)
expected = "foo"
if actual != expected {
t.Fatalf("bad: %#v", actual)
}
}
func TestResourceBuilder_preProcessUnknown(t *testing.T) {
rb := &ResourceBuilder{
Attrs: map[string]AttrType{
"foo": AttrTypeCreate,
},
PreProcess: map[string]PreProcessFunc{
"foo": func(string) string {
return "bar"
},
},
}
state := &terraform.InstanceState{}
c := testConfig(t, map[string]interface{}{
"foo": "${var.unknown}",
}, map[string]string{
"var.unknown": hcl2shim.UnknownVariableValue,
})
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff == nil {
t.Fatal("diff shold not be nil")
}
actual := testResourceDiffStr(diff)
expected := testRBPreProcessUnknownDiff
if actual != expected {
t.Fatalf("bad: %s", actual)
}
}
func TestResourceBuilder_requiresNew(t *testing.T) {
rb := &ResourceBuilder{
ComputedAttrs: []string{"private_ip"},
Attrs: map[string]AttrType{
"ami": AttrTypeCreate,
},
}
state := &terraform.InstanceState{
ID: "1",
Attributes: map[string]string{
"ami": "foo",
"private_ip": "127.0.0.1",
},
}
c := testConfig(t, map[string]interface{}{
"ami": "bar",
}, nil)
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff == nil {
t.Fatal("should not be nil")
}
actual := testResourceDiffStr(diff)
expected := testRBRequiresNewDiff
if actual != expected {
t.Fatalf("bad: %s", actual)
}
}
func TestResourceBuilder_same(t *testing.T) {
rb := &ResourceBuilder{
ComputedAttrs: []string{"private_ip"},
}
state := &terraform.InstanceState{
ID: "1",
Attributes: map[string]string{
"foo": "bar",
},
}
c := testConfig(t, map[string]interface{}{
"foo": "bar",
}, nil)
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff != nil {
t.Fatalf("should not diff: %#v", diff)
}
}
func TestResourceBuilder_unknown(t *testing.T) {
rb := &ResourceBuilder{
Attrs: map[string]AttrType{
"foo": AttrTypeUpdate,
},
}
state := &terraform.InstanceState{}
c := testConfig(t, map[string]interface{}{
"foo": "${var.unknown}",
}, map[string]string{
"var.foo": "bar",
"var.unknown": hcl2shim.UnknownVariableValue,
})
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff == nil {
t.Fatal("should not be nil")
}
actual := testResourceDiffStr(diff)
expected := testRBUnknownDiff
if actual != expected {
t.Fatalf("bad: %s", actual)
}
}
func TestResourceBuilder_vars(t *testing.T) {
rb := &ResourceBuilder{
Attrs: map[string]AttrType{
"foo": AttrTypeUpdate,
},
}
state := &terraform.InstanceState{}
c := testConfig(t, map[string]interface{}{
"foo": "${var.foo}",
}, map[string]string{
"var.foo": "bar",
})
diff, err := rb.Diff(state, c)
if err != nil {
t.Fatalf("err: %s", err)
}
if diff == nil {
t.Fatal("should not be nil")
}
actual := testResourceDiffStr(diff)
expected := testRBVarsDiff
if actual != expected {
t.Fatalf("bad: %s", actual)
}
}
const testRBAttrSetComputedDiff = `CREATE
IN foo: "" => "bar" (forces new resource)
`
const testRBComplexDiff = `UPDATE
IN listener.0.port: "80" => "3000"
`
const testRBComplexReplaceDiff = `UPDATE
IN listener.0.port: "80" => "<removed>"
IN listener.0.value: "" => "50"
`
const testRBComputedAttrUpdate = `UPDATE
OUT bar: "" => "<computed>"
IN foo: "foo" => "bar"
`
const testRBNewDiff = `UPDATE
IN foo: "" => "bar"
OUT private_ip: "" => "<computed>"
`
const testRBPreProcessDiff = `CREATE
IN foo: "" => "barfoo" (forces new resource)
`
const testRBPreProcessUnknownDiff = `CREATE
IN foo: "" => "${var.unknown}" (forces new resource)
`
const testRBRequiresNewDiff = `CREATE
IN ami: "foo" => "bar" (forces new resource)
OUT private_ip: "127.0.0.1" => "<computed>"
`
const testRBUnknownDiff = `UPDATE
IN foo: "" => "${var.unknown}"
`
const testRBVarsDiff = `UPDATE
IN foo: "" => "bar"
`

View File

@ -4,7 +4,6 @@ import (
"reflect"
"testing"
tfconfig "github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/helper/config"
"github.com/hashicorp/terraform/terraform"
)
@ -70,10 +69,5 @@ func TestMapValidate(t *testing.T) {
}
func testConfigForMap(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig {
r, err := tfconfig.NewRawConfig(c)
if err != nil {
t.Fatalf("bad: %s", err)
}
return terraform.NewResourceConfig(r)
return terraform.NewResourceConfigRaw(c)
}

View File

@ -6,8 +6,6 @@ import (
"reflect"
"testing"
"github.com/hashicorp/hil/ast"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/terraform"
@ -100,13 +98,8 @@ func TestConfigFieldReader_custom(t *testing.T) {
Exists: true,
Computed: true,
},
testConfigInterpolate(t, map[string]interface{}{
"bool": "${var.foo}",
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Value: hcl2shim.UnknownVariableValue,
Type: ast.TypeString,
},
testConfig(t, map[string]interface{}{
"bool": hcl2shim.UnknownVariableValue,
}),
false,
},
@ -268,14 +261,9 @@ func TestConfigFieldReader_ComputedMap(t *testing.T) {
Exists: true,
Computed: true,
},
testConfigInterpolate(t, map[string]interface{}{
testConfig(t, map[string]interface{}{
"map": map[string]interface{}{
"foo": "${var.foo}",
},
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Value: hcl2shim.UnknownVariableValue,
Type: ast.TypeString,
"foo": hcl2shim.UnknownVariableValue,
},
}),
false,
@ -292,21 +280,10 @@ func TestConfigFieldReader_ComputedMap(t *testing.T) {
Exists: true,
Computed: false,
},
testConfigInterpolate(t, map[string]interface{}{
"map": "${var.foo}",
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Type: ast.TypeMap,
Value: map[string]ast.Variable{
"bar": ast.Variable{
Type: ast.TypeString,
Value: "baz",
},
"baz": ast.Variable{
Type: ast.TypeString,
Value: "bar",
},
},
testConfig(t, map[string]interface{}{
"map": map[string]interface{}{
"bar": "baz",
"baz": "bar",
},
}),
false,
@ -322,21 +299,10 @@ func TestConfigFieldReader_ComputedMap(t *testing.T) {
Exists: true,
Computed: false,
},
testConfigInterpolate(t, map[string]interface{}{
"maplist": "${var.foo}",
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Type: ast.TypeList,
Value: []ast.Variable{
{
Type: ast.TypeMap,
Value: map[string]ast.Variable{
"key": ast.Variable{
Type: ast.TypeString,
Value: "bar",
},
},
},
testConfig(t, map[string]interface{}{
"maplist": []interface{}{
map[string]interface{}{
"key": "bar",
},
},
}),
@ -351,21 +317,10 @@ func TestConfigFieldReader_ComputedMap(t *testing.T) {
Exists: true,
Computed: false,
},
testConfigInterpolate(t, map[string]interface{}{
"maplist": "${var.foo}",
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Type: ast.TypeList,
Value: []ast.Variable{
{
Type: ast.TypeMap,
Value: map[string]ast.Variable{
"key": ast.Variable{
Type: ast.TypeString,
Value: "bar",
},
},
},
testConfig(t, map[string]interface{}{
"maplist": []interface{}{
map[string]interface{}{
"key": "bar",
},
},
}),
@ -380,21 +335,10 @@ func TestConfigFieldReader_ComputedMap(t *testing.T) {
Exists: true,
Computed: false,
},
testConfigInterpolate(t, map[string]interface{}{
"listmap": "${var.foo}",
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Type: ast.TypeMap,
Value: map[string]ast.Variable{
"key": ast.Variable{
Type: ast.TypeList,
Value: []ast.Variable{
ast.Variable{
Type: ast.TypeString,
Value: "bar",
},
},
},
testConfig(t, map[string]interface{}{
"listmap": map[string]interface{}{
"key": []interface{}{
"bar",
},
},
}),
@ -409,21 +353,10 @@ func TestConfigFieldReader_ComputedMap(t *testing.T) {
Exists: true,
Computed: false,
},
testConfigInterpolate(t, map[string]interface{}{
"listmap": "${var.foo}",
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Type: ast.TypeMap,
Value: map[string]ast.Variable{
"key": ast.Variable{
Type: ast.TypeList,
Value: []ast.Variable{
ast.Variable{
Type: ast.TypeString,
Value: "bar",
},
},
},
testConfig(t, map[string]interface{}{
"listmap": map[string]interface{}{
"key": []interface{}{
"bar",
},
},
}),
@ -492,31 +425,8 @@ func TestConfigFieldReader_ComputedSet(t *testing.T) {
Exists: true,
Computed: true,
},
testConfigInterpolate(t, map[string]interface{}{
"strSet": []interface{}{"${var.foo}"},
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Value: hcl2shim.UnknownVariableValue,
Type: ast.TypeUnknown,
},
}),
false,
},
"set, computed element substring": {
[]string{"strSet"},
FieldReadResult{
Value: nil,
Exists: true,
Computed: true,
},
testConfigInterpolate(t, map[string]interface{}{
"strSet": []interface{}{"${var.foo}/32"},
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Value: hcl2shim.UnknownVariableValue,
Type: ast.TypeUnknown,
},
testConfig(t, map[string]interface{}{
"strSet": []interface{}{hcl2shim.UnknownVariableValue},
}),
false,
},
@ -601,57 +511,6 @@ func TestConfigFieldReader_computedComplexSet(t *testing.T) {
}),
false,
},
"set, computed element": {
[]string{"set"},
FieldReadResult{
Value: map[string]interface{}{
"~3596295623": map[string]interface{}{
"name": "myosdisk1",
"vhd_uri": "${var.foo}/bar",
},
},
Exists: true,
Computed: false,
},
testConfigInterpolate(t, map[string]interface{}{
"set": []interface{}{
map[string]interface{}{
"name": "myosdisk1",
"vhd_uri": "${var.foo}/bar",
},
},
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Value: hcl2shim.UnknownVariableValue,
Type: ast.TypeUnknown,
},
}),
false,
},
"set, computed element single": {
[]string{"set", "~3596295623", "vhd_uri"},
FieldReadResult{
Value: "${var.foo}/bar",
Exists: true,
Computed: true,
},
testConfigInterpolate(t, map[string]interface{}{
"set": []interface{}{
map[string]interface{}{
"name": "myosdisk1",
"vhd_uri": "${var.foo}/bar",
},
},
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Value: hcl2shim.UnknownVariableValue,
Type: ast.TypeUnknown,
},
}),
false,
},
}
for name, tc := range cases {
@ -676,25 +535,6 @@ func TestConfigFieldReader_computedComplexSet(t *testing.T) {
}
}
func testConfig(
t *testing.T, raw map[string]interface{}) *terraform.ResourceConfig {
return testConfigInterpolate(t, raw, nil)
}
func testConfigInterpolate(
t *testing.T,
raw map[string]interface{},
vs map[string]ast.Variable) *terraform.ResourceConfig {
rc, err := config.NewRawConfig(raw)
if err != nil {
t.Fatalf("err: %s", err)
}
if len(vs) > 0 {
if err := rc.Interpolate(vs); err != nil {
t.Fatalf("err: %s", err)
}
}
return terraform.NewResourceConfig(rc)
func testConfig(t *testing.T, raw map[string]interface{}) *terraform.ResourceConfig {
return terraform.NewResourceConfigRaw(raw)
}

View File

@ -10,7 +10,6 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/terraform"
)
@ -157,12 +156,8 @@ func TestProviderConfigure(t *testing.T) {
}
for i, tc := range cases {
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
err = tc.P.Configure(terraform.NewResourceConfig(c))
c := terraform.NewResourceConfigRaw(tc.Config)
err := tc.P.Configure(c)
if err != nil != tc.Err {
t.Fatalf("%d: %s", i, err)
}
@ -266,18 +261,15 @@ func TestProviderValidate(t *testing.T) {
}
for i, tc := range cases {
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
_, es := tc.P.Validate(terraform.NewResourceConfig(c))
c := terraform.NewResourceConfigRaw(tc.Config)
_, es := tc.P.Validate(c)
if len(es) > 0 != tc.Err {
t.Fatalf("%d: %#v", i, es)
}
}
}
/* FIXME Invalid timeout structure: []interface {}{map[string]interface {}{"create":"40m"}}
func TestProviderDiff_legacyTimeoutType(t *testing.T) {
p := &Provider{
ResourcesMap: map[string]*Resource{
@ -295,48 +287,6 @@ func TestProviderDiff_legacyTimeoutType(t *testing.T) {
},
}
invalidCfg := map[string]interface{}{
"foo": 42,
"timeouts": []map[string]interface{}{
map[string]interface{}{
"create": "40m",
},
},
}
ic, err := config.NewRawConfig(invalidCfg)
if err != nil {
t.Fatalf("err: %s", err)
}
_, err = p.Diff(
&terraform.InstanceInfo{
Type: "blah",
},
nil,
terraform.NewResourceConfig(ic),
)
if err != nil {
t.Fatal(err)
}
}
func TestProviderDiff_invalidTimeoutType(t *testing.T) {
p := &Provider{
ResourcesMap: map[string]*Resource{
"blah": &Resource{
Schema: map[string]*Schema{
"foo": {
Type: TypeInt,
Optional: true,
},
},
Timeouts: &ResourceTimeout{
Create: DefaultTimeout(10 * time.Minute),
},
},
},
}
invalidCfg := map[string]interface{}{
"foo": 42,
"timeouts": []interface{}{
@ -345,28 +295,19 @@ func TestProviderDiff_invalidTimeoutType(t *testing.T) {
},
},
}
ic, err := config.NewRawConfig(invalidCfg)
if err != nil {
t.Fatalf("err: %s", err)
}
_, err = p.Diff(
ic := terraform.NewResourceConfigRaw(invalidCfg)
_, err := p.Diff(
&terraform.InstanceInfo{
Type: "blah",
},
nil,
terraform.NewResourceConfig(ic),
ic,
)
if err == nil {
t.Fatal("Expected provider.Diff to fail with invalid timeout type")
}
expectedErrMsg := "Invalid Timeout structure"
if !strings.Contains(err.Error(), expectedErrMsg) {
t.Fatalf("Unexpected error message: %q\nExpected message to contain %q",
err.Error(),
expectedErrMsg)
if err != nil {
t.Fatal(err)
}
}
*/
func TestProviderDiff_timeoutInvalidValue(t *testing.T) {
p := &Provider{
@ -391,17 +332,13 @@ func TestProviderDiff_timeoutInvalidValue(t *testing.T) {
"create": "invalid",
},
}
ic, err := config.NewRawConfig(invalidCfg)
if err != nil {
t.Fatalf("err: %s", err)
}
_, err = p.Diff(
ic := terraform.NewResourceConfigRaw(invalidCfg)
_, err := p.Diff(
&terraform.InstanceInfo{
Type: "blah",
},
nil,
terraform.NewResourceConfig(ic),
ic,
)
if err == nil {
t.Fatal("Expected provider.Diff to fail with invalid timeout value")
@ -441,12 +378,8 @@ func TestProviderValidateResource(t *testing.T) {
}
for i, tc := range cases {
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
_, es := tc.P.ValidateResource(tc.Type, terraform.NewResourceConfig(c))
c := terraform.NewResourceConfigRaw(tc.Config)
_, es := tc.P.ValidateResource(tc.Type, c)
if len(es) > 0 != tc.Err {
t.Fatalf("%d: %#v", i, es)
}

View File

@ -7,7 +7,6 @@ import (
"sync"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/terraform"
)
@ -146,13 +145,9 @@ func (p *Provisioner) Apply(
}
}
c, err := config.NewRawConfig(raw)
if err != nil {
return err
}
c := terraform.NewResourceConfigRaw(raw)
sm := schemaMap(p.ConnSchema)
diff, err := sm.Diff(nil, terraform.NewResourceConfig(c), nil, nil, true)
diff, err := sm.Diff(nil, c, nil, nil, true)
if err != nil {
return err
}

View File

@ -7,7 +7,6 @@ import (
"testing"
"time"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/terraform"
)
@ -125,12 +124,8 @@ func TestProvisionerValidate(t *testing.T) {
for i, tc := range cases {
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
ws, es := tc.P.Validate(terraform.NewResourceConfig(c))
c := terraform.NewResourceConfigRaw(tc.Config)
ws, es := tc.P.Validate(c)
if len(es) > 0 != tc.Err {
t.Fatalf("%d: %#v %s", i, es, es)
}
@ -191,10 +186,7 @@ func TestProvisionerApply(t *testing.T) {
for i, tc := range cases {
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
c := terraform.NewResourceConfigRaw(tc.Config)
state := &terraform.InstanceState{
Ephemeral: terraform.EphemeralState{
@ -202,8 +194,7 @@ func TestProvisionerApply(t *testing.T) {
},
}
err = tc.P.Apply(
nil, state, terraform.NewResourceConfig(c))
err := tc.P.Apply(nil, state, c)
if err != nil != tc.Err {
t.Fatalf("%d: %s", i, err)
}
@ -236,12 +227,8 @@ func TestProvisionerApply_nilState(t *testing.T) {
"foo": 42,
}
c, err := config.NewRawConfig(conf)
if err != nil {
t.Fatalf("err: %s", err)
}
err = p.Apply(nil, nil, terraform.NewResourceConfig(c))
c := terraform.NewResourceConfigRaw(conf)
err := p.Apply(nil, nil, c)
if err != nil {
t.Fatalf("err: %s", err)
}
@ -300,11 +287,7 @@ func TestProvisionerStop_apply(t *testing.T) {
"foo": 42,
}
c, err := config.NewRawConfig(conf)
if err != nil {
t.Fatalf("err: %s", err)
}
c := terraform.NewResourceConfigRaw(conf)
state := &terraform.InstanceState{
Ephemeral: terraform.EphemeralState{
ConnInfo: conn,
@ -314,7 +297,7 @@ func TestProvisionerStop_apply(t *testing.T) {
// Run the apply in a goroutine
doneCh := make(chan struct{})
go func() {
p.Apply(nil, state, terraform.NewResourceConfig(c))
p.Apply(nil, state, c)
close(doneCh)
}()

View File

@ -7,7 +7,6 @@ import (
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/hashicorp/hil/ast"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/terraform"
)
@ -808,7 +807,7 @@ func TestForceNew(t *testing.T) {
},
},
Config: testConfig(t, map[string]interface{}{
"foo": []map[string]interface{}{
"foo": []interface{}{
map[string]interface{}{
"bar": "abcdefg",
"baz": "changed",
@ -905,7 +904,7 @@ func TestForceNew(t *testing.T) {
},
},
Config: testConfig(t, map[string]interface{}{
"foo": []map[string]interface{}{
"foo": []interface{}{
map[string]interface{}{
"bar": "abcdefg",
},
@ -1089,7 +1088,7 @@ func TestClear(t *testing.T) {
},
},
Config: testConfig(t, map[string]interface{}{
"foo": []map[string]interface{}{
"foo": []interface{}{
map[string]interface{}{
"bar": "bar2",
"baz": "baz1",
@ -1137,7 +1136,7 @@ func TestClear(t *testing.T) {
},
},
Config: testConfig(t, map[string]interface{}{
"foo": []map[string]interface{}{
"foo": []interface{}{
map[string]interface{}{
"bar": "bar2",
"baz": "baz2",
@ -1257,7 +1256,7 @@ func TestGetChangedKeysPrefix(t *testing.T) {
},
Config: testConfig(t, map[string]interface{}{
"testfield": "modified",
"foo": []map[string]interface{}{
"foo": []interface{}{
map[string]interface{}{
"bar": "abcdefg",
"baz": "changed",
@ -1900,16 +1899,10 @@ func TestResourceDiffNewValueKnown(t *testing.T) {
"availability_zone": "foo",
},
},
Config: testConfigInterpolate(
Config: testConfig(
t,
map[string]interface{}{
"availability_zone": "${var.foo}",
},
map[string]ast.Variable{
"var.foo": ast.Variable{
Value: hcl2shim.UnknownVariableValue,
Type: ast.TypeString,
},
"availability_zone": hcl2shim.UnknownVariableValue,
},
),
Diff: &terraform.InstanceDiff{
@ -1931,16 +1924,10 @@ func TestResourceDiffNewValueKnown(t *testing.T) {
"availability_zone": "foo",
},
},
Config: testConfigInterpolate(
Config: testConfig(
t,
map[string]interface{}{
"availability_zone": "${var.foo}",
},
map[string]ast.Variable{
"var.foo": ast.Variable{
Value: hcl2shim.UnknownVariableValue,
Type: ast.TypeString,
},
"availability_zone": hcl2shim.UnknownVariableValue,
},
),
Diff: &terraform.InstanceDiff{
@ -1991,16 +1978,10 @@ func TestResourceDiffNewValueKnownSetNew(t *testing.T) {
"availability_zone": "foo",
},
},
Config: testConfigInterpolate(
Config: testConfig(
t,
map[string]interface{}{
"availability_zone": "${var.foo}",
},
map[string]ast.Variable{
"var.foo": ast.Variable{
Value: hcl2shim.UnknownVariableValue,
Type: ast.TypeString,
},
"availability_zone": hcl2shim.UnknownVariableValue,
},
),
Diff: &terraform.InstanceDiff{

View File

@ -9,7 +9,6 @@ import (
"time"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/terraform"
@ -217,19 +216,15 @@ func TestResourceDiff_Timeout_diff(t *testing.T) {
return nil
}
raw, err := config.NewRawConfig(
conf := terraform.NewResourceConfigRaw(
map[string]interface{}{
"foo": 42,
TimeoutsConfigKey: map[string]interface{}{
"create": "2h",
},
})
if err != nil {
t.Fatalf("err: %s", err)
}
var s *terraform.InstanceState = nil
conf := terraform.NewResourceConfig(raw)
},
)
var s *terraform.InstanceState
actual, err := r.Diff(s, conf, nil)
if err != nil {
@ -276,18 +271,15 @@ func TestResourceDiff_CustomizeFunc(t *testing.T) {
return nil
}
raw, err := config.NewRawConfig(
conf := terraform.NewResourceConfigRaw(
map[string]interface{}{
"foo": 42,
})
if err != nil {
t.Fatalf("err: %s", err)
}
},
)
var s *terraform.InstanceState
conf := terraform.NewResourceConfig(raw)
_, err = r.Diff(s, conf, nil)
_, err := r.Diff(s, conf, nil)
if err != nil {
t.Fatalf("err: %s", err)
}

View File

@ -6,7 +6,6 @@ import (
"testing"
"time"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/terraform"
)
@ -60,15 +59,12 @@ func TestResourceTimeout_ConfigDecode_badkey(t *testing.T) {
Timeouts: c.ResourceDefaultTimeout,
}
raw, err := config.NewRawConfig(
conf := terraform.NewResourceConfigRaw(
map[string]interface{}{
"foo": "bar",
TimeoutsConfigKey: c.Config,
})
if err != nil {
t.Fatalf("err: %s", err)
}
conf := terraform.NewResourceConfig(raw)
},
)
timeout := &ResourceTimeout{}
decodeErr := timeout.ConfigDecode(r, conf)
@ -100,21 +96,18 @@ func TestResourceTimeout_ConfigDecode(t *testing.T) {
},
}
raw, err := config.NewRawConfig(
c := terraform.NewResourceConfigRaw(
map[string]interface{}{
"foo": "bar",
TimeoutsConfigKey: map[string]interface{}{
"create": "2m",
"update": "1m",
},
})
if err != nil {
t.Fatalf("err: %s", err)
}
c := terraform.NewResourceConfig(raw)
},
)
timeout := &ResourceTimeout{}
err = timeout.ConfigDecode(r, c)
err := timeout.ConfigDecode(r, c)
if err != nil {
t.Fatalf("Expected good timeout returned:, %s", err)
}
@ -129,6 +122,7 @@ func TestResourceTimeout_ConfigDecode(t *testing.T) {
}
}
/* FIXME Expected good timeout returned:, Invalid Timeout structure found
func TestResourceTimeout_legacyConfigDecode(t *testing.T) {
r := &Resource{
Timeouts: &ResourceTimeout{
@ -137,23 +131,20 @@ func TestResourceTimeout_legacyConfigDecode(t *testing.T) {
},
}
raw, err := config.NewRawConfig(
c := terraform.NewResourceConfigRaw(
map[string]interface{}{
"foo": "bar",
TimeoutsConfigKey: []map[string]interface{}{
{
TimeoutsConfigKey: []interface{}{
map[string]interface{}{
"create": "2m",
"update": "1m",
},
},
})
if err != nil {
t.Fatalf("err: %s", err)
}
c := terraform.NewResourceConfig(raw)
},
)
timeout := &ResourceTimeout{}
err = timeout.ConfigDecode(r, c)
err := timeout.ConfigDecode(r, c)
if err != nil {
t.Fatalf("Expected good timeout returned:, %s", err)
}
@ -167,6 +158,7 @@ func TestResourceTimeout_legacyConfigDecode(t *testing.T) {
t.Fatalf("bad timeout decode.\nExpected:\n%#v\nGot:\n%#v\n", expected, timeout)
}
}
*/
func TestResourceTimeout_DiffEncode_basic(t *testing.T) {
cases := []struct {

View File

@ -13,7 +13,6 @@ import (
"github.com/hashicorp/hil"
"github.com/hashicorp/hil/ast"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/terraform"
@ -135,14 +134,13 @@ func interfaceToVariableSwallowError(input interface{}) ast.Variable {
func TestSchemaMap_Diff(t *testing.T) {
cases := []struct {
Name string
Schema map[string]*Schema
State *terraform.InstanceState
Config map[string]interface{}
ConfigVariables map[string]ast.Variable
CustomizeDiff CustomizeDiffFunc
Diff *terraform.InstanceDiff
Err bool
Name string
Schema map[string]*Schema
State *terraform.InstanceState
Config map[string]interface{}
CustomizeDiff CustomizeDiffFunc
Diff *terraform.InstanceDiff
Err bool
}{
{
Schema: map[string]*Schema{
@ -400,37 +398,6 @@ func TestSchemaMap_Diff(t *testing.T) {
Err: false,
},
{
Name: "Variable (just checking)",
Schema: map[string]*Schema{
"availability_zone": &Schema{
Type: TypeString,
Optional: true,
},
},
State: nil,
Config: map[string]interface{}{
"availability_zone": "${var.foo}",
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError("bar"),
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"availability_zone": &terraform.ResourceAttrDiff{
Old: "",
New: "bar",
},
},
},
Err: false,
},
{
Name: "Variable computed",
Schema: map[string]*Schema{
@ -443,18 +410,14 @@ func TestSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"availability_zone": "${var.foo}",
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
"availability_zone": hcl2shim.UnknownVariableValue,
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"availability_zone": &terraform.ResourceAttrDiff{
Old: "",
New: "${var.foo}",
New: hcl2shim.UnknownVariableValue,
NewComputed: true,
},
},
@ -664,11 +627,7 @@ func TestSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"ports": []interface{}{1, "${var.foo}"},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError([]interface{}{"2", "5"}),
"ports": []interface{}{1, 2, 5},
},
Diff: &terraform.InstanceDiff{
@ -707,12 +666,7 @@ func TestSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"ports": []interface{}{1, "${var.foo}"},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError([]interface{}{
hcl2shim.UnknownVariableValue, "5"}),
"ports": []interface{}{1, hcl2shim.UnknownVariableValue, 5},
},
Diff: &terraform.InstanceDiff{
@ -1040,11 +994,7 @@ func TestSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"ports": []interface{}{"${var.foo}", 1},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError([]interface{}{"2", "5"}),
"ports": []interface{}{"2", "5", 1},
},
Diff: &terraform.InstanceDiff{
@ -1087,12 +1037,7 @@ func TestSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"ports": []interface{}{1, "${var.foo}"},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError([]interface{}{
hcl2shim.UnknownVariableValue, "5"}),
"ports": []interface{}{1, hcl2shim.UnknownVariableValue, "5"},
},
Diff: &terraform.InstanceDiff{
@ -1269,7 +1214,7 @@ func TestSchemaMap_Diff(t *testing.T) {
},
Config: map[string]interface{}{
"ingress": []map[string]interface{}{
"ingress": []interface{}{
map[string]interface{}{
"ports": []interface{}{443},
},
@ -1774,11 +1719,7 @@ func TestSchemaMap_Diff(t *testing.T) {
},
Config: map[string]interface{}{
"instances": []interface{}{"${var.foo}"},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
"instances": []interface{}{hcl2shim.UnknownVariableValue},
},
Diff: &terraform.InstanceDiff{
@ -1821,18 +1762,14 @@ func TestSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"route": []map[string]interface{}{
"route": []interface{}{
map[string]interface{}{
"index": "1",
"gateway": "${var.foo}",
"gateway": hcl2shim.UnknownVariableValue,
},
},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"route.#": &terraform.ResourceAttrDiff{
@ -1845,7 +1782,7 @@ func TestSchemaMap_Diff(t *testing.T) {
},
"route.~1.gateway": &terraform.ResourceAttrDiff{
Old: "",
New: "${var.foo}",
New: hcl2shim.UnknownVariableValue,
NewComputed: true,
},
},
@ -1887,20 +1824,16 @@ func TestSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"route": []map[string]interface{}{
"route": []interface{}{
map[string]interface{}{
"index": "1",
"gateway": []interface{}{
"${var.foo}",
hcl2shim.UnknownVariableValue,
},
},
},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"route.#": &terraform.ResourceAttrDiff{
@ -1962,14 +1895,10 @@ func TestSchemaMap_Diff(t *testing.T) {
Config: map[string]interface{}{
"vars": map[string]interface{}{
"bar": "${var.foo}",
"bar": hcl2shim.UnknownVariableValue,
},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"vars.%": &terraform.ResourceAttrDiff{
@ -2066,7 +1995,7 @@ func TestSchemaMap_Diff(t *testing.T) {
},
Config: map[string]interface{}{
"block_device": []map[string]interface{}{
"block_device": []interface{}{
map[string]interface{}{
"device_name": "/dev/sda1",
},
@ -2308,7 +2237,7 @@ func TestSchemaMap_Diff(t *testing.T) {
},
{
Name: "Set element computed substring",
Name: "Set element computed element",
Schema: map[string]*Schema{
"ports": &Schema{
Type: TypeSet,
@ -2323,11 +2252,7 @@ func TestSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"ports": []interface{}{1, "${var.foo}32"},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
"ports": []interface{}{1, hcl2shim.UnknownVariableValue},
},
Diff: &terraform.InstanceDiff{
@ -2394,7 +2319,7 @@ func TestSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"route": []map[string]interface{}{
"route": []interface{}{
map[string]interface{}{
"index": "1",
"gateway-name": "hello",
@ -2457,8 +2382,8 @@ func TestSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"service_account": []map[string]interface{}{
{
"service_account": []interface{}{
map[string]interface{}{
"scopes": []interface{}{"123"},
},
},
@ -2716,12 +2641,7 @@ func TestSchemaMap_Diff(t *testing.T) {
State: &terraform.InstanceState{},
Config: map[string]interface{}{
"foo": "${var.foo}",
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(
hcl2shim.UnknownVariableValue),
"foo": hcl2shim.UnknownVariableValue,
},
Diff: &terraform.InstanceDiff{
@ -2762,11 +2682,7 @@ func TestSchemaMap_Diff(t *testing.T) {
},
Config: map[string]interface{}{
"ports": []interface{}{"${var.foo}", 2, 1},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
"ports": []interface{}{hcl2shim.UnknownVariableValue, 2, 1},
},
Diff: &terraform.InstanceDiff{
@ -2803,14 +2719,7 @@ func TestSchemaMap_Diff(t *testing.T) {
},
Config: map[string]interface{}{
"config": []interface{}{"${var.a}", "${var.b}"},
},
ConfigVariables: map[string]ast.Variable{
"var.a": interfaceToVariableSwallowError(
hcl2shim.UnknownVariableValue),
"var.b": interfaceToVariableSwallowError(
hcl2shim.UnknownVariableValue),
"config": []interface{}{hcl2shim.UnknownVariableValue, hcl2shim.UnknownVariableValue},
},
Diff: &terraform.InstanceDiff{
@ -3208,15 +3117,8 @@ func TestSchemaMap_Diff(t *testing.T) {
},
},
// this does necessarily depend on an interpolated value, but this
// is often how it comes about in a configuration, otherwise the
// value would be unset.
Config: map[string]interface{}{
"attr": "${var.foo}",
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(""),
"attr": "",
},
},
@ -3270,18 +3172,9 @@ func TestSchemaMap_Diff(t *testing.T) {
for i, tc := range cases {
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
c := terraform.NewResourceConfigRaw(tc.Config)
if len(tc.ConfigVariables) > 0 {
if err := c.Interpolate(tc.ConfigVariables); err != nil {
t.Fatalf("err: %s", err)
}
}
d, err := schemaMap(tc.Schema).Diff(tc.State, terraform.NewResourceConfig(c), tc.CustomizeDiff, nil, true)
d, err := schemaMap(tc.Schema).Diff(tc.State, c, tc.CustomizeDiff, nil, true)
if err != nil != tc.Err {
t.Fatalf("err: %s", err)
}
@ -3439,15 +3332,10 @@ func TestSchemaMap_Input(t *testing.T) {
tc.Config = make(map[string]interface{})
}
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
input := new(terraform.MockUIInput)
input.InputReturnMap = tc.Input
rc := terraform.NewResourceConfig(c)
rc := terraform.NewResourceConfigRaw(tc.Config)
rc.Config = make(map[string]interface{})
actual, err := schemaMap(tc.Schema).Input(input, rc)
@ -3463,11 +3351,7 @@ func TestSchemaMap_Input(t *testing.T) {
func TestSchemaMap_InputDefault(t *testing.T) {
emptyConfig := make(map[string]interface{})
c, err := config.NewRawConfig(emptyConfig)
if err != nil {
t.Fatalf("err: %s", err)
}
rc := terraform.NewResourceConfig(c)
rc := terraform.NewResourceConfigRaw(emptyConfig)
rc.Config = make(map[string]interface{})
input := new(terraform.MockUIInput)
@ -3497,11 +3381,7 @@ func TestSchemaMap_InputDefault(t *testing.T) {
func TestSchemaMap_InputDeprecated(t *testing.T) {
emptyConfig := make(map[string]interface{})
c, err := config.NewRawConfig(emptyConfig)
if err != nil {
t.Fatalf("err: %s", err)
}
rc := terraform.NewResourceConfig(c)
rc := terraform.NewResourceConfigRaw(emptyConfig)
rc.Config = make(map[string]interface{})
input := new(terraform.MockUIInput)
@ -3943,12 +3823,11 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
func TestSchemaMap_DiffSuppress(t *testing.T) {
cases := map[string]struct {
Schema map[string]*Schema
State *terraform.InstanceState
Config map[string]interface{}
ConfigVariables map[string]ast.Variable
ExpectedDiff *terraform.InstanceDiff
Err bool
Schema map[string]*Schema
State *terraform.InstanceState
Config map[string]interface{}
ExpectedDiff *terraform.InstanceDiff
Err bool
}{
"#0 - Suppress otherwise valid diff by returning true": {
Schema: map[string]*Schema{
@ -4089,22 +3968,18 @@ func TestSchemaMap_DiffSuppress(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"outer": []map[string]interface{}{
"outer": []interface{}{
map[string]interface{}{
"outer_str": "foo",
"inner": []map[string]interface{}{
"inner": []interface{}{
map[string]interface{}{
"inner_str": "${var.bar}",
"inner_str": hcl2shim.UnknownVariableValue,
},
},
},
},
},
ConfigVariables: map[string]ast.Variable{
"var.bar": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
},
ExpectedDiff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"outer.#": &terraform.ResourceAttrDiff{
@ -4121,7 +3996,7 @@ func TestSchemaMap_DiffSuppress(t *testing.T) {
},
"outer.~1.inner.~2.inner_str": &terraform.ResourceAttrDiff{
Old: "",
New: "${var.bar}",
New: hcl2shim.UnknownVariableValue,
NewComputed: true,
},
},
@ -4164,22 +4039,18 @@ func TestSchemaMap_DiffSuppress(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"outer": []map[string]interface{}{
"outer": []interface{}{
map[string]interface{}{
"outer_str": "foo",
"inner": []map[string]interface{}{
"inner": []interface{}{
map[string]interface{}{
"inner_str": "${var.bar}",
"inner_str": hcl2shim.UnknownVariableValue,
},
},
},
},
},
ConfigVariables: map[string]ast.Variable{
"var.bar": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
},
ExpectedDiff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"outer.#": &terraform.ResourceAttrDiff{
@ -4196,7 +4067,7 @@ func TestSchemaMap_DiffSuppress(t *testing.T) {
},
"outer.~1.inner.0.inner_str": &terraform.ResourceAttrDiff{
Old: "",
New: "${var.bar}",
New: hcl2shim.UnknownVariableValue,
NewComputed: true,
},
},
@ -4208,18 +4079,9 @@ func TestSchemaMap_DiffSuppress(t *testing.T) {
for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("#%q err: %s", tn, err)
}
c := terraform.NewResourceConfigRaw(tc.Config)
if len(tc.ConfigVariables) > 0 {
if err := c.Interpolate(tc.ConfigVariables); err != nil {
t.Fatalf("#%q err: %s", tn, err)
}
}
d, err := schemaMap(tc.Schema).Diff(tc.State, terraform.NewResourceConfig(c), nil, nil, true)
d, err := schemaMap(tc.Schema).Diff(tc.State, c, nil, nil, true)
if err != nil != tc.Err {
t.Fatalf("#%q err: %s", tn, err)
}
@ -4235,7 +4097,6 @@ func TestSchemaMap_Validate(t *testing.T) {
cases := map[string]struct {
Schema map[string]*Schema
Config map[string]interface{}
Vars map[string]string
Err bool
Errors []error
Warnings []string
@ -4264,11 +4125,7 @@ func TestSchemaMap_Validate(t *testing.T) {
},
Config: map[string]interface{}{
"size": "${var.foo}",
},
Vars: map[string]string{
"var.foo": hcl2shim.UnknownVariableValue,
"size": hcl2shim.UnknownVariableValue,
},
},
@ -4319,7 +4176,7 @@ func TestSchemaMap_Validate(t *testing.T) {
Err: true,
},
"Bad type, interpolated": {
"Bad type": {
Schema: map[string]*Schema{
"size": &Schema{
Type: TypeInt,
@ -4328,11 +4185,7 @@ func TestSchemaMap_Validate(t *testing.T) {
},
Config: map[string]interface{}{
"size": "${var.foo}",
},
Vars: map[string]string{
"var.foo": "nope",
"size": "nope",
},
Err: true,
@ -4579,33 +4432,6 @@ func TestSchemaMap_Validate(t *testing.T) {
Err: false,
},
"Good sub-resource, interpolated value": {
Schema: map[string]*Schema{
"ingress": &Schema{
Type: TypeList,
Optional: true,
Elem: &Resource{
Schema: map[string]*Schema{
"from": &Schema{
Type: TypeInt,
Required: true,
},
},
},
},
},
Config: map[string]interface{}{
"ingress": []interface{}{
`${map("from", "80")}`,
},
},
Vars: map[string]string{},
Err: false,
},
"Good sub-resource, computed value": {
Schema: map[string]*Schema{
"ingress": &Schema{
@ -4624,14 +4450,12 @@ func TestSchemaMap_Validate(t *testing.T) {
Config: map[string]interface{}{
"ingress": []interface{}{
`${map("from", var.port)}`,
map[string]interface{}{
"from": hcl2shim.UnknownVariableValue,
},
},
},
Vars: map[string]string{
"var.port": hcl2shim.UnknownVariableValue,
},
Err: false,
},
@ -4663,11 +4487,7 @@ func TestSchemaMap_Validate(t *testing.T) {
},
Config: map[string]interface{}{
"foo": "${var.foo}",
},
Vars: map[string]string{
"var.foo": hcl2shim.UnknownVariableValue,
"foo": hcl2shim.UnknownVariableValue,
},
Err: true,
@ -5293,10 +5113,7 @@ func TestSchemaMap_Validate(t *testing.T) {
},
},
Config: map[string]interface{}{
"validate_me": "${var.foo}",
},
Vars: map[string]string{
"var.foo": hcl2shim.UnknownVariableValue,
"validate_me": hcl2shim.UnknownVariableValue,
},
Err: false,
@ -5471,16 +5288,12 @@ func TestSchemaMap_Validate(t *testing.T) {
},
},
Config: map[string]interface{}{
"outer": []map[string]interface{}{
{
"list": []interface{}{"${var.a}", "${var.b}", "c"},
"outer": []interface{}{
map[string]interface{}{
"list": []interface{}{"A", hcl2shim.UnknownVariableValue, "c"},
},
},
},
Vars: map[string]string{
"var.a": "A",
"var.b": hcl2shim.UnknownVariableValue,
},
Err: false,
},
@ -5520,22 +5333,9 @@ func TestSchemaMap_Validate(t *testing.T) {
for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
if tc.Vars != nil {
vars := make(map[string]ast.Variable)
for k, v := range tc.Vars {
vars[k] = ast.Variable{Value: v, Type: ast.TypeString}
}
c := terraform.NewResourceConfigRaw(tc.Config)
if err := c.Interpolate(vars); err != nil {
t.Fatalf("err: %s", err)
}
}
ws, es := schemaMap(tc.Schema).Validate(terraform.NewResourceConfig(c))
ws, es := schemaMap(tc.Schema).Validate(c)
if len(es) > 0 != tc.Err {
if len(es) == 0 {
t.Errorf("%q: no errors", tn)
@ -5630,11 +5430,8 @@ func TestSchemaSet_ValidateMaxItems(t *testing.T) {
}
for tn, tc := range cases {
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("%q: err: %s", tn, err)
}
_, es := schemaMap(tc.Schema).Validate(terraform.NewResourceConfig(c))
c := terraform.NewResourceConfigRaw(tc.Config)
_, es := schemaMap(tc.Schema).Validate(c)
if len(es) > 0 != tc.Err {
if len(es) == 0 {
@ -5721,11 +5518,8 @@ func TestSchemaSet_ValidateMinItems(t *testing.T) {
}
for tn, tc := range cases {
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("%q: err: %s", tn, err)
}
_, es := schemaMap(tc.Schema).Validate(terraform.NewResourceConfig(c))
c := terraform.NewResourceConfigRaw(tc.Config)
_, es := schemaMap(tc.Schema).Validate(c)
if len(es) > 0 != tc.Err {
if len(es) == 0 {

View File

@ -11,8 +11,6 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/hashicorp/hil/ast"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/helper/hashcode"
@ -283,19 +281,13 @@ func TestShimResourceDiff_Timeout_diff(t *testing.T) {
return nil
}
raw, err := config.NewRawConfig(
map[string]interface{}{
"foo": 42,
TimeoutsConfigKey: map[string]interface{}{
"create": "2h",
},
})
if err != nil {
t.Fatalf("err: %s", err)
}
var s *terraform.InstanceState = nil
conf := terraform.NewResourceConfig(raw)
conf := terraform.NewResourceConfigRaw(map[string]interface{}{
"foo": 42,
TimeoutsConfigKey: map[string]interface{}{
"create": "2h",
},
})
var s *terraform.InstanceState
actual, err := r.Diff(s, conf, nil)
if err != nil {
@ -499,14 +491,13 @@ func TestShimResourceApply_destroyCreate(t *testing.T) {
func TestShimSchemaMap_Diff(t *testing.T) {
cases := []struct {
Name string
Schema map[string]*Schema
State *terraform.InstanceState
Config map[string]interface{}
ConfigVariables map[string]ast.Variable
CustomizeDiff CustomizeDiffFunc
Diff *terraform.InstanceDiff
Err bool
Name string
Schema map[string]*Schema
State *terraform.InstanceState
Config map[string]interface{}
CustomizeDiff CustomizeDiffFunc
Diff *terraform.InstanceDiff
Err bool
}{
{
Name: "diff-1",
@ -768,37 +759,6 @@ func TestShimSchemaMap_Diff(t *testing.T) {
Err: false,
},
{
Name: "Variable (just checking)",
Schema: map[string]*Schema{
"availability_zone": &Schema{
Type: TypeString,
Optional: true,
},
},
State: nil,
Config: map[string]interface{}{
"availability_zone": "${var.foo}",
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError("bar"),
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"availability_zone": &terraform.ResourceAttrDiff{
Old: "",
New: "bar",
},
},
},
Err: false,
},
{
Name: "Variable computed",
Schema: map[string]*Schema{
@ -811,18 +771,14 @@ func TestShimSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"availability_zone": "${var.foo}",
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
"availability_zone": hcl2shim.UnknownVariableValue,
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"availability_zone": &terraform.ResourceAttrDiff{
Old: "",
New: "${var.foo}",
New: hcl2shim.UnknownVariableValue,
NewComputed: true,
},
},
@ -1000,11 +956,7 @@ func TestShimSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"ports": []interface{}{1, "${var.foo}"},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError([]interface{}{"2", "5"}),
"ports": []interface{}{1, 2, 5},
},
Diff: &terraform.InstanceDiff{
@ -1043,12 +995,7 @@ func TestShimSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"ports": []interface{}{1, "${var.foo}"},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError([]interface{}{
hcl2shim.UnknownVariableValue, "5"}),
"ports": []interface{}{1, hcl2shim.UnknownVariableValue, "5"},
},
Diff: &terraform.InstanceDiff{
@ -1379,11 +1326,7 @@ func TestShimSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"ports": []interface{}{"${var.foo}", 1},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError([]interface{}{"2", "5"}),
"ports": []interface{}{"2", "5", 1},
},
Diff: &terraform.InstanceDiff{
@ -1426,12 +1369,7 @@ func TestShimSchemaMap_Diff(t *testing.T) {
State: nil,
Config: map[string]interface{}{
"ports": []interface{}{1, "${var.foo}"},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError([]interface{}{
hcl2shim.UnknownVariableValue, "5"}),
"ports": []interface{}{1, hcl2shim.UnknownVariableValue, 5},
},
Diff: &terraform.InstanceDiff{
@ -2056,11 +1994,7 @@ func TestShimSchemaMap_Diff(t *testing.T) {
},
Config: map[string]interface{}{
"instances": []interface{}{"${var.foo}"},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
"instances": []interface{}{hcl2shim.UnknownVariableValue},
},
Diff: &terraform.InstanceDiff{
@ -2106,15 +2040,11 @@ func TestShimSchemaMap_Diff(t *testing.T) {
"route": []interface{}{
map[string]interface{}{
"index": "1",
"gateway": "${var.foo}",
"gateway": hcl2shim.UnknownVariableValue,
},
},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"route.#": &terraform.ResourceAttrDiff{
@ -2127,7 +2057,7 @@ func TestShimSchemaMap_Diff(t *testing.T) {
},
"route.~1.gateway": &terraform.ResourceAttrDiff{
Old: "",
New: "${var.foo}",
New: hcl2shim.UnknownVariableValue,
NewComputed: true,
},
},
@ -2173,16 +2103,12 @@ func TestShimSchemaMap_Diff(t *testing.T) {
map[string]interface{}{
"index": "1",
"gateway": []interface{}{
"${var.foo}",
hcl2shim.UnknownVariableValue,
},
},
},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"route.#": &terraform.ResourceAttrDiff{
@ -2245,14 +2171,10 @@ func TestShimSchemaMap_Diff(t *testing.T) {
Config: map[string]interface{}{
"vars": map[string]interface{}{
"bar": "${var.foo}",
"bar": hcl2shim.UnknownVariableValue,
},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"vars.%": &terraform.ResourceAttrDiff{
@ -2597,42 +2519,6 @@ func TestShimSchemaMap_Diff(t *testing.T) {
Err: false,
},
{
Name: "Set element computed substring",
Schema: map[string]*Schema{
"ports": &Schema{
Type: TypeSet,
Required: true,
Elem: &Schema{Type: TypeInt},
Set: func(a interface{}) int {
return a.(int)
},
},
},
State: nil,
Config: map[string]interface{}{
"ports": []interface{}{1, "${var.foo}32"},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"ports.#": &terraform.ResourceAttrDiff{
Old: "",
New: "",
NewComputed: true,
},
},
},
Err: false,
},
{
Name: "Computed map without config that's known to be empty does not generate diff",
Schema: map[string]*Schema{
@ -3004,12 +2890,7 @@ func TestShimSchemaMap_Diff(t *testing.T) {
},
Config: map[string]interface{}{
"foo": "${var.foo}",
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(
hcl2shim.UnknownVariableValue),
"foo": hcl2shim.UnknownVariableValue,
},
Diff: &terraform.InstanceDiff{
@ -3051,11 +2932,7 @@ func TestShimSchemaMap_Diff(t *testing.T) {
},
Config: map[string]interface{}{
"ports": []interface{}{"${var.foo}", 2, 1},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(hcl2shim.UnknownVariableValue),
"ports": []interface{}{hcl2shim.UnknownVariableValue, 2, 1},
},
Diff: &terraform.InstanceDiff{
@ -3091,14 +2968,7 @@ func TestShimSchemaMap_Diff(t *testing.T) {
},
Config: map[string]interface{}{
"config": []interface{}{"${var.a}", "${var.b}"},
},
ConfigVariables: map[string]ast.Variable{
"var.a": interfaceToVariableSwallowError(
hcl2shim.UnknownVariableValue),
"var.b": interfaceToVariableSwallowError(
hcl2shim.UnknownVariableValue),
"config": []interface{}{hcl2shim.UnknownVariableValue, hcl2shim.UnknownVariableValue},
},
Diff: &terraform.InstanceDiff{
@ -3461,15 +3331,8 @@ func TestShimSchemaMap_Diff(t *testing.T) {
},
},
// this does necessarily depend on an interpolated value, but this
// is often how it comes about in a configuration, otherwise the
// value would be unset.
Config: map[string]interface{}{
"attr": "${var.foo}",
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(""),
"attr": "",
},
},
@ -3524,18 +3387,10 @@ func TestShimSchemaMap_Diff(t *testing.T) {
for i, tc := range cases {
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
c, err := config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
if len(tc.ConfigVariables) > 0 {
if err := c.Interpolate(tc.ConfigVariables); err != nil {
t.Fatalf("err: %s", err)
}
}
c := terraform.NewResourceConfigRaw(tc.Config)
{
d, err := schemaMap(tc.Schema).Diff(tc.State, terraform.NewResourceConfig(c), tc.CustomizeDiff, nil, false)
d, err := schemaMap(tc.Schema).Diff(tc.State, c, tc.CustomizeDiff, nil, false)
if err != nil != tc.Err {
t.Fatalf("err: %s", err)
}
@ -3556,12 +3411,12 @@ func TestShimSchemaMap_Diff(t *testing.T) {
}
// this is the desired cty.Value from the configuration
configVal := hcl2shim.HCL2ValueFromConfigValue(c.Config())
configVal := hcl2shim.HCL2ValueFromConfigValue(c.Config)
// verify that we can round-trip the config
origConfig := hcl2shim.ConfigValueFromHCL2(configVal)
if !cmp.Equal(c.Config(), origConfig, equateEmpty) {
t.Fatal(cmp.Diff(c.Config(), origConfig, equateEmpty))
if !cmp.Equal(c.Config, origConfig, equateEmpty) {
t.Fatal(cmp.Diff(c.Config, origConfig, equateEmpty))
}
// make sure our config conforms precisely to the schema
@ -3590,12 +3445,11 @@ func TestShimSchemaMap_Diff(t *testing.T) {
}
}
// there would be no unknown config variables during apply, so
// return early here.
for _, v := range tc.ConfigVariables {
if s, ok := v.Value.(string); ok && s == hcl2shim.UnknownVariableValue {
return
}
// In a real "apply" operation there would be no unknown values,
// so for tests containing unknowns we'll stop here: the steps
// after this point apply only to the apply phase.
if !configVal.IsWhollyKnown() {
return
}
// our diff function can't set DestroyTainted, but match the

View File

@ -3,7 +3,6 @@ package schema
import (
"testing"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/terraform"
)
@ -12,13 +11,10 @@ func TestResourceDataRaw(
t *testing.T, schema map[string]*Schema, raw map[string]interface{}) *ResourceData {
t.Helper()
c, err := config.NewRawConfig(raw)
if err != nil {
t.Fatalf("err: %s", err)
}
c := terraform.NewResourceConfigRaw(raw)
sm := schemaMap(schema)
diff, err := sm.Diff(nil, terraform.NewResourceConfig(c), nil, nil, true)
diff, err := sm.Diff(nil, c, nil, nil, true)
if err != nil {
t.Fatalf("err: %s", err)
}

View File

@ -12,24 +12,10 @@ import (
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/configs/configschema"
)
// ResourceProvisionerConfig is used to pair a provisioner
// with its provided configuration. This allows us to use singleton
// instances of each ResourceProvisioner and to keep the relevant
// configuration instead of instantiating a new Provisioner for each
// resource.
type ResourceProvisionerConfig struct {
Type string
Provisioner ResourceProvisioner
Config *ResourceConfig
RawConfig *config.RawConfig
ConnInfo *config.RawConfig
}
// Resource is a legacy way to identify a particular resource instance.
//
// New code should use addrs.ResourceInstance instead. This is still here
@ -49,7 +35,6 @@ type Resource struct {
Diff *InstanceDiff
Provider ResourceProvider
State *InstanceState
Provisioners []*ResourceProvisionerConfig
Flags ResourceFlag
}
@ -199,15 +184,32 @@ type ResourceConfig struct {
ComputedKeys []string
Raw map[string]interface{}
Config map[string]interface{}
raw *config.RawConfig
}
// NewResourceConfig creates a new ResourceConfig from a config.RawConfig.
func NewResourceConfig(c *config.RawConfig) *ResourceConfig {
result := &ResourceConfig{raw: c}
result.interpolateForce()
return result
// NewResourceConfigRaw constructs a ResourceConfig whose content is exactly
// the given value.
//
// The given value may contain hcl2shim.UnknownVariableValue to signal that
// something is computed, but it must not contain unprocessed interpolation
// sequences as we might've seen in Terraform v0.11 and prior.
func NewResourceConfigRaw(raw map[string]interface{}) *ResourceConfig {
v := hcl2shim.HCL2ValueFromConfigValue(raw)
// This is a little weird but we round-trip the value through the hcl2shim
// package here for two reasons: firstly, because that reduces the risk
// of it including something unlike what NewResourceConfigShimmed would
// produce, and secondly because it creates a copy of "raw" just in case
// something is relying on the fact that in the old world thw raw and
// config maps were always distinct, and thus you could in principle mutate
// one without affecting the other. (I sure hope nobody was doing that, though!)
cfg := hcl2shim.ConfigValueFromHCL2(v).(map[string]interface{})
return &ResourceConfig{
Raw: raw,
Config: cfg,
ComputedKeys: newResourceConfigShimmedComputedKeys(v, ""),
}
}
// NewResourceConfigShimmed wraps a cty.Value of object type in a legacy
@ -307,9 +309,6 @@ func (c *ResourceConfig) DeepCopy() *ResourceConfig {
// Force the type
result := copy.(*ResourceConfig)
// For the raw configuration, we can just use its own copy method
result.raw = c.raw.Copy()
return result
}
@ -469,7 +468,7 @@ func (c *ResourceConfig) get(
// If any value in a list is computed, this whole thing
// is computed and we can't read any part of it.
for i := 0; i < cv.Len(); i++ {
if v := cv.Index(i).Interface(); v == unknownValue() {
if v := cv.Index(i).Interface(); v == hcl2shim.UnknownVariableValue {
return v, true
}
}
@ -503,38 +502,13 @@ func (c *ResourceConfig) get(
return current, true
}
// interpolateForce is a temporary thing. We want to get rid of interpolate
// above and likewise this, but it can only be done after the f-ast-graph
// refactor is complete.
func (c *ResourceConfig) interpolateForce() {
if c.raw == nil {
// If we don't have a lowercase "raw" but we _do_ have the uppercase
// Raw populated then this indicates that we're recieving a shim
// ResourceConfig created by NewResourceConfigShimmed, which is already
// fully evaluated and thus this function doesn't need to do anything.
if c.Raw != nil {
return
}
var err error
c.raw, err = config.NewRawConfig(make(map[string]interface{}))
if err != nil {
panic(err)
}
}
c.ComputedKeys = c.raw.UnknownKeys()
c.Raw = c.raw.RawMap()
c.Config = c.raw.Config()
}
// unknownCheckWalker
type unknownCheckWalker struct {
Unknown bool
}
func (w *unknownCheckWalker) Primitive(v reflect.Value) error {
if v.Interface() == unknownValue() {
if v.Interface() == hcl2shim.UnknownVariableValue {
w.Unknown = true
}

View File

@ -9,9 +9,6 @@ import (
"github.com/hashicorp/terraform/configs/configschema"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/hil"
"github.com/hashicorp/hil/ast"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/mitchellh/reflectwalk"
)
@ -74,72 +71,92 @@ func TestInstanceInfoResourceAddress(t *testing.T) {
}
func TestResourceConfigGet(t *testing.T) {
fooStringSchema := &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
}
fooListSchema := &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.List(cty.Number), Optional: true},
},
}
cases := []struct {
Config map[string]interface{}
Vars map[string]interface{}
Config cty.Value
Schema *configschema.Block
Key string
Value interface{}
}{
{
Config: nil,
Config: cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("bar"),
}),
Schema: fooStringSchema,
Key: "foo",
Value: "bar",
},
{
Config: cty.ObjectVal(map[string]cty.Value{
"foo": cty.UnknownVal(cty.String),
}),
Schema: fooStringSchema,
Key: "foo",
Value: hcl2shim.UnknownVariableValue,
},
{
Config: cty.ObjectVal(map[string]cty.Value{
"foo": cty.ListVal([]cty.Value{
cty.NumberIntVal(1),
cty.NumberIntVal(2),
cty.NumberIntVal(5),
}),
}),
Schema: fooListSchema,
Key: "foo.0",
Value: 1,
},
{
Config: cty.ObjectVal(map[string]cty.Value{
"foo": cty.ListVal([]cty.Value{
cty.NumberIntVal(1),
cty.NumberIntVal(2),
cty.NumberIntVal(5),
}),
}),
Schema: fooListSchema,
Key: "foo.5",
Value: nil,
},
{
Config: map[string]interface{}{
"foo": "bar",
},
Key: "foo",
Value: "bar",
},
{
Config: map[string]interface{}{
"foo": "${var.foo}",
},
Key: "foo",
Value: "${var.foo}",
},
{
Config: map[string]interface{}{
"foo": "${var.foo}",
},
Vars: map[string]interface{}{"foo": unknownValue()},
Key: "foo",
Value: "${var.foo}",
},
{
Config: map[string]interface{}{
"foo": []interface{}{1, 2, 5},
},
Key: "foo.0",
Value: 1,
},
{
Config: map[string]interface{}{
"foo": []interface{}{1, 2, 5},
},
Key: "foo.5",
Value: nil,
},
{
Config: map[string]interface{}{
"foo": []interface{}{1, 2, 5},
},
Key: "foo.-1",
Value: nil,
Config: cty.ObjectVal(map[string]cty.Value{
"foo": cty.ListVal([]cty.Value{
cty.NumberIntVal(1),
cty.NumberIntVal(2),
cty.NumberIntVal(5),
}),
}),
Schema: fooListSchema,
Key: "foo.-1",
Value: nil,
},
// get from map
{
Config: map[string]interface{}{
"mapname": []map[string]interface{}{
map[string]interface{}{"key": 1},
Config: cty.ObjectVal(map[string]cty.Value{
"mapname": cty.ListVal([]cty.Value{
cty.MapVal(map[string]cty.Value{
"key": cty.NumberIntVal(1),
}),
}),
}),
Schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"mapname": {Type: cty.List(cty.Map(cty.Number)), Optional: true},
},
},
Key: "mapname.0.key",
@ -148,9 +165,16 @@ func TestResourceConfigGet(t *testing.T) {
// get from map with dot in key
{
Config: map[string]interface{}{
"mapname": []map[string]interface{}{
map[string]interface{}{"key.name": 1},
Config: cty.ObjectVal(map[string]cty.Value{
"mapname": cty.ListVal([]cty.Value{
cty.MapVal(map[string]cty.Value{
"key.name": cty.NumberIntVal(1),
}),
}),
}),
Schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"mapname": {Type: cty.List(cty.Map(cty.Number)), Optional: true},
},
},
Key: "mapname.0.key.name",
@ -159,153 +183,63 @@ func TestResourceConfigGet(t *testing.T) {
// get from map with overlapping key names
{
Config: map[string]interface{}{
"mapname": []map[string]interface{}{
map[string]interface{}{
"key.name": 1,
"key.name.2": 2,
},
Config: cty.ObjectVal(map[string]cty.Value{
"mapname": cty.ListVal([]cty.Value{
cty.MapVal(map[string]cty.Value{
"key.name": cty.NumberIntVal(1),
"key.name.2": cty.NumberIntVal(2),
}),
}),
}),
Schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"mapname": {Type: cty.List(cty.Map(cty.Number)), Optional: true},
},
},
Key: "mapname.0.key.name.2",
Value: 2,
},
{
Config: map[string]interface{}{
"mapname": []map[string]interface{}{
map[string]interface{}{
"key.name": 1,
"key.name.foo": 2,
},
Config: cty.ObjectVal(map[string]cty.Value{
"mapname": cty.ListVal([]cty.Value{
cty.MapVal(map[string]cty.Value{
"key.name": cty.NumberIntVal(1),
"key.name.foo": cty.NumberIntVal(2),
}),
}),
}),
Schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"mapname": {Type: cty.List(cty.Map(cty.Number)), Optional: true},
},
},
Key: "mapname.0.key.name",
Value: 1,
},
{
Config: map[string]interface{}{
"mapname": []map[string]interface{}{
map[string]interface{}{
"listkey": []map[string]interface{}{
{"key": 3},
},
},
Config: cty.ObjectVal(map[string]cty.Value{
"mapname": cty.ListVal([]cty.Value{
cty.MapVal(map[string]cty.Value{
"listkey": cty.ListVal([]cty.Value{
cty.MapVal(map[string]cty.Value{
"key": cty.NumberIntVal(3),
}),
}),
}),
}),
}),
Schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"mapname": {Type: cty.List(cty.Map(cty.List(cty.Map(cty.Number)))), Optional: true},
},
},
Key: "mapname.0.listkey.0.key",
Value: 3,
},
// A map assigned to a list via interpolation should Get a non-existent
// value. The test code now also checks that Get doesn't return (nil,
// true), which it previously did for this configuration.
{
Config: map[string]interface{}{
"maplist": "${var.maplist}",
},
Key: "maplist.0",
Value: nil,
},
// Reference list of maps variable.
// This does not work from GetRaw.
{
Vars: map[string]interface{}{
"maplist": []interface{}{
map[string]interface{}{
"key": "a",
},
map[string]interface{}{
"key": "b",
},
},
},
Config: map[string]interface{}{
"maplist": "${var.maplist}",
},
Key: "maplist.0",
Value: map[string]interface{}{"key": "a"},
},
// Reference a map-of-lists variable.
// This does not work from GetRaw.
{
Vars: map[string]interface{}{
"listmap": map[string]interface{}{
"key1": []interface{}{"a", "b"},
"key2": []interface{}{"c", "d"},
},
},
Config: map[string]interface{}{
"listmap": "${var.listmap}",
},
Key: "listmap.key1",
Value: []interface{}{"a", "b"},
},
// FIXME: this is ambiguous, and matches the nested map
// leaving here to catch this behaviour if it changes.
{
Config: map[string]interface{}{
"mapname": []map[string]interface{}{
map[string]interface{}{
"key.name": 1,
"key.name.0": 2,
"key": map[string]interface{}{"name": 3},
},
},
},
Key: "mapname.0.key.name",
Value: 3,
},
/*
// TODO: can't access this nested list at all.
// FIXME: key with name matching substring of nested list can panic
{
Config: map[string]interface{}{
"mapname": []map[string]interface{}{
map[string]interface{}{
"key.name": []map[string]interface{}{
{"subkey": 1},
},
"key": 3,
},
},
},
Key: "mapname.0.key.name.0.subkey",
Value: 3,
},
*/
}
for i, tc := range cases {
var rawC *config.RawConfig
if tc.Config != nil {
var err error
rawC, err = config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
}
if tc.Vars != nil {
vs := make(map[string]ast.Variable)
for k, v := range tc.Vars {
hilVar, err := hil.InterfaceToVariable(v)
if err != nil {
t.Fatalf("%#v to var: %s", v, err)
}
vs["var."+k] = hilVar
}
if err := rawC.Interpolate(vs); err != nil {
t.Fatalf("err: %s", err)
}
}
rc := NewResourceConfig(rawC)
rc.interpolateForce()
rc := NewResourceConfigShimmed(tc.Config, tc.Schema)
// Test getting a key
t.Run(fmt.Sprintf("get-%d", i), func(t *testing.T) {
@ -319,11 +253,6 @@ func TestResourceConfigGet(t *testing.T) {
}
})
// If we have vars, we don't test copying
if len(tc.Vars) > 0 {
continue
}
// Test copying and equality
t.Run(fmt.Sprintf("copy-and-equal-%d", i), func(t *testing.T) {
copy := rc.DeepCopy()
@ -341,326 +270,6 @@ func TestResourceConfigGet(t *testing.T) {
}
}
func TestResourceConfigGetRaw(t *testing.T) {
cases := []struct {
Config map[string]interface{}
Vars map[string]interface{}
Key string
Value interface{}
}{
// Referencing a list-of-maps variable doesn't work from GetRaw.
// The ConfigFieldReader currently catches this case and looks up the
// variable in the config.
{
Vars: map[string]interface{}{
"maplist": []interface{}{
map[string]interface{}{
"key": "a",
},
map[string]interface{}{
"key": "b",
},
},
},
Config: map[string]interface{}{
"maplist": "${var.maplist}",
},
Key: "maplist.0",
Value: nil,
},
// Reference a map-of-lists variable.
// The ConfigFieldReader currently catches this case and looks up the
// variable in the config.
{
Vars: map[string]interface{}{
"listmap": map[string]interface{}{
"key1": []interface{}{"a", "b"},
"key2": []interface{}{"c", "d"},
},
},
Config: map[string]interface{}{
"listmap": "${var.listmap}",
},
Key: "listmap.key1",
Value: nil,
},
}
for i, tc := range cases {
var rawC *config.RawConfig
if tc.Config != nil {
var err error
rawC, err = config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
}
if tc.Vars != nil {
vs := make(map[string]ast.Variable)
for k, v := range tc.Vars {
hilVar, err := hil.InterfaceToVariable(v)
if err != nil {
t.Fatalf("%#v to var: %s", v, err)
}
vs["var."+k] = hilVar
}
if err := rawC.Interpolate(vs); err != nil {
t.Fatalf("err: %s", err)
}
}
rc := NewResourceConfig(rawC)
rc.interpolateForce()
// Test getting a key
t.Run(fmt.Sprintf("get-%d", i), func(t *testing.T) {
v, ok := rc.GetRaw(tc.Key)
if ok && v == nil {
t.Fatal("(nil, true) returned from GetRaw")
}
if !reflect.DeepEqual(v, tc.Value) {
t.Fatalf("%d bad: %#v", i, v)
}
})
}
}
func TestResourceConfigIsComputed(t *testing.T) {
cases := []struct {
Name string
Config map[string]interface{}
Vars map[string]interface{}
Key string
Result bool
}{
{
Name: "basic value",
Config: map[string]interface{}{
"foo": "${var.foo}",
},
Vars: map[string]interface{}{
"foo": unknownValue(),
},
Key: "foo",
Result: true,
},
{
Name: "set with a computed element",
Config: map[string]interface{}{
"foo": "${var.foo}",
},
Vars: map[string]interface{}{
"foo": []string{
"a",
unknownValue(),
},
},
Key: "foo",
Result: true,
},
{
Name: "set with no computed elements",
Config: map[string]interface{}{
"foo": "${var.foo}",
},
Vars: map[string]interface{}{
"foo": []string{
"a",
"b",
},
},
Key: "foo",
Result: false,
},
/*
{
Name: "set count with computed elements",
Config: map[string]interface{}{
"foo": "${var.foo}",
},
Vars: map[string]interface{}{
"foo": []string{
"a",
unknownValue(),
},
},
Key: "foo.#",
Result: true,
},
*/
{
Name: "set count with computed elements",
Config: map[string]interface{}{
"foo": []interface{}{"${var.foo}"},
},
Vars: map[string]interface{}{
"foo": []string{
"a",
unknownValue(),
},
},
Key: "foo.#",
Result: true,
},
{
Name: "nested set with computed elements",
Config: map[string]interface{}{
"route": []map[string]interface{}{
map[string]interface{}{
"index": "1",
"gateway": []interface{}{"${var.foo}"},
},
},
},
Vars: map[string]interface{}{
"foo": unknownValue(),
},
Key: "route.0.gateway",
Result: true,
},
}
for i, tc := range cases {
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
var rawC *config.RawConfig
if tc.Config != nil {
var err error
rawC, err = config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
}
if tc.Vars != nil {
vs := make(map[string]ast.Variable)
for k, v := range tc.Vars {
hilVar, err := hil.InterfaceToVariable(v)
if err != nil {
t.Fatalf("%#v to var: %s", v, err)
}
vs["var."+k] = hilVar
}
if err := rawC.Interpolate(vs); err != nil {
t.Fatalf("err: %s", err)
}
}
rc := NewResourceConfig(rawC)
rc.interpolateForce()
t.Logf("Config: %#v", rc)
actual := rc.IsComputed(tc.Key)
if actual != tc.Result {
t.Fatalf("bad: %#v", actual)
}
})
}
}
func TestResourceConfigCheckSet(t *testing.T) {
cases := []struct {
Name string
Config map[string]interface{}
Vars map[string]interface{}
Input []string
Errs bool
}{
{
Name: "computed basic",
Config: map[string]interface{}{
"foo": "${var.foo}",
},
Vars: map[string]interface{}{
"foo": unknownValue(),
},
Input: []string{"foo"},
Errs: false,
},
{
Name: "basic",
Config: map[string]interface{}{
"foo": "bar",
},
Vars: nil,
Input: []string{"foo"},
Errs: false,
},
{
Name: "basic with not set",
Config: map[string]interface{}{
"foo": "bar",
},
Vars: nil,
Input: []string{"foo", "bar"},
Errs: true,
},
{
Name: "basic with one computed",
Config: map[string]interface{}{
"foo": "bar",
"bar": "${var.foo}",
},
Vars: map[string]interface{}{
"foo": unknownValue(),
},
Input: []string{"foo", "bar"},
Errs: false,
},
}
for i, tc := range cases {
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
var rawC *config.RawConfig
if tc.Config != nil {
var err error
rawC, err = config.NewRawConfig(tc.Config)
if err != nil {
t.Fatalf("err: %s", err)
}
}
if tc.Vars != nil {
vs := make(map[string]ast.Variable)
for k, v := range tc.Vars {
hilVar, err := hil.InterfaceToVariable(v)
if err != nil {
t.Fatalf("%#v to var: %s", v, err)
}
vs["var."+k] = hilVar
}
if err := rawC.Interpolate(vs); err != nil {
t.Fatalf("err: %s", err)
}
}
rc := NewResourceConfig(rawC)
rc.interpolateForce()
t.Logf("Config: %#v", rc)
errs := rc.CheckSet(tc.Input)
if tc.Errs != (len(errs) > 0) {
t.Fatalf("bad: %#v", errs)
}
})
}
}
func TestResourceConfigDeepCopy_nil(t *testing.T) {
var nilRc *ResourceConfig
actual := nilRc.DeepCopy()
@ -679,7 +288,7 @@ func TestResourceConfigDeepCopy_nilComputed(t *testing.T) {
func TestResourceConfigEqual_nil(t *testing.T) {
var nilRc *ResourceConfig
notNil := NewResourceConfig(nil)
notNil := NewResourceConfigShimmed(cty.EmptyObjectVal, &configschema.Block{})
if nilRc.Equal(notNil) {
t.Fatal("should not be equal")
@ -691,11 +300,18 @@ func TestResourceConfigEqual_nil(t *testing.T) {
}
func TestResourceConfigEqual_computedKeyOrder(t *testing.T) {
c := map[string]interface{}{"foo": "${a.b.c}"}
rc := NewResourceConfig(config.TestRawConfig(t, c))
rc2 := NewResourceConfig(config.TestRawConfig(t, c))
v := cty.ObjectVal(map[string]cty.Value{
"foo": cty.UnknownVal(cty.String),
})
schema := &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
}
rc := NewResourceConfigShimmed(v, schema)
rc2 := NewResourceConfigShimmed(v, schema)
// Set the computed keys manual
// Set the computed keys manually to force ordering to differ
rc.ComputedKeys = []string{"foo", "bar"}
rc2.ComputedKeys = []string{"bar", "foo"}
@ -718,13 +334,13 @@ func TestUnknownCheckWalker(t *testing.T) {
{
"primitive computed",
unknownValue(),
hcl2shim.UnknownVariableValue,
true,
},
{
"list",
[]interface{}{"foo", unknownValue()},
[]interface{}{"foo", hcl2shim.UnknownVariableValue},
true,
},
@ -732,7 +348,7 @@ func TestUnknownCheckWalker(t *testing.T) {
"nested list",
[]interface{}{
"foo",
[]interface{}{unknownValue()},
[]interface{}{hcl2shim.UnknownVariableValue},
},
true,
},
@ -752,16 +368,6 @@ func TestUnknownCheckWalker(t *testing.T) {
}
}
func testResourceConfig(
t *testing.T, c map[string]interface{}) *ResourceConfig {
raw, err := config.NewRawConfig(c)
if err != nil {
t.Fatalf("err: %s", err)
}
return NewResourceConfig(raw)
}
func TestNewResourceConfigShimmed(t *testing.T) {
for _, tc := range []struct {
Name string