From 2680b6bed4c146dbf177c9ce28f6de5a0c51eba8 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 11 Feb 2015 14:14:05 -0800 Subject: [PATCH] terraform: refresh tainted resources --- terraform/context_test.go | 6 +++--- terraform/eval_state.go | 25 +++++++++++++++++++----- terraform/transform_resource.go | 8 ++++---- terraform/transform_tainted.go | 34 +++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/terraform/context_test.go b/terraform/context_test.go index 5e0938ea4..c161f7248 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -365,8 +365,7 @@ func TestContext2Refresh_state(t *testing.T) { } } -/* -func TestContextRefresh_tainted(t *testing.T) { +func TestContext2Refresh_tainted(t *testing.T) { p := testProvider("aws") m := testModule(t, "refresh-basic") state := &State{ @@ -386,7 +385,7 @@ func TestContextRefresh_tainted(t *testing.T) { }, }, } - ctx := testContext(t, &ContextOpts{ + ctx := testContext2(t, &ContextOpts{ Module: m, Providers: map[string]ResourceProviderFactory{ "aws": testProviderFuncFixed(p), @@ -414,6 +413,7 @@ func TestContextRefresh_tainted(t *testing.T) { } } +/* func TestContextRefresh_vars(t *testing.T) { p := testProvider("aws") m := testModule(t, "refresh-vars") diff --git a/terraform/eval_state.go b/terraform/eval_state.go index 6a7f98840..92d612777 100644 --- a/terraform/eval_state.go +++ b/terraform/eval_state.go @@ -7,7 +7,9 @@ import ( // EvalReadState is an EvalNode implementation that reads the // InstanceState for a specific resource out of the state. type EvalReadState struct { - Name string + Name string + Tainted bool + TaintedIndex int } func (n *EvalReadState) Args() ([]EvalNode, []EvalType) { @@ -35,8 +37,13 @@ func (n *EvalReadState) Eval( return nil, nil } - // Return the primary - return rs.Primary, nil + if !n.Tainted { + // Return the primary + return rs.Primary, nil + } else { + // Return the proper tainted resource + return rs.Tainted[n.TaintedIndex], nil + } } func (n *EvalReadState) Type() EvalType { @@ -50,6 +57,8 @@ type EvalWriteState struct { ResourceType string Dependencies []string State EvalNode + Tainted bool + TaintedIndex int } func (n *EvalWriteState) Args() ([]EvalNode, []EvalType) { @@ -89,8 +98,14 @@ func (n *EvalWriteState) Eval( rs.Type = n.ResourceType rs.Dependencies = n.Dependencies - // Set the primary state - rs.Primary = instanceState + if n.Tainted { + if n.TaintedIndex != -1 { + rs.Tainted[n.TaintedIndex] = instanceState + } + } else { + // Set the primary state + rs.Primary = instanceState + } // Prune because why not, we can clear out old useless entries now rs.prune() diff --git a/terraform/transform_resource.go b/terraform/transform_resource.go index 87b7bce87..3ab9afc69 100644 --- a/terraform/transform_resource.go +++ b/terraform/transform_resource.go @@ -72,8 +72,8 @@ func (n *graphNodeExpandedResource) DependentOn() []string { } // GraphNodeProviderConsumer -func (n *graphNodeExpandedResource) ProvidedBy() string { - return resourceProvider(n.Resource.Type) +func (n *graphNodeExpandedResource) ProvidedBy() []string { + return []string{resourceProvider(n.Resource.Type)} } // GraphNodeEvalable impl. @@ -82,7 +82,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode { // Validate the resource seq.Nodes = append(seq.Nodes, &EvalValidateResource{ - Provider: &EvalGetProvider{Name: n.ProvidedBy()}, + Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]}, Config: &EvalInterpolate{Config: n.Resource.RawConfig}, ResourceName: n.Resource.Name, ResourceType: n.Resource.Type, @@ -109,7 +109,7 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode { Dependencies: n.DependentOn(), State: &EvalRefresh{ Info: info, - Provider: &EvalGetProvider{Name: n.ProvidedBy()}, + Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]}, State: &EvalReadState{Name: n.stateId()}, }, }, diff --git a/terraform/transform_tainted.go b/terraform/transform_tainted.go index 7252328ad..1ae16558f 100644 --- a/terraform/transform_tainted.go +++ b/terraform/transform_tainted.go @@ -34,6 +34,7 @@ func (t *TaintedTransformer) Transform(g *Graph) error { g.ConnectFrom(k, g.Add(&graphNodeTaintedResource{ Index: i, ResourceName: k, + ResourceType: rs.Type, })) } } @@ -47,6 +48,7 @@ func (t *TaintedTransformer) Transform(g *Graph) error { type graphNodeTaintedResource struct { Index int ResourceName string + ResourceType string } func (n *graphNodeTaintedResource) DependentOn() []string { @@ -60,3 +62,35 @@ func (n *graphNodeTaintedResource) Name() string { func (n *graphNodeTaintedResource) ProvidedBy() []string { 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 +}