Merge pull request #1452 from hashicorp/b-inherit-validate

terraform: don't prune, but disable, inherited configs [GH-1447]
This commit is contained in:
Mitchell Hashimoto 2015-04-09 09:03:11 -07:00
commit f0004186cf
10 changed files with 121 additions and 4 deletions

View File

@ -2258,6 +2258,29 @@ func TestContext2Validate_moduleProviderVar(t *testing.T) {
} }
} }
func TestContext2Validate_moduleProviderInheritUnused(t *testing.T) {
m := testModule(t, "validate-module-pc-inherit-unused")
p := testProvider("aws")
c := testContext2(t, &ContextOpts{
Module: m,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
})
p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
return nil, c.CheckSet([]string{"foo"})
}
w, e := c.Validate()
if len(w) > 0 {
t.Fatalf("bad: %#v", w)
}
if len(e) > 0 {
t.Fatalf("bad: %s", e)
}
}
func TestContext2Validate_orphans(t *testing.T) { func TestContext2Validate_orphans(t *testing.T) {
p := testProvider("aws") p := testProvider("aws")
m := testModule(t, "validate-good") m := testModule(t, "validate-good")

View File

@ -33,6 +33,7 @@ type EvalContext interface {
// is used to store the provider configuration for inheritance lookups // is used to store the provider configuration for inheritance lookups
// with ParentProviderConfig(). // with ParentProviderConfig().
ConfigureProvider(string, *ResourceConfig) error ConfigureProvider(string, *ResourceConfig) error
SetProviderConfig(string, *ResourceConfig) error
ParentProviderConfig(string) *ResourceConfig ParentProviderConfig(string) *ResourceConfig
// ProviderInput and SetProviderInput are used to configure providers // ProviderInput and SetProviderInput are used to configure providers

View File

@ -106,6 +106,15 @@ func (ctx *BuiltinEvalContext) ConfigureProvider(
return fmt.Errorf("Provider '%s' not initialized", n) return fmt.Errorf("Provider '%s' not initialized", n)
} }
if err := ctx.SetProviderConfig(n, cfg); err != nil {
return nil
}
return p.Configure(cfg)
}
func (ctx *BuiltinEvalContext) SetProviderConfig(
n string, cfg *ResourceConfig) error {
providerPath := make([]string, len(ctx.Path())+1) providerPath := make([]string, len(ctx.Path())+1)
copy(providerPath, ctx.Path()) copy(providerPath, ctx.Path())
providerPath[len(providerPath)-1] = n providerPath[len(providerPath)-1] = n
@ -115,7 +124,7 @@ func (ctx *BuiltinEvalContext) ConfigureProvider(
ctx.ProviderConfigCache[PathCacheKey(providerPath)] = cfg ctx.ProviderConfigCache[PathCacheKey(providerPath)] = cfg
ctx.ProviderLock.Unlock() ctx.ProviderLock.Unlock()
return p.Configure(cfg) return nil
} }
func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} { func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} {

View File

@ -38,6 +38,10 @@ type MockEvalContext struct {
ConfigureProviderConfig *ResourceConfig ConfigureProviderConfig *ResourceConfig
ConfigureProviderError error ConfigureProviderError error
SetProviderConfigCalled bool
SetProviderConfigName string
SetProviderConfigConfig *ResourceConfig
ParentProviderConfigCalled bool ParentProviderConfigCalled bool
ParentProviderConfigName string ParentProviderConfigName string
ParentProviderConfigConfig *ResourceConfig ParentProviderConfigConfig *ResourceConfig
@ -107,6 +111,14 @@ func (c *MockEvalContext) ConfigureProvider(n string, cfg *ResourceConfig) error
return c.ConfigureProviderError return c.ConfigureProviderError
} }
func (c *MockEvalContext) SetProviderConfig(
n string, cfg *ResourceConfig) error {
c.SetProviderConfigCalled = true
c.SetProviderConfigName = n
c.SetProviderConfigConfig = cfg
return nil
}
func (c *MockEvalContext) ParentProviderConfig(n string) *ResourceConfig { func (c *MockEvalContext) ParentProviderConfig(n string) *ResourceConfig {
c.ParentProviderConfigCalled = true c.ParentProviderConfigCalled = true
c.ParentProviderConfigName = n c.ParentProviderConfigName = n

View File

@ -6,6 +6,17 @@ import (
"github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config"
) )
// EvalSetProviderConfig sets the parent configuration for a provider
// without configuring that provider, validating it, etc.
type EvalSetProviderConfig struct {
Provider string
Config **ResourceConfig
}
func (n *EvalSetProviderConfig) Eval(ctx EvalContext) (interface{}, error) {
return nil, ctx.SetProviderConfig(n.Provider, *n.Config)
}
// EvalBuildProviderConfig outputs a *ResourceConfig that is properly // EvalBuildProviderConfig outputs a *ResourceConfig that is properly
// merged with parents and inputs on top of what is configured in the file. // merged with parents and inputs on top of what is configured in the file.
type EvalBuildProviderConfig struct { type EvalBuildProviderConfig struct {

View File

@ -209,6 +209,11 @@ func (n *GraphNodeConfigProvider) ProviderName() string {
return n.Provider.Name return n.Provider.Name
} }
// GraphNodeProvider implementation
func (n *GraphNodeConfigProvider) ProviderConfig() *config.RawConfig {
return n.Provider.RawConfig
}
// GraphNodeDotter impl. // GraphNodeDotter impl.
func (n *GraphNodeConfigProvider) Dot(name string) string { func (n *GraphNodeConfigProvider) Dot(name string) string {
return fmt.Sprintf( return fmt.Sprintf(

View File

@ -0,0 +1 @@
resource "aws_instance" "foo" {}

View File

@ -0,0 +1,7 @@
module "child" {
source = "./child"
}
provider "aws" {
foo = "set"
}

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/dag" "github.com/hashicorp/terraform/dag"
) )
@ -12,6 +13,7 @@ import (
// they satisfy. // they satisfy.
type GraphNodeProvider interface { type GraphNodeProvider interface {
ProviderName() string ProviderName() string
ProviderConfig() *config.RawConfig
} }
// GraphNodeProviderConsumer is an interface that nodes that require // GraphNodeProviderConsumer is an interface that nodes that require
@ -28,7 +30,8 @@ type DisableProviderTransformer struct{}
func (t *DisableProviderTransformer) Transform(g *Graph) error { func (t *DisableProviderTransformer) Transform(g *Graph) error {
for _, v := range g.Vertices() { for _, v := range g.Vertices() {
// We only care about providers // We only care about providers
if _, ok := v.(GraphNodeProvider); !ok { pn, ok := v.(GraphNodeProvider)
if !ok {
continue continue
} }
@ -54,8 +57,13 @@ func (t *DisableProviderTransformer) Transform(g *Graph) error {
continue continue
} }
// Disable the provider by removing it from the graph. // Disable the provider by replacing it with a "disabled" provider
g.Remove(v) disabled := &graphNodeDisabledProvider{GraphNodeProvider: pn}
if !g.Replace(v, disabled) {
panic(fmt.Sprintf(
"vertex disappeared from under us: %s",
dag.VertexName(v)))
}
} }
return nil return nil
@ -134,6 +142,40 @@ func (t *PruneProviderTransformer) Transform(g *Graph) error {
return nil return nil
} }
type graphNodeDisabledProvider struct {
GraphNodeProvider
}
// GraphNodeEvalable impl.
func (n *graphNodeDisabledProvider) EvalTree() EvalNode {
var resourceConfig *ResourceConfig
return &EvalOpFilter{
Ops: []walkOperation{walkValidate, walkRefresh, walkPlan, walkApply},
Node: &EvalSequence{
Nodes: []EvalNode{
&EvalInterpolate{
Config: n.ProviderConfig(),
Output: &resourceConfig,
},
&EvalBuildProviderConfig{
Provider: n.ProviderName(),
Config: &resourceConfig,
Output: &resourceConfig,
},
&EvalSetProviderConfig{
Provider: n.ProviderName(),
Config: &resourceConfig,
},
},
},
}
}
func (n *graphNodeDisabledProvider) Name() string {
return fmt.Sprintf("%s (disabled)", dag.VertexName(n.GraphNodeProvider))
}
type graphNodeMissingProvider struct { type graphNodeMissingProvider struct {
ProviderNameValue string ProviderNameValue string
} }
@ -151,6 +193,10 @@ func (n *graphNodeMissingProvider) ProviderName() string {
return n.ProviderNameValue return n.ProviderNameValue
} }
func (n *graphNodeMissingProvider) ProviderConfig() *config.RawConfig {
return nil
}
// GraphNodeDotter impl. // GraphNodeDotter impl.
func (n *graphNodeMissingProvider) Dot(name string) string { func (n *graphNodeMissingProvider) Dot(name string) string {
return fmt.Sprintf( return fmt.Sprintf(

View File

@ -217,6 +217,8 @@ provider.foo
const testTransformDisableProviderBasicStr = ` const testTransformDisableProviderBasicStr = `
module.child module.child
provider.aws (disabled)
provider.aws (disabled)
` `
const testTransformDisableProviderKeepStr = ` const testTransformDisableProviderKeepStr = `