Merge pull request #16920 from hashicorp/jbardin/init-future-state

check state version during init
This commit is contained in:
James Bardin 2018-01-05 16:54:41 -05:00 committed by GitHub
commit 504ea578ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 10 deletions

View File

@ -180,7 +180,6 @@ func (c *InitCommand) Run(args []string) int {
"Error downloading modules: %s", err))
return 1
}
}
// If we're requesting backend configuration or looking for required
@ -280,6 +279,12 @@ func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade
return diags.Err()
}
if err := terraform.CheckStateVersion(state); err != nil {
diags = diags.Append(err)
c.showDiagnostics(diags)
return err
}
if err := terraform.CheckRequiredVersion(mod); err != nil {
diags = diags.Append(err)
c.showDiagnostics(diags)

View File

@ -11,6 +11,7 @@ import (
"strings"
"testing"
"github.com/hashicorp/terraform/backend/local"
"github.com/hashicorp/terraform/helper/copy"
"github.com/hashicorp/terraform/plugin/discovery"
"github.com/hashicorp/terraform/state"
@ -583,12 +584,12 @@ func TestInit_getProvider(t *testing.T) {
defer os.RemoveAll(td)
defer testChdir(t, td)()
overrides := metaOverridesForProvider(testProvider())
ui := new(cli.MockUi)
m := Meta{
testingOverrides: metaOverridesForProvider(testProvider()),
testingOverrides: overrides,
Ui: ui,
}
installer := &mockProviderInstaller{
Providers: map[string][]string{
// looking for an exact version
@ -631,6 +632,36 @@ func TestInit_getProvider(t *testing.T) {
if _, err := os.Stat(betweenPath); os.IsNotExist(err) {
t.Fatal("provider 'between' not downloaded")
}
t.Run("future-state", func(t *testing.T) {
// getting providers should fail if a state from a newer version of
// terraform exists, since InitCommand.getProviders needs to inspect that
// state.
s := terraform.NewState()
s.TFVersion = "100.1.0"
local := &state.LocalState{
Path: local.DefaultStateFilename,
}
if err := local.WriteState(s); err != nil {
t.Fatal(err)
}
ui := new(cli.MockUi)
m.Ui = ui
c := &InitCommand{
Meta: m,
providerInstaller: installer,
}
if code := c.Run(nil); code == 0 {
t.Fatal("expected error, got:", ui.OutputWriter)
}
errMsg := ui.ErrorWriter.String()
if !strings.Contains(errMsg, "future Terraform version") {
t.Fatal("unexpected error:", errMsg)
}
})
}
// make sure we can locate providers in various paths

View File

@ -145,13 +145,8 @@ func NewContext(opts *ContextOpts) (*Context, error) {
// If our state is from the future, then error. Callers can avoid
// this error by explicitly setting `StateFutureAllowed`.
if !opts.StateFutureAllowed && state.FromFutureTerraform() {
return nil, fmt.Errorf(
"Terraform doesn't allow running any operations against a state\n"+
"that was written by a future Terraform version. The state is\n"+
"reporting it is written by Terraform '%s'.\n\n"+
"Please run at least that version of Terraform to continue.",
state.TFVersion)
if err := CheckStateVersion(state); err != nil && !opts.StateFutureAllowed {
return nil, err
}
// Explicitly reset our state version to our current version so that

View File

@ -2174,6 +2174,19 @@ func (s moduleStateSort) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
// StateCompatible returns an error if the state is not compatible with the
// current version of terraform.
func CheckStateVersion(state *State) error {
if state == nil {
return nil
}
if state.FromFutureTerraform() {
return fmt.Errorf(stateInvalidTerraformVersionErr, state.TFVersion)
}
return nil
}
const stateValidateErrMultiModule = `
Multiple modules with the same path: %s
@ -2182,3 +2195,11 @@ in your state file that point to the same module. This will cause Terraform
to behave in unexpected and error prone ways and is invalid. Please back up
and modify your state file manually to resolve this.
`
const stateInvalidTerraformVersionErr = `
Terraform doesn't allow running any operations against a state
that was written by a future Terraform version. The state is
reporting it is written by Terraform '%s'
Please run at least that version of Terraform to continue.
`