From 14a233b019031f0f3fb71b51129849c39f13cce0 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Tue, 22 Sep 2020 17:33:09 -0400 Subject: [PATCH] command: Taint should respect required_version Despite not requiring the configuration for any other reason, the taint subcommand should not execute if the required_version constraints cannot be met. Doing so can result in an undesirable state file upgrade. --- command/taint.go | 30 +++++++++++ command/taint_test.go | 52 +++++++++++++++++++ .../taint-check-required-version/main.tf | 7 +++ 3 files changed, 89 insertions(+) create mode 100644 command/testdata/taint-check-required-version/main.tf diff --git a/command/taint.go b/command/taint.go index 97464994c29b..4c8d0f93fc8a 100644 --- a/command/taint.go +++ b/command/taint.go @@ -3,11 +3,13 @@ package command import ( "context" "fmt" + "os" "strings" "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/command/clistate" "github.com/hashicorp/terraform/states" + "github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/tfdiags" ) @@ -62,6 +64,34 @@ func (c *TaintCommand) Run(args []string) int { return 1 } + // Load the config and check the core version requirements are satisfied + loader, err := c.initConfigLoader() + if err != nil { + diags = diags.Append(err) + c.showDiagnostics(diags) + return 1 + } + + pwd, err := os.Getwd() + if err != nil { + c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err)) + return 1 + } + + config, configDiags := loader.LoadConfig(pwd) + diags = diags.Append(configDiags) + if diags.HasErrors() { + c.showDiagnostics(diags) + return 1 + } + + versionDiags := terraform.CheckCoreVersionRequirements(config) + diags = diags.Append(versionDiags) + if diags.HasErrors() { + c.showDiagnostics(diags) + return 1 + } + // Load the backend b, backendDiags := c.Backend(nil) diags = diags.Append(backendDiags) diff --git a/command/taint_test.go b/command/taint_test.go index 80816b837de6..30e60e0141a0 100644 --- a/command/taint_test.go +++ b/command/taint_test.go @@ -8,6 +8,7 @@ import ( "github.com/mitchellh/cli" "github.com/hashicorp/terraform/addrs" + "github.com/hashicorp/terraform/helper/copy" "github.com/hashicorp/terraform/states" "github.com/hashicorp/terraform/terraform" ) @@ -407,6 +408,57 @@ func TestTaint_module(t *testing.T) { testStateOutput(t, statePath, testTaintModuleStr) } +func TestTaint_checkRequiredVersion(t *testing.T) { + // Create a temporary working directory that is empty + td := tempDir(t) + copy.CopyDir(testFixturePath("taint-check-required-version"), td) + defer os.RemoveAll(td) + defer testChdir(t, td)() + + // Write the temp state + state := &terraform.State{ + Modules: []*terraform.ModuleState{ + { + Path: []string{"root"}, + Resources: map[string]*terraform.ResourceState{ + "test_instance.foo": { + Type: "test_instance", + Primary: &terraform.InstanceState{ + ID: "bar", + }, + }, + }, + }, + }, + } + path := testStateFileDefault(t, state) + + ui := cli.NewMockUi() + c := &TaintCommand{ + Meta: Meta{ + testingOverrides: metaOverridesForProvider(testProvider()), + Ui: ui, + }, + } + + args := []string{"test_instance.foo"} + if code := c.Run(args); code != 1 { + t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String()) + } + + // State is unchanged + testStateOutput(t, path, testTaintDefaultStr) + + // Required version diags are correct + errStr := ui.ErrorWriter.String() + if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) { + t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr) + } + if strings.Contains(errStr, `required_version = ">= 0.13.0"`) { + t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr) + } +} + const testTaintStr = ` test_instance.foo: (tainted) ID = bar diff --git a/command/testdata/taint-check-required-version/main.tf b/command/testdata/taint-check-required-version/main.tf new file mode 100644 index 000000000000..f3f71a6ead30 --- /dev/null +++ b/command/testdata/taint-check-required-version/main.tf @@ -0,0 +1,7 @@ +terraform { + required_version = "~> 0.9.0" +} + +terraform { + required_version = ">= 0.13.0" +}