states/statemgr: don't panic if no state file is present on first write

This commit is contained in:
Martin Atkins 2018-08-27 15:54:03 -07:00
parent 5731703de5
commit 03e6771536
2 changed files with 43 additions and 1 deletions

View File

@ -123,6 +123,13 @@ func (s *Filesystem) WriteState(state *states.State) error {
// writing to a temp file on the same filesystem, and renaming the file over // writing to a temp file on the same filesystem, and renaming the file over
// the original. // the original.
if s.readFile == nil {
err := s.RefreshState()
if err != nil {
return err
}
}
defer s.mutex()() defer s.mutex()()
// We'll try to write our backup first, so we can be sure we've created // We'll try to write our backup first, so we can be sure we've created
@ -150,6 +157,9 @@ func (s *Filesystem) WriteState(state *states.State) error {
defer s.stateFileOut.Sync() defer s.stateFileOut.Sync()
s.file = s.file.DeepCopy() s.file = s.file.DeepCopy()
if s.file == nil {
s.file = NewStateFile()
}
s.file.State = state.DeepCopy() s.file.State = state.DeepCopy()
if _, err := s.stateFileOut.Seek(0, os.SEEK_SET); err != nil { if _, err := s.stateFileOut.Seek(0, os.SEEK_SET); err != nil {
@ -164,7 +174,7 @@ func (s *Filesystem) WriteState(state *states.State) error {
return nil return nil
} }
if !statefile.StatesMarshalEqual(s.file.State, s.readFile.State) { if s.readFile == nil || !statefile.StatesMarshalEqual(s.file.State, s.readFile.State) {
s.file.Serial++ s.file.Serial++
} }

View File

@ -0,0 +1,32 @@
package statemgr
import (
"fmt"
uuid "github.com/hashicorp/go-uuid"
"github.com/hashicorp/terraform/states/statefile"
"github.com/hashicorp/terraform/version"
)
// NewLineage generates a new lineage identifier string. A lineage identifier
// is an opaque string that is intended to be unique in space and time, chosen
// when state is recorded at a location for the first time and then preserved
// afterwards to allow Terraform to recognize when one state snapshot is a
// predecessor or successor of another.
func NewLineage() string {
lineage, err := uuid.GenerateUUID()
if err != nil {
panic(fmt.Errorf("Failed to generate lineage: %v", err))
}
return lineage
}
// NewStateFile creates a new statefile.File object, with a newly-minted
// lineage identifier and serial 0, and returns a pointer to it.
func NewStateFile() *statefile.File {
return &statefile.File{
Lineage: NewLineage(),
TerraformVersion: version.SemVer,
}
}