Merge pull request #12777 from hashicorp/b-refresh-empty

backend/local: allow refresh on empty/non-existent state
This commit is contained in:
Mitchell Hashimoto 2017-03-16 13:04:27 -07:00 committed by GitHub
commit 6921457601
3 changed files with 57 additions and 35 deletions

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"os"
"strings"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/go-multierror"
@ -22,18 +23,10 @@ func (b *Local) opRefresh(
if b.Backend == nil {
if _, err := os.Stat(b.StatePath); err != nil {
if os.IsNotExist(err) {
runningOp.Err = fmt.Errorf(
"The Terraform state file for your infrastructure does not\n"+
"exist. The 'refresh' command only works and only makes sense\n"+
"when there is existing state that Terraform is managing. Please\n"+
"double-check the value given below and try again. If you\n"+
"haven't created infrastructure with Terraform yet, use the\n"+
"'terraform apply' command.\n\n"+
"Path: %s",
b.StatePath)
return
err = nil
}
if err != nil {
runningOp.Err = fmt.Errorf(
"There was an error reading the Terraform state that is needed\n"+
"for refreshing. The path and error are shown below.\n\n"+
@ -42,6 +35,7 @@ func (b *Local) opRefresh(
return
}
}
}
// If we have no config module given to use, create an empty tree to
// avoid crashes when Terraform.Context is initialized.
@ -74,6 +68,12 @@ func (b *Local) opRefresh(
// Set our state
runningOp.State = opState.State()
if runningOp.State.Empty() || !runningOp.State.HasResources() {
if b.CLI != nil {
b.CLI.Output(b.Colorize().Color(
strings.TrimSpace(refreshNoState) + "\n"))
}
}
// Perform operation and write the resulting state to the running op
newState, err := tfCtx.Refresh()
@ -93,3 +93,11 @@ func (b *Local) opRefresh(
return
}
}
const refreshNoState = `
[reset][bold][yellow]Empty or non-existent state file.[reset][yellow]
Refresh will do nothing. Refresh does not error or return an erroneous
exit status because many automation scripts use refresh, plan, then apply
and may not have a state file yet for the first run.
`

View File

@ -9,6 +9,7 @@ import (
"strings"
"testing"
"github.com/hashicorp/terraform/helper/copy"
"github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/cli"
)
@ -59,6 +60,37 @@ func TestRefresh(t *testing.T) {
}
}
func TestRefresh_empty(t *testing.T) {
// Create a temporary working directory that is empty
td := tempDir(t)
copy.CopyDir(testFixturePath("refresh-empty"), td)
defer os.RemoveAll(td)
defer testChdir(t, td)()
p := testProvider()
ui := new(cli.MockUi)
c := &RefreshCommand{
Meta: Meta{
ContextOpts: testCtxConfig(p),
Ui: ui,
},
}
p.RefreshFn = nil
p.RefreshReturn = &terraform.InstanceState{ID: "yes"}
args := []string{
td,
}
if code := c.Run(args); code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
if p.RefreshCalled {
t.Fatal("refresh should not be called")
}
}
func TestRefresh_lockedState(t *testing.T) {
state := testState()
statePath := testStateFile(t, state)
@ -96,25 +128,6 @@ func TestRefresh_lockedState(t *testing.T) {
}
}
func TestRefresh_badState(t *testing.T) {
p := testProvider()
ui := new(cli.MockUi)
c := &RefreshCommand{
Meta: Meta{
ContextOpts: testCtxConfig(p),
Ui: ui,
},
}
args := []string{
"-state", "i-should-not-exist-ever",
testFixturePath("refresh"),
}
if code := c.Run(args); code != 1 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
}
func TestRefresh_cwd(t *testing.T) {
cwd, err := os.Getwd()
if err != nil {

View File

@ -0,0 +1 @@
# Hello