Skip to content

Commit

Permalink
Deprecate the tfmigrate plan --out=tfplan option
Browse files Browse the repository at this point in the history
Closes #62

The tfmigrate plan --out=tfplan option was originally requested in #36,
and added in #37.

While testing Terraform 1.1 support, I found it no longer work with
Terraform 1.1. #62

After debugging, the tfmigrate plan --out=tfplan option was based on a
bug prior to Terraform 1.1.

Since terraform state push increments the serial of tfstate, a saved
plan file in tfmigrate plan phase should not be able to terraform apply.
However, prior to Terraform 1.1, there was no proper validation and
terraform apply allows a such case incorrectly. Starting from Terraform
1.1, it now rejects the plan as stale, which seems to be a correct
behavior.

That is, the tfmigrate plan --out=tfplan option doesn't work with
Terraform 1.1 or later. There is no way to do this.

Fortunately, Terraform 1.1 added a new `moved` block feature, so some
use-cases could be covered by the `moved` block.

So, I decided to deprecate the tfmigrate plan --out=tfplan option
without replacement and it will be removed in a future release.
  • Loading branch information
minamijoyo committed Dec 10, 2021
1 parent 3cc5036 commit dba98a6
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 5 deletions.
14 changes: 12 additions & 2 deletions command/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type PlanCommand struct {
func (c *PlanCommand) Run(args []string) int {
cmdFlags := flag.NewFlagSet("plan", flag.ContinueOnError)
cmdFlags.StringVar(&c.configFile, "config", defaultConfigFile, "A path to tfmigrate config file")
cmdFlags.StringVar(&c.out, "out", "", "Save a plan file after dry-run migration to the given path")
cmdFlags.StringVar(&c.out, "out", "", "[Deprecated] Save a plan file after dry-run migration to the given path")

if err := cmdFlags.Parse(args); err != nil {
c.UI.Error(fmt.Sprintf("failed to parse arguments: %s", err))
Expand All @@ -40,6 +40,12 @@ func (c *PlanCommand) Run(args []string) int {
// So logging the option set log level to DEBUG instead of INFO.
log.Printf("[DEBUG] [command] option: %#v\n", c.Option)

// The tfmigrate plan --out=tfplan option is deprecated and doesn't work with Terraform 1.1+
// https://github.com/minamijoyo/tfmigrate/issues/62
if c.Option.PlanOut != "" {
log.Println("[WARN] The --out option is deprecated without replacement and it will be removed in a future release")
}

if c.config.History == nil {
// non-history mode
if len(cmdFlags.Args()) != 1 {
Expand Down Expand Up @@ -114,9 +120,13 @@ Arguments:
Options:
--config A path to tfmigrate config file
--out=path Save a plan file after dry-run migration to the given path.
[Deprecated]
--out=path
Save a plan file after dry-run migration to the given path.
Note that applying the plan file only affects a local state,
make sure to force push it to remote after terraform apply.
This option doesn't work with Terraform 1.1+
`
return strings.TrimSpace(helpText)
}
Expand Down
21 changes: 19 additions & 2 deletions tfmigrate/multi_state_migrator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,23 @@ func TestAccMultiStateMigratorApply(t *testing.T) {
}

if tc.force {
// The tfmigrate plan --out=tfplan option is deprecated and doesn't work with Terraform 1.1+
// https://github.com/minamijoyo/tfmigrate/issues/62
fromTfVersionMatched, err := tfexec.MatchTerraformVersion(ctx, fromTf, ">= 1.1.0")
if err != nil {
t.Fatalf("failed to check terraform version constraints in fromDir: %s", err)
}
if fromTfVersionMatched {
t.Skip("skip the following test because the saved plan can't apply in Terraform v1.1+")
}
toTfVersionMatched, err := tfexec.MatchTerraformVersion(ctx, toTf, ">= 1.1.0")
if err != nil {
t.Fatalf("failed to check terraform version constraints in toDir: %s", err)
}
if toTfVersionMatched {
t.Skip("skip the following test because the saved plan can't apply in Terraform v1.1+")
}

// apply the saved plan files
fromPlan, err := ioutil.ReadFile(filepath.Join(fromTf.Dir(), o.PlanOut))
if err != nil {
Expand All @@ -346,14 +363,14 @@ func TestAccMultiStateMigratorApply(t *testing.T) {

// Terraform >= v0.12.25 and < v0.13 has a bug for state push -force
// https://github.com/hashicorp/terraform/issues/25761
fromTfVersionMatched, err := tfexec.MatchTerraformVersion(ctx, fromTf, ">= 0.12.25, < 0.13")
fromTfVersionMatched, err = tfexec.MatchTerraformVersion(ctx, fromTf, ">= 0.12.25, < 0.13")
if err != nil {
t.Fatalf("failed to check terraform version constraints in fromDir: %s", err)
}
if fromTfVersionMatched {
t.Skip("skip the following test due to a bug in Terraform v0.12")
}
toTfVersionMatched, err := tfexec.MatchTerraformVersion(ctx, toTf, ">= 0.12.25, < 0.13")
toTfVersionMatched, err = tfexec.MatchTerraformVersion(ctx, toTf, ">= 0.12.25, < 0.13")
if err != nil {
t.Fatalf("failed to check terraform version constraints in toDir: %s", err)
}
Expand Down
14 changes: 13 additions & 1 deletion tfmigrate/state_migrator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,18 @@ resource "aws_security_group" "baz" {}
t.Fatalf("expect to have changes")
}

// The tfmigrate plan --out=tfplan option was based on a bug prior to Terraform 1.1.
// Terraform v1.1 now rejects the plan as stale.
// The tfmigrate plan --out=tfplan option is deprecated without replacement.
// https://github.com/minamijoyo/tfmigrate/issues/62
tfVersionMatched, err := tfexec.MatchTerraformVersion(ctx, tf, ">= 1.1.0")
if err != nil {
t.Fatalf("failed to check terraform version constraints: %s", err)
}
if tfVersionMatched {
t.Skip("skip the following test because the saved plan can't apply in Terraform v1.1+")
}

// apply the saved plan files
plan, err := ioutil.ReadFile(filepath.Join(tf.Dir(), o.PlanOut))
if err != nil {
Expand All @@ -300,7 +312,7 @@ resource "aws_security_group" "baz" {}

// Terraform >= v0.12.25 and < v0.13 has a bug for state push -force
// https://github.com/hashicorp/terraform/issues/25761
tfVersionMatched, err := tfexec.MatchTerraformVersion(ctx, tf, ">= 0.12.25, < 0.13")
tfVersionMatched, err = tfexec.MatchTerraformVersion(ctx, tf, ">= 0.12.25, < 0.13")
if err != nil {
t.Fatalf("failed to check terraform version constraints: %s", err)
}
Expand Down

0 comments on commit dba98a6

Please sign in to comment.