terraform: taint plan requires destroy/create

This commit is contained in:
Mitchell Hashimoto 2014-07-22 10:30:42 -07:00
parent 192fc1e544
commit 14f7067b0c
6 changed files with 81 additions and 4 deletions

View File

@ -681,7 +681,13 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc {
// Get a diff from the newest state
log.Printf("[DEBUG] %s: Executing diff", r.Id)
var err error
diff, err = r.Provider.Diff(r.State, r.Config)
state := r.State
if r.Tainted {
// If we're tainted, we pretend to create a new thing.
state = new(ResourceState)
state.Type = r.State.Type
}
diff, err = r.Provider.Diff(state, r.Config)
if err != nil {
return err
}
@ -691,6 +697,11 @@ func (c *Context) planWalkFn(result *Plan) depgraph.WalkFunc {
diff = new(ResourceDiff)
}
if r.Tainted {
// Tainted resources must also be destroyed
diff.Destroy = true
}
if diff.RequiresNew() && r.State.ID != "" {
// This will also require a destroy
diff.Destroy = true

View File

@ -1457,6 +1457,44 @@ func TestContextPlan_state(t *testing.T) {
}
}
func TestContextPlan_taint(t *testing.T) {
c := testConfig(t, "plan-taint")
p := testProvider("aws")
p.DiffFn = testDiffFn
s := &State{
Resources: map[string]*ResourceState{
"aws_instance.foo": &ResourceState{
ID: "bar",
Type: "aws_instance",
Attributes: map[string]string{"num": "2"},
},
"aws_instance.bar": &ResourceState{
ID: "baz",
Type: "aws_instance",
},
},
Tainted: map[string]struct{}{"aws_instance.bar": struct{}{}},
}
ctx := testContext(t, &ContextOpts{
Config: c,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
State: s,
})
plan, err := ctx.Plan(nil)
if err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(plan.String())
expected := strings.TrimSpace(testTerraformPlanTaintStr)
if actual != expected {
t.Fatalf("bad:\n%s", actual)
}
}
func TestContextRefresh(t *testing.T) {
p := testProvider("aws")
c := testConfig(t, "refresh-basic")

View File

@ -178,6 +178,9 @@ func graphAddConfigResources(
index = i
}
// Determine if this resource is tainted
_, tainted := s.Tainted[r.Id()]
var state *ResourceState
if s != nil {
state = s.Resources[name]
@ -209,9 +212,10 @@ func graphAddConfigResources(
Type: r.Type,
Config: r,
Resource: &Resource{
Id: name,
State: state,
Config: NewResourceConfig(r.RawConfig),
Id: name,
State: state,
Config: NewResourceConfig(r.RawConfig),
Tainted: tainted,
},
},
}

View File

@ -31,6 +31,7 @@ type Resource struct {
Provider ResourceProvider
State *ResourceState
Provisioners []*ResourceProvisionerConfig
Tainted bool
}
// Vars returns the mapping of variables that should be replaced in

View File

@ -411,3 +411,19 @@ STATE:
aws_instance.foo:
ID = bar
`
const testTerraformPlanTaintStr = `
DIFF:
DESTROY: aws_instance.bar
foo: "" => "2"
type: "" => "aws_instance"
STATE:
aws_instance.bar: (tainted)
ID = baz
aws_instance.foo:
ID = bar
num = 2
`

View File

@ -0,0 +1,7 @@
resource "aws_instance" "foo" {
num = "2"
}
resource "aws_instance" "bar" {
foo = "${aws_instance.foo.num}"
}