Merge pull request #20843 from hashicorp/svh/f-force-push

backend/local: preserve serial and lineage on failure
This commit is contained in:
Sander van Harmelen 2019-03-28 10:19:11 +01:00 committed by GitHub
commit 86164c0bb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 13 additions and 8 deletions

View File

@ -157,7 +157,15 @@ func (b *Local) opApply(
runningOp.State = applyState
err := statemgr.WriteAndPersist(opState, applyState)
if err != nil {
diags = diags.Append(b.backupStateForError(applyState, err))
// Export the state file from the state manager and assign the new
// state. This is needed to preserve the existing serial and lineage.
stateFile := statemgr.Export(opState)
if stateFile == nil {
stateFile = &statefile.File{}
}
stateFile.State = applyState
diags = diags.Append(b.backupStateForError(stateFile, err))
b.ReportResult(runningOp, diags)
return
}
@ -208,11 +216,11 @@ func (b *Local) opApply(
// to local disk to help the user recover. This is a "last ditch effort" sort
// of thing, so we really don't want to end up in this codepath; we should do
// everything we possibly can to get the state saved _somewhere_.
func (b *Local) backupStateForError(applyState *states.State, err error) error {
func (b *Local) backupStateForError(stateFile *statefile.File, err error) error {
b.CLI.Error(fmt.Sprintf("Failed to save state: %s\n", err))
local := statemgr.NewFilesystem("errored.tfstate")
writeErr := local.WriteState(applyState)
writeErr := local.WriteStateForMigration(stateFile, true)
if writeErr != nil {
b.CLI.Error(fmt.Sprintf(
"Also failed to create local state file for recovery: %s\n\n", writeErr,
@ -223,9 +231,6 @@ func (b *Local) backupStateForError(applyState *states.State, err error) error {
// but at least the user has _some_ path to recover if we end up
// here for some reason.
stateBuf := new(bytes.Buffer)
stateFile := &statefile.File{
State: applyState,
}
jsonErr := statefile.Write(stateFile, stateBuf)
if jsonErr != nil {
b.CLI.Error(fmt.Sprintf(

View File

@ -49,7 +49,7 @@ type Filesystem struct {
lockID string
// created is set to true if stateFileOut didn't exist before we created it.
// This is mostly so we can clean up emtpy files during tests, but doesn't
// This is mostly so we can clean up empty files during tests, but doesn't
// hurt to remove file we never wrote to.
created bool

View File

@ -31,7 +31,7 @@ type Migrator interface {
// the given file and the current file and complete the update only if
// that function returns nil. If force is set this may override such
// checks, but some backends do not support forcing and so will act
// as if force is always true.
// as if force is always false.
WriteStateForMigration(f *statefile.File, force bool) error
}