diff --git a/terraform/context_test.go b/terraform/context_test.go index 659ce2a6dd..76e03df819 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -80,7 +80,7 @@ func TestContext2Validate_orphans(t *testing.T) { t.Fatalf("bad: %#v", w) } if len(e) > 0 { - t.Fatalf("bad: %#v", e) + t.Fatalf("bad: %s", e) } } diff --git a/terraform/eval_sequence.go b/terraform/eval_sequence.go new file mode 100644 index 0000000000..e475e6bddf --- /dev/null +++ b/terraform/eval_sequence.go @@ -0,0 +1,33 @@ +package terraform + +// EvalSequence is an EvalNode that evaluates in sequence. +type EvalSequence struct { + Nodes []EvalNode +} + +func (n *EvalSequence) Args() ([]EvalNode, []EvalType) { + types := make([]EvalType, len(n.Nodes)) + for i, n := range n.Nodes { + types[i] = n.Type() + } + + return n.Nodes, types +} + +func (n *EvalSequence) Eval( + ctx EvalContext, args []interface{}) (interface{}, error) { + // TODO: test + if len(args) == 0 { + return nil, nil + } + + return args[len(args)-1], nil +} + +func (n *EvalSequence) Type() EvalType { + if len(n.Nodes) == 0 { + return EvalTypeNull + } + + return n.Nodes[len(n.Nodes)-1].Type() +} diff --git a/terraform/eval_validate.go b/terraform/eval_validate.go index 7a729f23eb..9b7fac0daf 100644 --- a/terraform/eval_validate.go +++ b/terraform/eval_validate.go @@ -15,17 +15,48 @@ func (e *EvalValidateError) Error() string { return "" } +// EvalValidateProvider is an EvalNode implementation that validates +// the configuration of a resource. +type EvalValidateProvider struct { + Provider EvalNode + Config EvalNode +} + +func (n *EvalValidateProvider) Args() ([]EvalNode, []EvalType) { + return []EvalNode{n.Provider, n.Config}, + []EvalType{EvalTypeResourceProvider, EvalTypeConfig} +} + +func (n *EvalValidateProvider) Eval( + ctx EvalContext, args []interface{}) (interface{}, error) { + provider := args[0].(ResourceProvider) + config := args[1].(*ResourceConfig) + warns, errs := provider.Validate(config) + if len(warns) == 0 && len(errs) == 0 { + return nil, nil + } + + return nil, &EvalValidateError{ + Warnings: warns, + Errors: errs, + } +} + +func (n *EvalValidateProvider) Type() EvalType { + return EvalTypeNull +} + // EvalValidateResource is an EvalNode implementation that validates // the configuration of a resource. type EvalValidateResource struct { Provider EvalNode - Config *config.RawConfig + Config EvalNode ProviderType string } func (n *EvalValidateResource) Args() ([]EvalNode, []EvalType) { - return []EvalNode{n.Provider}, - []EvalType{EvalTypeResourceProvider} + return []EvalNode{n.Provider, n.Config}, + []EvalType{EvalTypeResourceProvider, EvalTypeConfig} } func (n *EvalValidateResource) Eval( diff --git a/terraform/graph_config_node.go b/terraform/graph_config_node.go index 887fc16822..e5be6cfbb8 100644 --- a/terraform/graph_config_node.go +++ b/terraform/graph_config_node.go @@ -75,9 +75,18 @@ func (n *GraphNodeConfigProvider) DependentOn() []string { // GraphNodeEvalable impl. func (n *GraphNodeConfigProvider) EvalTree() EvalNode { - return &EvalConfigProvider{ - Provider: &EvalGetProvider{Name: n.Provider.Name}, - Config: &EvalInterpolate{Config: n.Provider.RawConfig}, + return &EvalSequence{ + Nodes: []EvalNode{ + &EvalInitProvider{Name: n.Provider.Name}, + &EvalValidateProvider{ + Provider: &EvalGetProvider{Name: n.Provider.Name}, + Config: &EvalInterpolate{Config: n.Provider.RawConfig}, + }, + &EvalConfigProvider{ + Provider: &EvalGetProvider{Name: n.Provider.Name}, + Config: &EvalInterpolate{Config: n.Provider.RawConfig}, + }, + }, } } @@ -121,11 +130,14 @@ func (n *GraphNodeConfigResource) Name() string { // GraphNodeEvalable impl. func (n *GraphNodeConfigResource) EvalTree() EvalNode { - return &EvalValidateResource{ - Provider: &EvalGetProvider{Name: n.ProvidedBy()}, - - Config: n.Resource.RawConfig, - ProviderType: n.ProvidedBy(), + return &EvalSequence{ + Nodes: []EvalNode{ + &EvalValidateResource{ + Provider: &EvalGetProvider{Name: n.ProvidedBy()}, + Config: n.Resource.RawConfig, + ProviderType: n.ProvidedBy(), + }, + }, } }