terraform: refresh tainted resources

This commit is contained in:
Mitchell Hashimoto 2015-02-11 14:14:05 -08:00
parent e5e4ac7548
commit 2680b6bed4
4 changed files with 61 additions and 12 deletions

View File

@ -365,8 +365,7 @@ func TestContext2Refresh_state(t *testing.T) {
} }
} }
/* func TestContext2Refresh_tainted(t *testing.T) {
func TestContextRefresh_tainted(t *testing.T) {
p := testProvider("aws") p := testProvider("aws")
m := testModule(t, "refresh-basic") m := testModule(t, "refresh-basic")
state := &State{ state := &State{
@ -386,7 +385,7 @@ func TestContextRefresh_tainted(t *testing.T) {
}, },
}, },
} }
ctx := testContext(t, &ContextOpts{ ctx := testContext2(t, &ContextOpts{
Module: m, Module: m,
Providers: map[string]ResourceProviderFactory{ Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p), "aws": testProviderFuncFixed(p),
@ -414,6 +413,7 @@ func TestContextRefresh_tainted(t *testing.T) {
} }
} }
/*
func TestContextRefresh_vars(t *testing.T) { func TestContextRefresh_vars(t *testing.T) {
p := testProvider("aws") p := testProvider("aws")
m := testModule(t, "refresh-vars") m := testModule(t, "refresh-vars")

View File

@ -8,6 +8,8 @@ import (
// InstanceState for a specific resource out of the state. // InstanceState for a specific resource out of the state.
type EvalReadState struct { type EvalReadState struct {
Name string Name string
Tainted bool
TaintedIndex int
} }
func (n *EvalReadState) Args() ([]EvalNode, []EvalType) { func (n *EvalReadState) Args() ([]EvalNode, []EvalType) {
@ -35,8 +37,13 @@ func (n *EvalReadState) Eval(
return nil, nil return nil, nil
} }
if !n.Tainted {
// Return the primary // Return the primary
return rs.Primary, nil return rs.Primary, nil
} else {
// Return the proper tainted resource
return rs.Tainted[n.TaintedIndex], nil
}
} }
func (n *EvalReadState) Type() EvalType { func (n *EvalReadState) Type() EvalType {
@ -50,6 +57,8 @@ type EvalWriteState struct {
ResourceType string ResourceType string
Dependencies []string Dependencies []string
State EvalNode State EvalNode
Tainted bool
TaintedIndex int
} }
func (n *EvalWriteState) Args() ([]EvalNode, []EvalType) { func (n *EvalWriteState) Args() ([]EvalNode, []EvalType) {
@ -89,8 +98,14 @@ func (n *EvalWriteState) Eval(
rs.Type = n.ResourceType rs.Type = n.ResourceType
rs.Dependencies = n.Dependencies rs.Dependencies = n.Dependencies
if n.Tainted {
if n.TaintedIndex != -1 {
rs.Tainted[n.TaintedIndex] = instanceState
}
} else {
// Set the primary state // Set the primary state
rs.Primary = instanceState rs.Primary = instanceState
}
// Prune because why not, we can clear out old useless entries now // Prune because why not, we can clear out old useless entries now
rs.prune() rs.prune()

View File

@ -72,8 +72,8 @@ func (n *graphNodeExpandedResource) DependentOn() []string {
} }
// GraphNodeProviderConsumer // GraphNodeProviderConsumer
func (n *graphNodeExpandedResource) ProvidedBy() string { func (n *graphNodeExpandedResource) ProvidedBy() []string {
return resourceProvider(n.Resource.Type) return []string{resourceProvider(n.Resource.Type)}
} }
// GraphNodeEvalable impl. // GraphNodeEvalable impl.
@ -82,7 +82,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
// Validate the resource // Validate the resource
seq.Nodes = append(seq.Nodes, &EvalValidateResource{ seq.Nodes = append(seq.Nodes, &EvalValidateResource{
Provider: &EvalGetProvider{Name: n.ProvidedBy()}, Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
Config: &EvalInterpolate{Config: n.Resource.RawConfig}, Config: &EvalInterpolate{Config: n.Resource.RawConfig},
ResourceName: n.Resource.Name, ResourceName: n.Resource.Name,
ResourceType: n.Resource.Type, ResourceType: n.Resource.Type,
@ -109,7 +109,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
Dependencies: n.DependentOn(), Dependencies: n.DependentOn(),
State: &EvalRefresh{ State: &EvalRefresh{
Info: info, Info: info,
Provider: &EvalGetProvider{Name: n.ProvidedBy()}, Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
State: &EvalReadState{Name: n.stateId()}, State: &EvalReadState{Name: n.stateId()},
}, },
}, },

View File

@ -34,6 +34,7 @@ func (t *TaintedTransformer) Transform(g *Graph) error {
g.ConnectFrom(k, g.Add(&graphNodeTaintedResource{ g.ConnectFrom(k, g.Add(&graphNodeTaintedResource{
Index: i, Index: i,
ResourceName: k, ResourceName: k,
ResourceType: rs.Type,
})) }))
} }
} }
@ -47,6 +48,7 @@ func (t *TaintedTransformer) Transform(g *Graph) error {
type graphNodeTaintedResource struct { type graphNodeTaintedResource struct {
Index int Index int
ResourceName string ResourceName string
ResourceType string
} }
func (n *graphNodeTaintedResource) DependentOn() []string { func (n *graphNodeTaintedResource) DependentOn() []string {
@ -60,3 +62,35 @@ func (n *graphNodeTaintedResource) Name() string {
func (n *graphNodeTaintedResource) ProvidedBy() []string { func (n *graphNodeTaintedResource) ProvidedBy() []string {
return []string{resourceProvider(n.ResourceName)} return []string{resourceProvider(n.ResourceName)}
} }
// GraphNodeEvalable impl.
func (n *graphNodeTaintedResource) EvalTree() EvalNode {
seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
// Build instance info
info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType}
seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info})
// Refresh the resource
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
Ops: []walkOperation{walkRefresh},
Node: &EvalWriteState{
Name: n.ResourceName,
ResourceType: n.ResourceType,
Dependencies: n.DependentOn(),
Tainted: true,
TaintedIndex: n.Index,
State: &EvalRefresh{
Info: info,
Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
State: &EvalReadState{
Name: n.ResourceName,
Tainted: true,
TaintedIndex: n.Index,
},
},
},
})
return seq
}