diff --git a/terraform/context_test.go b/terraform/context_test.go index c6dd83b94..abffbf5c3 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -2505,6 +2505,9 @@ func TestContext2Input_provider(t *testing.T) { actual = c.Config["foo"] return nil } + p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { + return nil, c.CheckSet([]string{"foo"}) + } if err := ctx.Input(InputModeStd); err != nil { t.Fatalf("err: %s", err) diff --git a/terraform/eval_provider.go b/terraform/eval_provider.go index f648fe46f..f8d61b1f1 100644 --- a/terraform/eval_provider.go +++ b/terraform/eval_provider.go @@ -6,17 +6,18 @@ import ( "github.com/hashicorp/terraform/config" ) -// EvalConfigProvider is an EvalNode implementation that configures -// a provider that is already initialized and retrieved. -type EvalConfigProvider struct { +// EvalBuildProviderConfig outputs a *ResourceConfig that is properly +// merged with parents and inputs on top of what is configured in the file. +type EvalBuildProviderConfig struct { Provider string Config **ResourceConfig + Output **ResourceConfig } -func (n *EvalConfigProvider) Eval(ctx EvalContext) (interface{}, error) { +func (n *EvalBuildProviderConfig) Eval(ctx EvalContext) (interface{}, error) { cfg := *n.Config - // If we have a configuration set, then use that + // If we have a configuration set, then merge that in if input := ctx.ProviderInput(n.Provider); input != nil { rc, err := config.NewRawConfig(input) if err != nil { @@ -33,7 +34,19 @@ func (n *EvalConfigProvider) Eval(ctx EvalContext) (interface{}, error) { cfg = NewResourceConfig(merged) } - return nil, ctx.ConfigureProvider(n.Provider, cfg) + *n.Output = cfg + return nil, nil +} + +// EvalConfigProvider is an EvalNode implementation that configures +// a provider that is already initialized and retrieved. +type EvalConfigProvider struct { + Provider string + Config **ResourceConfig +} + +func (n *EvalConfigProvider) Eval(ctx EvalContext) (interface{}, error) { + return nil, ctx.ConfigureProvider(n.Provider, *n.Config) } // EvalInitProvider is an EvalNode implementation that initializes a provider diff --git a/terraform/eval_provider_test.go b/terraform/eval_provider_test.go index 849e434a6..5d50d746b 100644 --- a/terraform/eval_provider_test.go +++ b/terraform/eval_provider_test.go @@ -5,6 +5,71 @@ import ( "testing" ) +func TestEvalBuildProviderConfig_impl(t *testing.T) { + var _ EvalNode = new(EvalBuildProviderConfig) +} + +func TestEvalBuildProviderConfig(t *testing.T) { + config := testResourceConfig(t, map[string]interface{}{}) + provider := "foo" + + n := &EvalBuildProviderConfig{ + Provider: provider, + Config: &config, + Output: &config, + } + + ctx := &MockEvalContext{ + ParentProviderConfigConfig: testResourceConfig(t, map[string]interface{}{ + "foo": "bar", + }), + ProviderInputConfig: map[string]interface{}{ + "bar": "baz", + }, + } + if _, err := n.Eval(ctx); err != nil { + t.Fatalf("err: %s", err) + } + + expected := map[string]interface{}{ + "foo": "bar", + "bar": "baz", + } + if !reflect.DeepEqual(config.Raw, expected) { + t.Fatalf("bad: %#v", config.Raw) + } +} + +func TestEvalBuildProviderConfig_parentPriority(t *testing.T) { + config := testResourceConfig(t, map[string]interface{}{}) + provider := "foo" + + n := &EvalBuildProviderConfig{ + Provider: provider, + Config: &config, + Output: &config, + } + + ctx := &MockEvalContext{ + ParentProviderConfigConfig: testResourceConfig(t, map[string]interface{}{ + "foo": "bar", + }), + ProviderInputConfig: map[string]interface{}{ + "foo": "baz", + }, + } + if _, err := n.Eval(ctx); err != nil { + t.Fatalf("err: %s", err) + } + + expected := map[string]interface{}{ + "foo": "bar", + } + if !reflect.DeepEqual(config.Raw, expected) { + t.Fatalf("bad: %#v", config.Raw) + } +} + func TestEvalConfigProvider_impl(t *testing.T) { var _ EvalNode = new(EvalConfigProvider) } diff --git a/terraform/eval_validate.go b/terraform/eval_validate.go index c6c1f20ba..e808240a0 100644 --- a/terraform/eval_validate.go +++ b/terraform/eval_validate.go @@ -57,21 +57,14 @@ RETURN: // EvalValidateProvider is an EvalNode implementation that validates // the configuration of a resource. type EvalValidateProvider struct { - ProviderName string - Provider *ResourceProvider - Config **ResourceConfig + Provider *ResourceProvider + Config **ResourceConfig } func (n *EvalValidateProvider) Eval(ctx EvalContext) (interface{}, error) { provider := *n.Provider config := *n.Config - // Get the parent configuration if there is one - if parent := ctx.ParentProviderConfig(n.ProviderName); parent != nil { - merged := parent.raw.Merge(config.raw) - config = NewResourceConfig(merged) - } - warns, errs := provider.Validate(config) if len(warns) == 0 && len(errs) == 0 { return nil, nil diff --git a/terraform/evaltree_provider.go b/terraform/evaltree_provider.go index 89937d562..e2f51f06b 100644 --- a/terraform/evaltree_provider.go +++ b/terraform/evaltree_provider.go @@ -44,10 +44,14 @@ func ProviderEvalTree(n string, config *config.RawConfig) EvalNode { Config: config, Output: &resourceConfig, }, + &EvalBuildProviderConfig{ + Provider: n, + Config: &resourceConfig, + Output: &resourceConfig, + }, &EvalValidateProvider{ - ProviderName: n, - Provider: &provider, - Config: &resourceConfig, + Provider: &provider, + Config: &resourceConfig, }, &EvalConfigProvider{ Provider: n,