Skip to content

Commit

Permalink
backend/local: Avoid rendering data sources on destroy
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Dec 12, 2018
1 parent 7d184cb commit 13f6c50
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 1 deletion.
9 changes: 8 additions & 1 deletion backend/local/backend_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"sort"
"strings"

"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/backend"
"github.com/hashicorp/terraform/command/format"
"github.com/hashicorp/terraform/plans"
Expand Down Expand Up @@ -189,7 +190,14 @@ func (b *Local) opPlan(

func (b *Local) renderPlan(plan *plans.Plan, schemas *terraform.Schemas) {
counts := map[plans.Action]int{}
var rChanges []*plans.ResourceInstanceChangeSrc
for _, change := range plan.Changes.Resources {
if change.Action == plans.Delete && change.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
// Avoid rendering data sources on deletion
continue
}

rChanges = append(rChanges, change)
counts[change.Action]++
}

Expand Down Expand Up @@ -225,7 +233,6 @@ func (b *Local) renderPlan(plan *plans.Plan, schemas *terraform.Schemas) {
// here. The ordering of resource changes in a plan is not significant,
// but we can only do this safely here because we can assume that nobody
// is concurrently modifying our changes while we're trying to print it.
rChanges := plan.Changes.Resources
sort.Slice(rChanges, func(i, j int) bool {
iA := rChanges[i].Addr
jA := rChanges[j].Addr
Expand Down
131 changes: 131 additions & 0 deletions backend/local/backend_plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,88 @@ func TestLocal_planDestroy(t *testing.T) {
}
}

func TestLocal_planDestroy_withDataSources(t *testing.T) {
b, cleanup := TestLocal(t)
defer cleanup()

p := TestLocalProvider(t, b, "test", planFixtureSchema())
testStateFile(t, b.StatePath, testPlanState_withDataSource())

b.CLI = cli.NewMockUi()

outDir := testTempDir(t)
defer os.RemoveAll(outDir)
planPath := filepath.Join(outDir, "plan.tfplan")

op, configCleanup := testOperationPlan(t, "./test-fixtures/destroy-with-ds")
defer configCleanup()
op.Destroy = true
op.PlanRefresh = true
op.PlanOutPath = planPath
cfg := cty.ObjectVal(map[string]cty.Value{
"path": cty.StringVal(b.StatePath),
})
cfgRaw, err := plans.NewDynamicValue(cfg, cfg.Type())
if err != nil {
t.Fatal(err)
}
op.PlanOutBackend = &plans.Backend{
// Just a placeholder so that we can generate a valid plan file.
Type: "local",
Config: cfgRaw,
}

run, err := b.Operation(context.Background(), op)
if err != nil {
t.Fatalf("bad: %s", err)
}
<-run.Done()
if run.Result != backend.OperationSuccess {
t.Fatalf("plan operation failed")
}

if !p.ReadResourceCalled {
t.Fatal("ReadResource should be called")
}

if run.PlanEmpty {
t.Fatal("plan should not be empty")
}

plan := testReadPlan(t, planPath)
if len(plan.Changes.Resources) != 2 {
t.Fatalf("Expected exactly 1 resource for destruction, %d given: %q",
len(plan.Changes.Resources), getAddrs(plan.Changes.Resources))
}

expectedOutput := `Terraform will perform the following actions:
# test_instance.foo will be destroyed
- resource "test_instance" "foo" {
- ami = "bar" -> null
- network_interface {
- description = "Main network interface" -> null
- device_index = 0 -> null
}
}
Plan: 0 to add, 0 to change, 1 to destroy.`

output := b.CLI.(*cli.MockUi).OutputWriter.String()
if !strings.Contains(output, expectedOutput) {
t.Fatalf("Unexpected output (expected no data source):\n%s", output)
}
}

func getAddrs(resources []*plans.ResourceInstanceChangeSrc) []string {
addrs := make([]string, len(resources), len(resources))
for i, r := range resources {
addrs[i] = r.Addr.String()
}
return addrs
}

func TestLocal_planOutPathNoChange(t *testing.T) {
b, cleanup := TestLocal(t)
defer cleanup()
Expand Down Expand Up @@ -336,6 +418,48 @@ func testPlanState() *states.State {
return state
}

func testPlanState_withDataSource() *states.State {
state := states.NewState()
rootModule := state.RootModule()
rootModule.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_instance",
Name: "foo",
}.Instance(addrs.IntKey(0)),
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{
"ami": "bar",
"network_interface": [{
"device_index": 0,
"description": "Main network interface"
}]
}`),
},
addrs.ProviderConfig{
Type: "test",
}.Absolute(addrs.RootModuleInstance),
)
rootModule.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.DataResourceMode,
Type: "test_ds",
Name: "bar",
}.Instance(addrs.IntKey(0)),
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{
"filter": "foo"
}`),
},
addrs.ProviderConfig{
Type: "test",
}.Absolute(addrs.RootModuleInstance),
)
return state
}

func testReadPlan(t *testing.T, path string) *plans.Plan {
t.Helper()

Expand Down Expand Up @@ -376,5 +500,12 @@ func planFixtureSchema() *terraform.ProviderSchema {
},
},
},
DataSources: map[string]*configschema.Block{
"test_ds": {
Attributes: map[string]*configschema.Attribute{
"filter": {Type: cty.String, Required: true},
},
},
},
}
}
7 changes: 7 additions & 0 deletions backend/local/test-fixtures/destroy-with-ds/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
resource "test_instance" "foo" {
ami = "bar"
}

data "test_ds" "bar" {
filter = "foo"
}
3 changes: 3 additions & 0 deletions backend/local/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ func TestLocalProvider(t *testing.T, b *Local, name string, schema *terraform.Pr
p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
return providers.ReadResourceResponse{NewState: req.PriorState}
}
p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
return providers.ReadDataSourceResponse{State: req.Config}
}

// Initialize the opts
if b.ContextOpts == nil {
Expand Down

0 comments on commit 13f6c50

Please sign in to comment.