Merge pull request #11989 from hashicorp/b-backend-local

backend/local: check for empty config on apply
This commit is contained in:
Mitchell Hashimoto 2017-02-16 11:02:45 -08:00 committed by GitHub
commit f231ca3d5a
3 changed files with 79 additions and 0 deletions

View File

@ -4,11 +4,13 @@ import (
"context" "context"
"fmt" "fmt"
"log" "log"
"strings"
"github.com/hashicorp/errwrap" "github.com/hashicorp/errwrap"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/backend"
clistate "github.com/hashicorp/terraform/command/state" clistate "github.com/hashicorp/terraform/command/state"
"github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/state"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
) )
@ -19,6 +21,19 @@ func (b *Local) opApply(
runningOp *backend.RunningOperation) { runningOp *backend.RunningOperation) {
log.Printf("[INFO] backend/local: starting Apply operation") log.Printf("[INFO] backend/local: starting Apply operation")
// If we have a nil module at this point, then set it to an empty tree
// to avoid any potential crashes.
if op.Plan == nil && op.Module == nil && !op.Destroy {
runningOp.Err = fmt.Errorf(strings.TrimSpace(applyErrNoConfig))
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)
stateHook := new(StateHook) stateHook := new(StateHook)
@ -165,3 +180,12 @@ func (b *Local) opApply(
} }
} }
} }
const applyErrNoConfig = `
No configuration files found!
Apply requires configuration to be present. Applying without a configuration
would mark everything for destruction, which is normally not what is desired.
If you would like to destroy everything, please run 'terraform destroy' instead
which does not require any configuration files.
`

View File

@ -3,6 +3,7 @@ package local
import ( import (
"context" "context"
"fmt" "fmt"
"os"
"sync" "sync"
"testing" "testing"
@ -50,6 +51,59 @@ test_instance.foo:
`) `)
} }
func TestLocal_applyEmptyDir(t *testing.T) {
b := TestLocal(t)
p := TestLocalProvider(t, b, "test")
p.ApplyReturn = &terraform.InstanceState{ID: "yes"}
op := testOperationApply()
op.Module = nil
run, err := b.Operation(context.Background(), op)
if err != nil {
t.Fatalf("bad: %s", err)
}
<-run.Done()
if run.Err == nil {
t.Fatal("should error")
}
if p.ApplyCalled {
t.Fatal("apply should not be called")
}
if _, err := os.Stat(b.StateOutPath); err == nil {
t.Fatal("should not exist")
}
}
func TestLocal_applyEmptyDirDestroy(t *testing.T) {
b := TestLocal(t)
p := TestLocalProvider(t, b, "test")
p.ApplyReturn = nil
op := testOperationApply()
op.Module = nil
op.Destroy = true
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.ApplyCalled {
t.Fatal("apply should not be called")
}
checkState(t, b.StateOutPath, `<no state>`)
}
func TestLocal_applyError(t *testing.T) { func TestLocal_applyError(t *testing.T) {
b := TestLocal(t) b := TestLocal(t)
p := TestLocalProvider(t, b, "test") p := TestLocalProvider(t, b, "test")

View File

@ -0,0 +1 @@
This is an empty dir