terraform: don't prune, but disable, inherited configs [GH-1447]

This commit is contained in:
Mitchell Hashimoto 2015-04-09 08:48:08 -07:00
parent 4363ac4970
commit bcff7e070c
9 changed files with 115 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) {
p := testProvider("aws")
m := testModule(t, "validate-good")

View File

@ -33,6 +33,7 @@ type EvalContext interface {
// is used to store the provider configuration for inheritance lookups
// with ParentProviderConfig().
ConfigureProvider(string, *ResourceConfig) error
SetProviderConfig(string, *ResourceConfig) error
ParentProviderConfig(string) *ResourceConfig
// 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)
}
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)
copy(providerPath, ctx.Path())
providerPath[len(providerPath)-1] = n
@ -115,7 +124,7 @@ func (ctx *BuiltinEvalContext) ConfigureProvider(
ctx.ProviderConfigCache[PathCacheKey(providerPath)] = cfg
ctx.ProviderLock.Unlock()
return p.Configure(cfg)
return nil
}
func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} {

View File

@ -38,6 +38,10 @@ type MockEvalContext struct {
ConfigureProviderConfig *ResourceConfig
ConfigureProviderError error
SetProviderConfigCalled bool
SetProviderConfigName string
SetProviderConfigConfig *ResourceConfig
ParentProviderConfigCalled bool
ParentProviderConfigName string
ParentProviderConfigConfig *ResourceConfig
@ -107,6 +111,14 @@ func (c *MockEvalContext) ConfigureProvider(n string, cfg *ResourceConfig) error
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 {
c.ParentProviderConfigCalled = true
c.ParentProviderConfigName = n

View File

@ -6,6 +6,17 @@ import (
"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
// merged with parents and inputs on top of what is configured in the file.
type EvalBuildProviderConfig struct {

View File

@ -209,6 +209,11 @@ func (n *GraphNodeConfigProvider) ProviderName() string {
return n.Provider.Name
}
// GraphNodeProvider implementation
func (n *GraphNodeConfigProvider) ProviderConfig() *config.RawConfig {
return n.Provider.RawConfig
}
// GraphNodeDotter impl.
func (n *GraphNodeConfigProvider) Dot(name string) string {
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"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/dag"
)
@ -12,6 +13,7 @@ import (
// they satisfy.
type GraphNodeProvider interface {
ProviderName() string
ProviderConfig() *config.RawConfig
}
// GraphNodeProviderConsumer is an interface that nodes that require
@ -28,7 +30,8 @@ type DisableProviderTransformer struct{}
func (t *DisableProviderTransformer) Transform(g *Graph) error {
for _, v := range g.Vertices() {
// We only care about providers
if _, ok := v.(GraphNodeProvider); !ok {
pn, ok := v.(GraphNodeProvider)
if !ok {
continue
}
@ -54,8 +57,13 @@ func (t *DisableProviderTransformer) Transform(g *Graph) error {
continue
}
// Disable the provider by removing it from the graph.
g.Remove(v)
// Disable the provider by replacing it with a "disabled" provider
disabled := &graphNodeDisabledProvider{GraphNodeProvider: pn}
if !g.Replace(v, disabled) {
panic(fmt.Sprintf(
"vertex disappeared from under us: %s",
dag.VertexName(v)))
}
}
return nil
@ -134,6 +142,36 @@ func (t *PruneProviderTransformer) Transform(g *Graph) error {
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,
},
},
},
}
}
type graphNodeMissingProvider struct {
ProviderNameValue string
}
@ -151,6 +189,10 @@ func (n *graphNodeMissingProvider) ProviderName() string {
return n.ProviderNameValue
}
func (n *graphNodeMissingProvider) ProviderConfig() *config.RawConfig {
return nil
}
// GraphNodeDotter impl.
func (n *graphNodeMissingProvider) Dot(name string) string {
return fmt.Sprintf(