diff --git a/terraform/diff.go b/terraform/diff.go index d11440c4c..dbc310ea1 100644 --- a/terraform/diff.go +++ b/terraform/diff.go @@ -99,7 +99,11 @@ func (d *Diff) String() string { rdiff := d.Resources[name] crud := "UPDATE" - if rdiff.RequiresNew() { + if rdiff.RequiresNew() && rdiff.Destroy { + crud = "DESTROY/CREATE" + } else if rdiff.Destroy { + crud = "DESTROY" + } else if rdiff.RequiresNew() { crud = "CREATE" } @@ -179,7 +183,7 @@ func (d *ResourceDiff) Empty() bool { return true } - return len(d.Attributes) == 0 + return !d.Destroy && len(d.Attributes) == 0 } // RequiresNew returns true if the diff requires the creation of a new diff --git a/terraform/terraform.go b/terraform/terraform.go index c3b159dec..fdebe4f5a 100644 --- a/terraform/terraform.go +++ b/terraform/terraform.go @@ -225,10 +225,18 @@ func (t *Terraform) planWalkFn( result.init() cb := func(r *Resource) (map[string]string, error) { - // Get a diff from the newest state - diff, err := r.Provider.Diff(r.State, r.Config) - if err != nil { - return nil, err + var diff *ResourceDiff + + if r.Config == nil { + // This is an orphan (no config), so we mark it to be destroyed + diff = &ResourceDiff{Destroy: true} + } else { + // Get a diff from the newest state + var err error + diff, err = r.Provider.Diff(r.State, r.Config) + if err != nil { + return nil, err + } } l.Lock() @@ -304,7 +312,7 @@ func (t *Terraform) genericWalkFn( } // Make sure that at least some resource configuration is set - if rn.Resource.Config == nil { + if rn.Resource.Config == nil && !rn.Orphan { if rn.Config == nil { rn.Resource.Config = new(ResourceConfig) } else { diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 110777eae..98ee04354 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -161,6 +161,31 @@ func TestTerraformPlan_computed(t *testing.T) { } } +func TestTerraformPlan_orphan(t *testing.T) { + c := testConfig(t, "plan-orphan") + tf := testTerraform2(t, nil) + + s := &State{ + Resources: map[string]*ResourceState{ + "aws_instance.baz": &ResourceState{ + ID: "bar", + Type: "aws_instance", + }, + }, + } + + plan, err := tf.Plan(c, s, nil) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(plan.String()) + expected := strings.TrimSpace(testTerraformPlanOrphanStr) + if actual != expected { + t.Fatalf("bad:\n%s", actual) + } +} + func TestTerraformPlan_state(t *testing.T) { c := testConfig(t, "plan-good") tf := testTerraform2(t, nil) @@ -495,6 +520,20 @@ STATE: ` +const testTerraformPlanOrphanStr = ` +DIFF: + +DESTROY: aws_instance.baz +UPDATE: aws_instance.foo + num: "" => "2" + type: "" => "aws_instance" + +STATE: + +aws_instance.baz: + ID = bar +` + const testTerraformPlanStateStr = ` DIFF: diff --git a/terraform/test-fixtures/plan-orphan/main.tf b/terraform/test-fixtures/plan-orphan/main.tf new file mode 100644 index 000000000..cccf922e8 --- /dev/null +++ b/terraform/test-fixtures/plan-orphan/main.tf @@ -0,0 +1,3 @@ +resource "aws_instance" "foo" { + num = "2" +}