filter unknowns from simple lists and maps in sdk

While there was already a check in the sdk to filter unknowns from
validation, it missed the case where those were in simple lists and maps.
This commit is contained in:
James Bardin 2019-05-24 16:13:29 -04:00
parent 2c176fdf4b
commit 6055cb632e
3 changed files with 67 additions and 4 deletions

View File

@ -3,6 +3,7 @@ package test
import ( import (
"fmt" "fmt"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
) )
@ -22,6 +23,15 @@ func testResourceMap() *schema.Resource {
Type: schema.TypeMap, Type: schema.TypeMap,
Optional: true, Optional: true,
Elem: &schema.Schema{Type: schema.TypeString}, Elem: &schema.Schema{Type: schema.TypeString},
ValidateFunc: func(v interface{}, _ string) ([]string, []error) {
errs := []error{}
for k, v := range v.(map[string]interface{}) {
if v == config.UnknownVariableValue {
errs = append(errs, fmt.Errorf("unknown value in ValidateFunc: %q=%q", k, v))
}
}
return nil, errs
},
}, },
"map_values": { "map_values": {
Type: schema.TypeMap, Type: schema.TypeMap,

View File

@ -31,6 +31,35 @@ resource "test_resource_map" "foobar" {
}) })
} }
func TestResourceMap_basicWithVars(t *testing.T) {
resource.UnitTest(t, resource.TestCase{
Providers: testAccProviders,
CheckDestroy: testAccCheckResourceDestroy,
Steps: []resource.TestStep{
{
Config: `
variable "a" {
default = "a"
}
variable "b" {
default = "b"
}
resource "test_resource_map" "foobar" {
name = "test"
map_of_three = {
one = var.a
two = var.b
empty = ""
}
}`,
Check: resource.ComposeTestCheckFunc(),
},
},
})
}
func TestResourceMap_computedMap(t *testing.T) { func TestResourceMap_computedMap(t *testing.T) {
resource.UnitTest(t, resource.TestCase{ resource.UnitTest(t, resource.TestCase{
Providers: testAccProviders, Providers: testAccProviders,

View File

@ -1365,10 +1365,12 @@ func (m schemaMap) validate(
"%q: this field cannot be set", k)} "%q: this field cannot be set", k)}
} }
if raw == config.UnknownVariableValue { // If the value is unknown then we can't validate it yet.
// If the value is unknown then we can't validate it yet. // In particular, this avoids spurious type errors where downstream
// In particular, this avoids spurious type errors where downstream // validation code sees UnknownVariableValue as being just a string.
// validation code sees UnknownVariableValue as being just a string. // The SDK has to allow the unknown value through initially, so that
// Required fields set via an interpolated value are accepted.
if !isWhollyKnown(raw) {
return nil, nil return nil, nil
} }
@ -1380,6 +1382,28 @@ func (m schemaMap) validate(
return m.validateType(k, raw, schema, c) return m.validateType(k, raw, schema, c)
} }
// isWhollyKnown returns false if the argument contains an UnknownVariableValue
func isWhollyKnown(raw interface{}) bool {
switch raw := raw.(type) {
case string:
if raw == config.UnknownVariableValue {
return false
}
case []interface{}:
for _, v := range raw {
if !isWhollyKnown(v) {
return false
}
}
case map[string]interface{}:
for _, v := range raw {
if !isWhollyKnown(v) {
return false
}
}
}
return true
}
func (m schemaMap) validateConflictingAttributes( func (m schemaMap) validateConflictingAttributes(
k string, k string,
schema *Schema, schema *Schema,