diff --git a/terraform/eval_variable.go b/terraform/eval_variable.go index ce6064706..47bd2ea2b 100644 --- a/terraform/eval_variable.go +++ b/terraform/eval_variable.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "reflect" + "strconv" "strings" "github.com/hashicorp/terraform/config" @@ -143,15 +144,60 @@ func (n *EvalVariableBlock) Eval(ctx EvalContext) (interface{}, error) { return nil, fmt.Errorf("Variable value for %s is not a string, list or map type", k) } - for k, _ := range rc.Raw { - if _, ok := n.VariableValues[k]; !ok { - n.VariableValues[k] = config.UnknownVariableValue + + for _, path := range rc.ComputedKeys { + log.Printf("[DEBUG] Setting Unknown Variable Value for computed key: %s", path) + err := n.setUnknownVariableValueForPath(path) + if err != nil { + return nil, err } } return nil, nil } +func (n *EvalVariableBlock) setUnknownVariableValueForPath(path string) error { + pathComponents := strings.Split(path, ".") + + if len(pathComponents) < 1 { + return fmt.Errorf("No path comoponents in %s", path) + } + + if len(pathComponents) == 1 { + // Special case the "top level" since we know the type + if _, ok := n.VariableValues[pathComponents[0]]; !ok { + n.VariableValues[pathComponents[0]] = config.UnknownVariableValue + } + return nil + } + + // Otherwise find the correct point in the tree and then set to unknown + var current interface{} = n.VariableValues[pathComponents[0]] + for i := 1; i < len(pathComponents); i++ { + switch current.(type) { + case []interface{}, []map[string]interface{}: + tCurrent := current.([]interface{}) + index, err := strconv.Atoi(pathComponents[i]) + if err != nil { + return fmt.Errorf("Cannot convert %s to slice index in path %s", + pathComponents[i], path) + } + current = tCurrent[index] + case map[string]interface{}: + tCurrent := current.(map[string]interface{}) + if val, hasVal := tCurrent[pathComponents[i]]; hasVal { + current = val + continue + } + + tCurrent[pathComponents[i]] = config.UnknownVariableValue + break + } + } + + return nil +} + // EvalCoerceMapVariable is an EvalNode implementation that recognizes a // specific ambiguous HCL parsing situation and resolves it. In HCL parsing, a // bare map literal is indistinguishable from a list of maps w/ one element.