backend/local: check for empty config on apply
This prevents Terraform from crashing on apply/destroy with a directory with no Terraform configuration files. We allow a destroy with no files but not an apply.
This commit is contained in:
parent
fa2fd0bf01
commit
1480d0c5b8
|
@ -4,11 +4,13 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
clistate "github.com/hashicorp/terraform/command/state"
|
||||
"github.com/hashicorp/terraform/config/module"
|
||||
"github.com/hashicorp/terraform/state"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
@ -19,6 +21,19 @@ func (b *Local) opApply(
|
|||
runningOp *backend.RunningOperation) {
|
||||
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.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
|
||||
countHook := new(CountHook)
|
||||
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.
|
||||
`
|
||||
|
|
|
@ -3,6 +3,7 @@ package local
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"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) {
|
||||
b := TestLocal(t)
|
||||
p := TestLocalProvider(t, b, "test")
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
This is an empty dir
|
Loading…
Reference in New Issue