config: substring containing computed value replaces element

This commit is contained in:
Mitchell Hashimoto 2015-02-27 21:51:14 -08:00
parent abd68c2c87
commit 2feaebdca5
4 changed files with 184 additions and 15 deletions

View File

@ -152,12 +152,12 @@ func (w *interpolationWalker) Primitive(v reflect.Value) error {
if w.loc == reflectwalk.SliceElem {
parts := strings.Split(replaceVal, InterpSplitDelim)
for _, p := range parts {
if p == UnknownVariableValue {
if strings.Contains(p, UnknownVariableValue) {
remove = true
break
}
}
} else if replaceVal == UnknownVariableValue {
} else if strings.Contains(replaceVal, UnknownVariableValue) {
remove = true
}
if remove {

View File

@ -5,6 +5,7 @@ import (
"reflect"
"testing"
"github.com/hashicorp/terraform/config/lang"
"github.com/hashicorp/terraform/config/lang/ast"
"github.com/mitchellh/reflectwalk"
)
@ -124,7 +125,7 @@ func TestInterpolationWalker_replace(t *testing.T) {
"foo": "hello, ${var.foo}",
},
Output: map[string]interface{}{
"foo": "bar",
"foo": "hello, bar",
},
Value: "bar",
},
@ -170,11 +171,38 @@ func TestInterpolationWalker_replace(t *testing.T) {
Output: map[string]interface{}{},
Value: UnknownVariableValue + InterpSplitDelim + "baz",
},
{
Input: map[string]interface{}{
"foo": []interface{}{
"${var.foo}/32",
"bing",
},
},
Output: map[string]interface{}{},
Value: UnknownVariableValue,
},
}
for i, tc := range cases {
fn := func(ast.Node) (string, error) {
return tc.Value, nil
config := &lang.EvalConfig{
GlobalScope: &ast.BasicScope{
VarMap: map[string]ast.Variable{
"var.foo": ast.Variable{
Value: tc.Value,
Type: ast.TypeString,
},
},
},
}
fn := func(root ast.Node) (string, error) {
value, _, err := lang.Eval(root, config)
if err != nil {
return "", err
}
return value.(string), nil
}
w := &interpolationWalker{F: fn, Replace: true}

View File

@ -5,6 +5,8 @@ import (
"testing"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/lang/ast"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/terraform"
)
@ -48,16 +50,6 @@ func TestConfigFieldReader(t *testing.T) {
})
}
func testConfig(
t *testing.T, raw map[string]interface{}) *terraform.ResourceConfig {
rc, err := config.NewRawConfig(raw)
if err != nil {
t.Fatalf("err: %s", err)
}
return terraform.NewResourceConfig(rc)
}
func TestConfigFieldReader_DefaultHandling(t *testing.T) {
schema := map[string]*Schema{
"strWithDefault": &Schema{
@ -142,3 +134,116 @@ func TestConfigFieldReader_DefaultHandling(t *testing.T) {
}
}
}
func TestConfigFieldReader_ComputedSet(t *testing.T) {
schema := map[string]*Schema{
"strSet": &Schema{
Type: TypeSet,
Elem: &Schema{Type: TypeString},
Set: func(v interface{}) int {
return hashcode.String(v.(string))
},
},
}
cases := map[string]struct {
Addr []string
Result FieldReadResult
Config *terraform.ResourceConfig
Err bool
}{
"set, normal": {
[]string{"strSet"},
FieldReadResult{
Value: map[int]interface{}{
2356372769: "foo",
},
Exists: true,
Computed: false,
},
testConfig(t, map[string]interface{}{
"strSet": []interface{}{"foo"},
}),
false,
},
"set, computed element": {
[]string{"strSet"},
FieldReadResult{
Value: nil,
Exists: true,
Computed: true,
},
testConfigInterpolate(t, map[string]interface{}{
"strSet": []interface{}{"${var.foo}"},
}, map[string]ast.Variable{
"var.foo": ast.Variable{
Value: config.UnknownVariableValue,
Type: ast.TypeString,
},
}),
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: config.UnknownVariableValue,
Type: ast.TypeString,
},
}),
false,
},
}
for name, tc := range cases {
r := &ConfigFieldReader{
Schema: schema,
Config: tc.Config,
}
out, err := r.ReadField(tc.Addr)
if (err != nil) != tc.Err {
t.Fatalf("%s: err: %s", name, err)
}
if s, ok := out.Value.(*Set); ok {
// If it is a set, convert to the raw map
out.Value = s.m
if len(s.m) == 0 {
out.Value = nil
}
}
if !reflect.DeepEqual(tc.Result, out) {
t.Fatalf("%s: bad: %#v", name, out)
}
}
}
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)
}

View File

@ -2165,6 +2165,42 @@ func TestSchemaMap_Diff(t *testing.T) {
Err: false,
},
// #56 - 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]string{
"var.foo": config.UnknownVariableValue,
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"ports.#": &terraform.ResourceAttrDiff{
Old: "",
New: "",
NewComputed: true,
},
},
},
Err: false,
},
}
for i, tc := range cases {