Use -state-out option when applying from a plan
When working from an existing plan, we weren't setting the PathOut field for a LocalState. This required adding an outPath argument to the StateFromPlan function to avoid having to introspect the returned state.State interface to find the appropriate field. To test we run a plan first and provide the new plan to apply with `-state-out` set.
This commit is contained in:
parent
a84aa5e914
commit
6b5ee73e86
|
@ -1326,6 +1326,59 @@ func TestApply_disableBackup(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -state-out wasn't taking effect when a plan is supplied. GH-7264
|
||||||
|
func TestApply_stateOutWithPlan(t *testing.T) {
|
||||||
|
p := testProvider()
|
||||||
|
ui := new(cli.MockUi)
|
||||||
|
|
||||||
|
tmpDir := testTempDir(t)
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
statePath := filepath.Join(tmpDir, "state.tfstate")
|
||||||
|
planPath := filepath.Join(tmpDir, "terraform.tfplan")
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"-state", statePath,
|
||||||
|
"-out", planPath,
|
||||||
|
testFixturePath("plan"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run plan first to get a current plan file
|
||||||
|
pc := &PlanCommand{
|
||||||
|
Meta: Meta{
|
||||||
|
ContextOpts: testCtxConfig(p),
|
||||||
|
Ui: ui,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if code := pc.Run(args); code != 0 {
|
||||||
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// now run apply with the generated plan
|
||||||
|
stateOutPath := filepath.Join(tmpDir, "state-new.tfstate")
|
||||||
|
|
||||||
|
args = []string{
|
||||||
|
"-state", statePath,
|
||||||
|
"-state-out", stateOutPath,
|
||||||
|
planPath,
|
||||||
|
}
|
||||||
|
|
||||||
|
ac := &ApplyCommand{
|
||||||
|
Meta: Meta{
|
||||||
|
ContextOpts: testCtxConfig(p),
|
||||||
|
Ui: ui,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if code := ac.Run(args); code != 0 {
|
||||||
|
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// now make sure we wrote out our new state
|
||||||
|
if _, err := os.Stat(stateOutPath); err != nil {
|
||||||
|
t.Fatalf("missing new state file: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testHttpServer(t *testing.T) net.Listener {
|
func testHttpServer(t *testing.T) net.Listener {
|
||||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -109,14 +109,18 @@ func (m *Meta) Context(copts contextOpts) (*terraform.Context, bool, error) {
|
||||||
f.Close()
|
f.Close()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Setup our state
|
// Setup our state
|
||||||
state, statePath, err := StateFromPlan(m.statePath, plan)
|
state, statePath, err := StateFromPlan(m.statePath, m.stateOutPath, plan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, fmt.Errorf("Error loading plan: %s", err)
|
return nil, false, fmt.Errorf("Error loading plan: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set our state
|
// Set our state
|
||||||
m.state = state
|
m.state = state
|
||||||
m.stateOutPath = statePath
|
|
||||||
|
// this is used for printing the saved location later
|
||||||
|
if m.stateOutPath == "" {
|
||||||
|
m.stateOutPath = statePath
|
||||||
|
}
|
||||||
|
|
||||||
if len(m.variables) > 0 {
|
if len(m.variables) > 0 {
|
||||||
return nil, false, fmt.Errorf(
|
return nil, false, fmt.Errorf(
|
||||||
|
|
|
@ -169,7 +169,8 @@ func State(opts *StateOpts) (*StateResult, error) {
|
||||||
|
|
||||||
// StateFromPlan gets our state from the plan.
|
// StateFromPlan gets our state from the plan.
|
||||||
func StateFromPlan(
|
func StateFromPlan(
|
||||||
localPath string, plan *terraform.Plan) (state.State, string, error) {
|
localPath, outPath string,
|
||||||
|
plan *terraform.Plan) (state.State, string, error) {
|
||||||
var result state.State
|
var result state.State
|
||||||
resultPath := localPath
|
resultPath := localPath
|
||||||
if plan != nil && plan.State != nil &&
|
if plan != nil && plan.State != nil &&
|
||||||
|
@ -186,7 +187,10 @@ func StateFromPlan(
|
||||||
}
|
}
|
||||||
|
|
||||||
if result == nil {
|
if result == nil {
|
||||||
local := &state.LocalState{Path: resultPath}
|
local := &state.LocalState{
|
||||||
|
Path: resultPath,
|
||||||
|
PathOut: outPath,
|
||||||
|
}
|
||||||
local.SetState(plan.State)
|
local.SetState(plan.State)
|
||||||
result = local
|
result = local
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue