mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Merge pull request #16920 from hashicorp/jbardin/init-future-state
check state version during init
This commit is contained in:
commit
504ea578ee
@ -180,7 +180,6 @@ func (c *InitCommand) Run(args []string) int {
|
|||||||
"Error downloading modules: %s", err))
|
"Error downloading modules: %s", err))
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're requesting backend configuration or looking for required
|
// 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()
|
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 {
|
if err := terraform.CheckRequiredVersion(mod); err != nil {
|
||||||
diags = diags.Append(err)
|
diags = diags.Append(err)
|
||||||
c.showDiagnostics(diags)
|
c.showDiagnostics(diags)
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/backend/local"
|
||||||
"github.com/hashicorp/terraform/helper/copy"
|
"github.com/hashicorp/terraform/helper/copy"
|
||||||
"github.com/hashicorp/terraform/plugin/discovery"
|
"github.com/hashicorp/terraform/plugin/discovery"
|
||||||
"github.com/hashicorp/terraform/state"
|
"github.com/hashicorp/terraform/state"
|
||||||
@ -583,12 +584,12 @@ func TestInit_getProvider(t *testing.T) {
|
|||||||
defer os.RemoveAll(td)
|
defer os.RemoveAll(td)
|
||||||
defer testChdir(t, td)()
|
defer testChdir(t, td)()
|
||||||
|
|
||||||
|
overrides := metaOverridesForProvider(testProvider())
|
||||||
ui := new(cli.MockUi)
|
ui := new(cli.MockUi)
|
||||||
m := Meta{
|
m := Meta{
|
||||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
testingOverrides: overrides,
|
||||||
Ui: ui,
|
Ui: ui,
|
||||||
}
|
}
|
||||||
|
|
||||||
installer := &mockProviderInstaller{
|
installer := &mockProviderInstaller{
|
||||||
Providers: map[string][]string{
|
Providers: map[string][]string{
|
||||||
// looking for an exact version
|
// looking for an exact version
|
||||||
@ -631,6 +632,36 @@ func TestInit_getProvider(t *testing.T) {
|
|||||||
if _, err := os.Stat(betweenPath); os.IsNotExist(err) {
|
if _, err := os.Stat(betweenPath); os.IsNotExist(err) {
|
||||||
t.Fatal("provider 'between' not downloaded")
|
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
|
// make sure we can locate providers in various paths
|
||||||
|
@ -145,13 +145,8 @@ func NewContext(opts *ContextOpts) (*Context, error) {
|
|||||||
|
|
||||||
// If our state is from the future, then error. Callers can avoid
|
// If our state is from the future, then error. Callers can avoid
|
||||||
// this error by explicitly setting `StateFutureAllowed`.
|
// this error by explicitly setting `StateFutureAllowed`.
|
||||||
if !opts.StateFutureAllowed && state.FromFutureTerraform() {
|
if err := CheckStateVersion(state); err != nil && !opts.StateFutureAllowed {
|
||||||
return nil, fmt.Errorf(
|
return nil, err
|
||||||
"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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Explicitly reset our state version to our current version so that
|
// Explicitly reset our state version to our current version so that
|
||||||
|
@ -2174,6 +2174,19 @@ func (s moduleStateSort) Swap(i, j int) {
|
|||||||
s[i], s[j] = s[j], s[i]
|
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 = `
|
const stateValidateErrMultiModule = `
|
||||||
Multiple modules with the same path: %s
|
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
|
to behave in unexpected and error prone ways and is invalid. Please back up
|
||||||
and modify your state file manually to resolve this.
|
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.
|
||||||
|
`
|
||||||
|
Loading…
Reference in New Issue
Block a user