states: Extract version check logic from read

Instead of always checking the Terraform version associated with a state
file when reading it, we add a CheckTerraformVersion method and call it
from locations where we care about enforcing this check.

For this commit, the check has been retained at all call sites for
states/statefile.Read, with these exceptions:

- Unit tests, which shouldn't care about the state file version;
- E2E test runner which should always be using valid state files;
- terraform.ShimLegacyState, where the check is pointless as the state
  file was just created by the current Terraform version.
pull/26692/head
Alisdair McDiarmid 6 years ago
parent 931f09437f
commit ff7382680d

@ -64,6 +64,9 @@ func (r *remoteClient) Put(state []byte) error {
if err != nil {
return fmt.Errorf("Error reading state: %s", err)
}
if err := stateFile.CheckTerraformVersion(); err != nil {
return fmt.Errorf("Incompatible statefile: %s", err)
}
options := tfe.StateVersionCreateOptions{
Lineage: tfe.String(stateFile.Lineage),

@ -245,6 +245,9 @@ func getStateFromPath(path string) (*statefile.File, error) {
if err != nil {
return nil, fmt.Errorf("Error reading %s as a statefile: %s", path, err)
}
if err := stateFile.CheckTerraformVersion(); err != nil {
return nil, fmt.Errorf("Incompatible statefile %s: %s", path, err)
}
return stateFile, nil
}

@ -63,6 +63,10 @@ func (c *StatePushCommand) Run(args []string) int {
c.Ui.Error(fmt.Sprintf("Error reading source state %q: %s", args[0], err))
return 1
}
if err := srcStateFile.CheckTerraformVersion(); err != nil {
c.Ui.Error(fmt.Sprintf("Incompatible statefile %q: %s", args[0], err))
return 1
}
// Load the backend
b, backendDiags := c.Backend(nil)

@ -141,6 +141,10 @@ func (c *WorkspaceNewCommand) Run(args []string) int {
c.Ui.Error(err.Error())
return 1
}
if err := stateFile.CheckTerraformVersion(); err != nil {
c.Ui.Error(err.Error())
return 1
}
// save the existing state in the new Backend.
err = stateMgr.WriteState(stateFile.State)

@ -101,7 +101,11 @@ func (r *Reader) ReadStateFile() (*statefile.File, error) {
if err != nil {
return nil, fmt.Errorf("failed to extract state from plan file: %s", err)
}
return statefile.Read(r)
stateFile, err := statefile.Read(r)
if err == nil {
err = stateFile.CheckTerraformVersion()
}
return stateFile, err
}
}
return nil, statefile.ErrNoState

@ -125,6 +125,9 @@ func (s *State) refreshState() error {
if err != nil {
return err
}
if err := stateFile.CheckTerraformVersion(); err != nil {
return err
}
s.lineage = stateFile.Lineage
s.serial = stateFile.Serial

@ -1,6 +1,8 @@
package statefile
import (
"fmt"
version "github.com/hashicorp/go-version"
"github.com/hashicorp/terraform/states"
@ -60,3 +62,15 @@ func (f *File) DeepCopy() *File {
State: f.State.DeepCopy(),
}
}
func (f *File) CheckTerraformVersion() error {
if f.TerraformVersion != nil && f.TerraformVersion.GreaterThan(tfversion.SemVer) {
return fmt.Errorf(
"state snapshot was created by Terraform v%s, which is newer than current v%s; upgrade to Terraform v%s or greater to work with this state",
f.TerraformVersion,
tfversion.SemVer,
f.TerraformVersion,
)
}
return nil
}

@ -62,15 +62,6 @@ func Read(r io.Reader) (*File, error) {
panic("readState returned nil state with no errors")
}
if state.TerraformVersion != nil && state.TerraformVersion.GreaterThan(tfversion.SemVer) {
return state, fmt.Errorf(
"state snapshot was created by Terraform v%s, which is newer than current v%s; upgrade to Terraform v%s or greater to work with this state",
state.TerraformVersion,
tfversion.SemVer,
state.TerraformVersion,
)
}
return state, diags.Err()
}

@ -280,6 +280,10 @@ func (s *Filesystem) refreshState() error {
return err
}
log.Printf("[TRACE] statemgr.Filesystem: snapshot file has nil snapshot, but that's okay")
} else {
if err := f.CheckTerraformVersion(); err != nil {
return err
}
}
s.file = f
@ -459,6 +463,10 @@ func (s *Filesystem) createStateFiles() error {
}
log.Printf("[TRACE] statemgr.Filesystem: no previously-stored snapshot exists")
} else {
if err := s.backupFile.CheckTerraformVersion(); err != nil {
return err
}
log.Printf("[TRACE] statemgr.Filesystem: existing snapshot has lineage %q serial %d", s.backupFile.Lineage, s.backupFile.Serial)
}

Loading…
Cancel
Save