Skip to content

Commit

Permalink
Merge pull request #1307 from hashicorp/b-provider-config-merge
Browse files Browse the repository at this point in the history
terraform: merge provider configs before validate [GH-1282]
  • Loading branch information
mitchellh committed Mar 25, 2015
2 parents 8f11118 + a0839da commit 19c7f8c
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 18 deletions.
3 changes: 3 additions & 0 deletions terraform/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
25 changes: 19 additions & 6 deletions terraform/eval_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand Down
65 changes: 65 additions & 0 deletions terraform/eval_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
11 changes: 2 additions & 9 deletions terraform/eval_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions terraform/evaltree_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 19c7f8c

Please sign in to comment.