From d01886a644b0706cd1ef7f2bd04631f60c438623 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 20 Mar 2017 10:05:24 -0700 Subject: [PATCH] command: remove legacy remote state on migration Fixes #12871 We were forgetting to remove the legacy remote state from the actual state value when migrating. This only causes an issue when saving a plan since the plan contains the state itself and causes an error where both a backend + legacy state exist. If saved plans aren't used this causes no noticable issue. Due to buggy upgrades already existing in the wild, I also added code to clear the remote section if it exists in a standard unchanged backend --- backend/local/backend_plan.go | 6 ++++++ command/meta_backend_migrate.go | 9 +++++++++ command/meta_backend_test.go | 7 +++++++ .../backend-new-legacy/local-state-old.tfstate | 8 +++++++- 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/backend/local/backend_plan.go b/backend/local/backend_plan.go index afb483dad..f63735873 100644 --- a/backend/local/backend_plan.go +++ b/backend/local/backend_plan.go @@ -110,6 +110,12 @@ func (b *Local) opPlan( // Write the backend if we have one plan.Backend = op.PlanOutBackend + // This works around a bug (#12871) which is no longer possible to + // trigger but will exist for already corrupted upgrades. + if plan.Backend != nil && plan.State != nil { + plan.State.Remote = nil + } + log.Printf("[INFO] backend/local: writing plan output to: %s", path) f, err := os.Create(path) if err == nil { diff --git a/command/meta_backend_migrate.go b/command/meta_backend_migrate.go index cce00c35b..643e6e570 100644 --- a/command/meta_backend_migrate.go +++ b/command/meta_backend_migrate.go @@ -235,6 +235,15 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error { one := stateOne.State() two := stateTwo.State() + // Clear the legacy remote state in both cases. If we're at the migration + // step then this won't be used anymore. + if one != nil { + one.Remote = nil + } + if two != nil { + two.Remote = nil + } + var confirmFunc func(state.State, state.State, *backendMigrateOpts) (bool, error) switch { // No migration necessary diff --git a/command/meta_backend_test.go b/command/meta_backend_test.go index 54bdc2053..5cc8289d4 100644 --- a/command/meta_backend_test.go +++ b/command/meta_backend_test.go @@ -771,6 +771,13 @@ func TestMetaBackend_configureNewLegacyCopy(t *testing.T) { } } + // Verify we have no configured legacy in the state itself + { + if !state.Remote.Empty() { + t.Fatalf("legacy has remote state: %#v", state.Remote) + } + } + // Write some state state = terraform.NewState() state.Lineage = "changing" diff --git a/command/test-fixtures/backend-new-legacy/local-state-old.tfstate b/command/test-fixtures/backend-new-legacy/local-state-old.tfstate index 0af594cc4..8f312596d 100644 --- a/command/test-fixtures/backend-new-legacy/local-state-old.tfstate +++ b/command/test-fixtures/backend-new-legacy/local-state-old.tfstate @@ -2,5 +2,11 @@ "version": 3, "terraform_version": "0.8.2", "serial": 7, - "lineage": "backend-new-legacy" + "lineage": "backend-new-legacy", + "remote": { + "type": "local", + "config": { + "path": "local-state-old.tfstate" + } + } }