Merge pull request #11510 from hashicorp/b-plan-config

backend/local: validate module exists for plan
This commit is contained in:
Mitchell Hashimoto 2017-01-30 08:44:06 -08:00 committed by GitHub
commit 17cb8d8d8d
2 changed files with 89 additions and 0 deletions

View File

@ -10,6 +10,7 @@ import (
"github.com/hashicorp/errwrap" "github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/backend"
"github.com/hashicorp/terraform/command/format" "github.com/hashicorp/terraform/command/format"
"github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
) )
@ -28,6 +29,18 @@ func (b *Local) opPlan(
"directory as an argument.\n\n")) "directory as an argument.\n\n"))
} }
// A local plan requires either a plan or a module
if op.Plan == nil && op.Module == nil && !op.Destroy {
runningOp.Err = fmt.Errorf(strings.TrimSpace(planErrNoConfig))
return
}
// If we have a nil module at this point, then set it to an empty tree
// to avoid any potential crashes.
if op.Module == nil {
op.Module = module.NewEmptyTree()
}
// Setup our count hook that keeps track of resource changes // Setup our count hook that keeps track of resource changes
countHook := new(CountHook) countHook := new(CountHook)
if b.ContextOpts == nil { if b.ContextOpts == nil {
@ -120,6 +133,16 @@ func (b *Local) opPlan(
} }
} }
const planErrNoConfig = `
No configuration files found!
Plan requires configuration to be present. Planning without a configuration
would mark everything for destruction, which is normally not what is desired.
If you would like to destroy everything, please run plan with the "-destroy"
flag or create a single empty configuration file. Otherwise, please create
a Terraform configuration file in the path being executed and try again.
`
const planHeaderNoOutput = ` const planHeaderNoOutput = `
The Terraform execution plan has been generated and is shown below. The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources Resources are shown in alphabetical order for quick scanning. Green resources

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/backend"
@ -36,6 +37,29 @@ func TestLocal_planBasic(t *testing.T) {
} }
} }
func TestLocal_planNoConfig(t *testing.T) {
b := TestLocal(t)
TestLocalProvider(t, b, "test")
op := testOperationPlan()
op.Module = nil
op.PlanRefresh = true
run, err := b.Operation(context.Background(), op)
if err != nil {
t.Fatalf("bad: %s", err)
}
<-run.Done()
err = run.Err
if err == nil {
t.Fatal("should error")
}
if !strings.Contains(err.Error(), "configuration") {
t.Fatalf("bad: %s", err)
}
}
func TestLocal_planRefreshFalse(t *testing.T) { func TestLocal_planRefreshFalse(t *testing.T) {
b := TestLocal(t) b := TestLocal(t)
p := TestLocalProvider(t, b, "test") p := TestLocalProvider(t, b, "test")
@ -110,6 +134,48 @@ func TestLocal_planDestroy(t *testing.T) {
} }
} }
func TestLocal_planDestroyNoConfig(t *testing.T) {
b := TestLocal(t)
p := TestLocalProvider(t, b, "test")
terraform.TestStateFile(t, b.StatePath, testPlanState())
outDir := testTempDir(t)
defer os.RemoveAll(outDir)
planPath := filepath.Join(outDir, "plan.tfplan")
op := testOperationPlan()
op.Destroy = true
op.PlanRefresh = true
op.Module = nil
op.PlanOutPath = planPath
run, err := b.Operation(context.Background(), op)
if err != nil {
t.Fatalf("bad: %s", err)
}
<-run.Done()
if run.Err != nil {
t.Fatalf("err: %s", err)
}
if !p.RefreshCalled {
t.Fatal("refresh should be called")
}
if run.PlanEmpty {
t.Fatal("plan should not be empty")
}
plan := testReadPlan(t, planPath)
for _, m := range plan.Diff.Modules {
for _, r := range m.Resources {
if !r.Destroy {
t.Fatalf("bad: %#v", r)
}
}
}
}
func TestLocal_planOutPathNoChange(t *testing.T) { func TestLocal_planOutPathNoChange(t *testing.T) {
b := TestLocal(t) b := TestLocal(t)
TestLocalProvider(t, b, "test") TestLocalProvider(t, b, "test")