minamijoyo / tfmigrate

A Terraform / OpenTofu state migration tool for GitOps
MIT License
1.13k stars 57 forks source link

"multi_state" failed question #43

Closed antigenius0910 closed 3 years ago

antigenius0910 commented 3 years ago

Hi thanks for this awesome project! I have a quick question here.

I would like to use the "multi_state" feature but don't know if I config it correctly. this is my tfmigrate_mv_dir1_dir2.hcl file in sandbox env

bash-5.0# cat tfmigrate_mv_dir1_dir2.hcl 
migration "multi_state" "mv_dir1_dir2" {
  from_dir = "/work/tmp/dir1"
  to_dir   = "/work/tmp/dir2"
  actions = [
    "mv aws_security_group.foo aws_security_group.foo2",
    "mv aws_security_group.bar aws_security_group.bar2",
  ]
}

and this is the current state list

bash-5.0# terraform state list
aws_security_group.bar
aws_security_group.foo

/work/tmp/dir2 is a empty directory

bash-5.0# ls -al /work/tmp/dir2
total 0
drwxr-xr-x    2 root     root            64 Oct  9 02:03 .
drwxr-xr-x    4 root     root           128 Oct  8 14:32 ..

What I think multi_state will do for me is

  1. rename the resource
  2. cut from the current tfstate file from dir1 and create a new tfstate file in dir2 But, instead, this is the result.
    
    bash-5.0# TFMIGRATE_LOG=DEBUG tfmigrate plan tfmigrate_mv_dir1_dir2.hcl
    2021/10/09 02:05:31 [DEBUG] [main] start: tfmigrate plan tfmigrate_mv_dir1_dir2.hcl
    2021/10/09 02:05:31 [DEBUG] [main] tfmigrate version: 0.2.9
    2021/10/09 02:05:31 [DEBUG] [command] config: &config.TfmigrateConfig{MigrationDir:".", History:(*history.Config)(nil)}
    2021/10/09 02:05:31 [DEBUG] [command] option: &tfmigrate.MigratorOption{ExecPath:"", PlanOut:""}
    2021/10/09 02:05:31 [INFO] [runner] load migration file: tfmigrate_mv_dir1_dir2.hcl
    2021/10/09 02:05:31 [INFO] [migrator] multi start state migrator plan
    2021/10/09 02:05:31 [DEBUG] [executor@/work/tmp/dir1]$ terraform version
    2021/10/09 02:05:31 [INFO] [migrator@/work/tmp/dir1] terraform version: 1.0.8
    2021/10/09 02:05:31 [INFO] [migrator@/work/tmp/dir1] initialize work dir
    2021/10/09 02:05:32 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color
    2021/10/09 02:05:32 [INFO] [migrator@/work/tmp/dir1] switch to remote workspace default
    2021/10/09 02:05:33 [DEBUG] [executor@/work/tmp/dir1]$ terraform workspace select default
    2021/10/09 02:05:33 [INFO] [migrator@/work/tmp/dir1] get the current remote state
    2021/10/09 02:05:33 [DEBUG] [executor@/work/tmp/dir1]$ terraform state pull
    2021/10/09 02:05:33 [INFO] [migrator@/work/tmp/dir1] override backend to local
    2021/10/09 02:05:33 [INFO] [executor@/work/tmp/dir1] create an override file
    2021/10/09 02:05:33 [INFO] [migrator@/work/tmp/dir1] creating local workspace folder in: /work/tmp/dir1/terraform.tfstate.d/default
    2021/10/09 02:05:33 [INFO] [executor@/work/tmp/dir1] switch backend to local
    2021/10/09 02:05:35 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
    2021/10/09 02:05:35 [DEBUG] [executor@/work/tmp/dir2]$ terraform version
    2021/10/09 02:05:35 [INFO] [migrator@/work/tmp/dir2] terraform version: 1.0.8
    2021/10/09 02:05:35 [INFO] [migrator@/work/tmp/dir2] initialize work dir
    2021/10/09 02:05:35 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color
    2021/10/09 02:05:35 [INFO] [migrator@/work/tmp/dir2] switch to remote workspace default
    2021/10/09 02:05:35 [DEBUG] [executor@/work/tmp/dir2]$ terraform workspace select default
    2021/10/09 02:05:35 [INFO] [migrator@/work/tmp/dir2] get the current remote state
    2021/10/09 02:05:36 [DEBUG] [executor@/work/tmp/dir2]$ terraform state pull
    2021/10/09 02:05:36 [INFO] [migrator@/work/tmp/dir2] override backend to local
    2021/10/09 02:05:36 [INFO] [executor@/work/tmp/dir2] create an override file
    2021/10/09 02:05:36 [INFO] [migrator@/work/tmp/dir2] creating local workspace folder in: /work/tmp/dir2/terraform.tfstate.d/default
    2021/10/09 02:05:36 [INFO] [executor@/work/tmp/dir2] switch backend to local
    2021/10/09 02:05:36 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
    2021/10/09 02:05:36 [INFO] [migrator] compute new states (/work/tmp/dir1 => /work/tmp/dir2)
    2021/10/09 02:05:36 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp995693296 -state-out=/tmp/tmp740880783 -backup=/dev/null aws_security_group.foo aws_security_group.foo
    2021/10/09 02:05:36 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp848061346 -state-out=/tmp/tmp388647065 -backup=/dev/null aws_security_group.foo aws_security_group.foo2
    2021/10/09 02:05:36 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp335183140 -state-out=/tmp/tmp391829555 -backup=/dev/null aws_security_group.bar aws_security_group.bar
    2021/10/09 02:05:36 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp514207734 -state-out=/tmp/tmp343693021 -backup=/dev/null aws_security_group.bar aws_security_group.bar2
    2021/10/09 02:05:36 [INFO] [migrator@/work/tmp/dir1] check diffs
    2021/10/09 02:05:37 [DEBUG] [executor@/work/tmp/dir1]$ terraform plan -state=/tmp/tmp664858264 -out=/tmp/tfplan877530391 -input=false -no-color -detailed-exitcode
    2021/10/09 02:05:37 [DEBUG] [executor@/work/tmp/dir1] failed to run command: (*exec.ExitError)(0xc0003063a0)(exit status 2)
    2021/10/09 02:05:37 [ERROR] [migrator@/work/tmp/dir1] unexpected diffs
    2021/10/09 02:05:37 [INFO] [executor@/work/tmp/dir2] remove the override file
    2021/10/09 02:05:37 [INFO] [executor@/work/tmp/dir2] remove the workspace state folder
    2021/10/09 02:05:37 [INFO] [executor@/work/tmp/dir2] switch back to remote
    2021/10/09 02:05:38 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
    2021/10/09 02:05:38 [INFO] [executor@/work/tmp/dir1] remove the override file
    2021/10/09 02:05:38 [INFO] [executor@/work/tmp/dir1] remove the workspace state folder
    2021/10/09 02:05:38 [INFO] [executor@/work/tmp/dir1] switch back to remote
    2021/10/09 02:05:40 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
    terraform plan command returns unexpected diffs: failed to run command (exited 2): terraform plan -state=/tmp/tmp664858264 -out=/tmp/tfplan877530391 -input=false -no-color -detailed-exitcode
    stdout:

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:

Terraform will perform the following actions:

aws_security_group.bar will be created

Plan: 2 to add, 0 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: /tmp/tfplan877530391

To perform exactly these actions, run the following command to apply: terraform apply "/tmp/tfplan877530391"

stderr:



Instead rename and move the tfstate it seem to want to create extra resource for me. and now I wondering on which step I might did wrong on multi_state.

Thank for your help and your awesome project once again!
minamijoyo commented 3 years ago

@antigenius0910 Looking at the log, the diff detected in the from_dir (dir1). The plan will create moved resources in the from_dir. This means that the states will be moved, but the resources still have been defined in the configurations (.tf) and will be created again in the from_dir. Could you confirm that you moved the Terraform configurations of moved resources from dir1 to dir2? The tfmigrate only moves tfstate and you need to move resources in .tf by yourself.

antigenius0910 commented 3 years ago

Thanks @minamijoyo for the prompt response. sorry I didn't see your response earlier therefore I edit my question with README format and redo it once again. Let me go through your suggest and see if I can figure it out now.

antigenius0910 commented 3 years ago

ok @minamijoyo,

I recreate the POC once again and please let me know if I done correctly this time.

this is what I have in dir1

bash-5.0# ls -al
total 28
drwxr-xr-x   11 root     root           352 Oct  9 02:15 .
drwxr-xr-x    4 root     root           128 Oct  8 14:32 ..
drwxr-xr-x    4 root     root           128 Oct  9 02:15 .terraform
-rw-r--r--    1 root     root          1077 Oct  7 21:10 .terraform.lock.hcl
-rw-r--r--    1 root     root           107 Oct  8 14:41 .tfmigrate
-rw-r--r--    1 root     root          1114 Oct  9 02:14 config.tf
-rw-r--r--    1 root     root             1 Oct  9 02:14 main.tf
drwxr-xr-x    4 root     root           128 Oct  9 02:12 old
-rw-r--r--    1 root     root           235 Oct  9 02:02 tfmigrate_mv_dir1_dir2.hcl
-rw-r--r--    1 root     root           107 Oct  8 14:47 tfmigrate_test.hcl
-rw-r--r--    1 root     root           174 Oct  8 15:23 tfmigrate_test2.hcl

bash-5.0# cat main.tf 
NULL
bash-5.0#

bash-5.0# cat tfmigrate_mv_dir1_dir2.hcl 
migration "multi_state" "mv_dir1_dir2" {
  from_dir = "/work/tmp/dir1"
  to_dir   = "/work/tmp/dir2"
  actions = [
    "mv aws_security_group.foo aws_security_group.foo2",
    "mv aws_security_group.bar aws_security_group.bar2",
  ]
}

this is what I have in dir2

bash-5.0# pwd
/work/tmp/dir2
bash-5.0# ls -al
total 12
drwxr-xr-x    6 root     root           192 Oct  9 02:15 .
drwxr-xr-x    4 root     root           128 Oct  8 14:32 ..
-rw-r--r--    1 root     root          1114 Oct  9 02:12 config.tf
-rw-r--r--    1 root     root           111 Oct  9 02:12 main.tf

bash-5.0# cat main.tf 
resource "aws_security_group" "foo2" {
  name = "foo"
}

resource "aws_security_group" "bar2" {
  name = "bar"
}

here is state list

bash-5.0# terraform state list
aws_security_group.bar
aws_security_group.foo

here is multi-state running results

bash-5.0# TFMIGRATE_LOG=DEBUG tfmigrate plan tfmigrate_mv_dir1_dir2.hcl

2021/10/09 03:03:12 [DEBUG] [main] start: tfmigrate plan tfmigrate_mv_dir1_dir2.hcl
2021/10/09 03:03:12 [DEBUG] [main] tfmigrate version: 0.2.9
2021/10/09 03:03:12 [DEBUG] [command] config: &config.TfmigrateConfig{MigrationDir:".", History:(*history.Config)(nil)}
2021/10/09 03:03:12 [DEBUG] [command] option: &tfmigrate.MigratorOption{ExecPath:"", PlanOut:""}
2021/10/09 03:03:12 [INFO] [runner] load migration file: tfmigrate_mv_dir1_dir2.hcl
2021/10/09 03:03:12 [INFO] [migrator] multi start state migrator plan
2021/10/09 03:03:12 [DEBUG] [executor@/work/tmp/dir1]$ terraform version
2021/10/09 03:03:12 [INFO] [migrator@/work/tmp/dir1] terraform version: 1.0.8
2021/10/09 03:03:12 [INFO] [migrator@/work/tmp/dir1] initialize work dir
2021/10/09 03:03:14 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color
2021/10/09 03:03:14 [INFO] [migrator@/work/tmp/dir1] switch to remote workspace default
2021/10/09 03:03:15 [DEBUG] [executor@/work/tmp/dir1]$ terraform workspace select default
2021/10/09 03:03:15 [INFO] [migrator@/work/tmp/dir1] get the current remote state
2021/10/09 03:03:15 [DEBUG] [executor@/work/tmp/dir1]$ terraform state pull
2021/10/09 03:03:15 [INFO] [migrator@/work/tmp/dir1] override backend to local
2021/10/09 03:03:15 [INFO] [executor@/work/tmp/dir1] create an override file
2021/10/09 03:03:15 [INFO] [migrator@/work/tmp/dir1] creating local workspace folder in: /work/tmp/dir1/terraform.tfstate.d/default
2021/10/09 03:03:15 [INFO] [executor@/work/tmp/dir1] switch backend to local
2021/10/09 03:03:17 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
2021/10/09 03:03:17 [DEBUG] [executor@/work/tmp/dir2]$ terraform version
2021/10/09 03:03:17 [INFO] [migrator@/work/tmp/dir2] terraform version: 1.0.8
2021/10/09 03:03:17 [INFO] [migrator@/work/tmp/dir2] initialize work dir
2021/10/09 03:03:18 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color
2021/10/09 03:03:18 [INFO] [migrator@/work/tmp/dir2] switch to remote workspace default
2021/10/09 03:03:19 [DEBUG] [executor@/work/tmp/dir2]$ terraform workspace select default
2021/10/09 03:03:19 [INFO] [migrator@/work/tmp/dir2] get the current remote state
2021/10/09 03:03:19 [DEBUG] [executor@/work/tmp/dir2]$ terraform state pull
2021/10/09 03:03:19 [INFO] [migrator@/work/tmp/dir2] override backend to local
2021/10/09 03:03:19 [INFO] [executor@/work/tmp/dir2] create an override file
2021/10/09 03:03:19 [INFO] [migrator@/work/tmp/dir2] creating local workspace folder in: /work/tmp/dir2/terraform.tfstate.d/default
2021/10/09 03:03:19 [INFO] [executor@/work/tmp/dir2] switch backend to local
2021/10/09 03:03:21 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
2021/10/09 03:03:21 [INFO] [migrator] compute new states (/work/tmp/dir1 => /work/tmp/dir2)
2021/10/09 03:03:21 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp182956343 -state-out=/tmp/tmp138647338 -backup=/dev/null aws_security_group.foo aws_security_group.foo
2021/10/09 03:03:21 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp330973313 -state-out=/tmp/tmp121202156 -backup=/dev/null aws_security_group.foo aws_security_group.foo2
2021/10/09 03:03:21 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp828792411 -state-out=/tmp/tmp745882110 -backup=/dev/null aws_security_group.bar aws_security_group.bar
2021/10/09 03:03:21 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp826731845 -state-out=/tmp/tmp100663776 -backup=/dev/null aws_security_group.bar aws_security_group.bar2
2021/10/09 03:03:21 [INFO] [migrator@/work/tmp/dir1] check diffs
2021/10/09 03:03:22 [DEBUG] [executor@/work/tmp/dir1]$ terraform plan -state=/tmp/tmp121499071 -out=/tmp/tfplan338528274 -input=false -no-color -detailed-exitcode
2021/10/09 03:03:22 [INFO] [migrator@/work/tmp/dir2] check diffs
2021/10/09 03:03:24 [DEBUG] [executor@/work/tmp/dir2]$ terraform plan -state=/tmp/tmp173385289 -out=/tmp/tfplan582690068 -input=false -no-color -detailed-exitcode
2021/10/09 03:03:24 [DEBUG] [executor@/work/tmp/dir2] failed to run command: (*exec.ExitError)(0xc00030c600)(exit status 2)
2021/10/09 03:03:24 [ERROR] [migrator@/work/tmp/dir2] unexpected diffs
2021/10/09 03:03:24 [INFO] [executor@/work/tmp/dir2] remove the override file
2021/10/09 03:03:24 [INFO] [executor@/work/tmp/dir2] remove the workspace state folder
2021/10/09 03:03:24 [INFO] [executor@/work/tmp/dir2] switch back to remote
2021/10/09 03:03:26 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
2021/10/09 03:03:26 [INFO] [executor@/work/tmp/dir1] remove the override file
2021/10/09 03:03:26 [INFO] [executor@/work/tmp/dir1] remove the workspace state folder
2021/10/09 03:03:26 [INFO] [executor@/work/tmp/dir1] switch back to remote
2021/10/09 03:03:28 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
terraform plan command returns unexpected diffs: failed to run command (exited 2): terraform plan -state=/tmp/tmp173385289 -out=/tmp/tfplan582690068 -input=false -no-color -detailed-exitcode
stdout:
aws_security_group.foo: Refreshing state... [id=sg-5eb74e40]
aws_security_group.bar: Refreshing state... [id=sg-826b9c77]
aws_security_group.foo2: Refreshing state... [id=sg-5eb74e40]
aws_security_group.bar2: Refreshing state... [id=sg-826b9c77]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the
last "terraform apply":

  # aws_security_group.bar has been changed
  ~ resource "aws_security_group" "bar" {
        id                     = "sg-826b9c77"
        name                   = "bar"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }
  # aws_security_group.bar2 has been changed
  ~ resource "aws_security_group" "bar2" {
        id                     = "sg-826b9c77"
        name                   = "bar"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }
  # aws_security_group.foo has been changed
  ~ resource "aws_security_group" "foo" {
        id                     = "sg-5eb74e40"
        name                   = "foo"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }
  # aws_security_group.foo2 has been changed
  ~ resource "aws_security_group" "foo2" {
        id                     = "sg-5eb74e40"
        name                   = "foo"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }

Unless you have made equivalent changes to your configuration, or ignored the
relevant attributes using ignore_changes, the following plan may include
actions to undo or respond to these changes.

─────────────────────────────────────────────────────────────────────────────

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_security_group.bar will be destroyed
  - resource "aws_security_group" "bar" {
      - arn                    = "arn:aws:ec2:ap-northeast-1:000000000000:security-group/sg-826b9c77" -> null
      - description            = "Managed by Terraform" -> null
      - egress                 = [
          - {
              - cidr_blocks      = [
                  - "0.0.0.0/0",
                ]
              - description      = ""
              - from_port        = 0
              - ipv6_cidr_blocks = []
              - prefix_list_ids  = []
              - protocol         = "-1"
              - security_groups  = []
              - self             = false
              - to_port          = 0
            },
        ] -> null
      - id                     = "sg-826b9c77" -> null
      - ingress                = [] -> null
      - name                   = "bar" -> null
      - owner_id               = "000000000000" -> null
      - revoke_rules_on_delete = false -> null
      - tags                   = {} -> null
      - tags_all               = {} -> null
    }

  # aws_security_group.foo will be destroyed
  - resource "aws_security_group" "foo" {
      - arn                    = "arn:aws:ec2:ap-northeast-1:000000000000:security-group/sg-5eb74e40" -> null
      - description            = "Managed by Terraform" -> null
      - egress                 = [
          - {
              - cidr_blocks      = [
                  - "0.0.0.0/0",
                ]
              - description      = ""
              - from_port        = 0
              - ipv6_cidr_blocks = []
              - prefix_list_ids  = []
              - protocol         = "-1"
              - security_groups  = []
              - self             = false
              - to_port          = 0
            },
        ] -> null
      - id                     = "sg-5eb74e40" -> null
      - ingress                = [] -> null
      - name                   = "foo" -> null
      - owner_id               = "000000000000" -> null
      - revoke_rules_on_delete = false -> null
      - tags                   = {} -> null
      - tags_all               = {} -> null
    }

Plan: 0 to add, 0 to change, 2 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: /tmp/tfplan582690068

To perform exactly these actions, run the following command to apply:
    terraform apply "/tmp/tfplan582690068"

stderr:

Am I doing this correctly this time? or should I have main.tf in both dir1 and dir2?

minamijoyo commented 3 years ago

The migration file indicates moving aws_security_group.foo and aws_security_group.bar from dir1 to dir2 and renaming them to aws_security_group.foo2 and aws_security_group.bar2. However your dir2/main.tf has aws_security_group.foo and aws_security_group.bar. They should be aws_security_group.foo2 and aws_security_group.bar2 or not to rename in the migration file.

antigenius0910 commented 3 years ago

yes, thanks for noticing that. I update my result once again before refresh the status. let me destroy everything and redo it once again. thanks

antigenius0910 commented 3 years ago

remove whole repo and re-clone from start, would you mind take a look for me once again when you have a chance? thanks! @minamijoyo Or can you show me your running result for the same steps? I would love to see the DEBUG and find out what was wrong with my setup. thank a million!

bash-5.0# terraform state list
aws_security_group.bar
aws_security_group.foo
bash-5.0# pwd
/work/tmp/dir1
bash-5.0# cat main.tf 
NULL

bash-5.0# cat tfmigrate_mv_dir1_dir2.hcl 
migration "multi_state" "mv_dir1_dir2" {
  from_dir = "/work/tmp/dir1"
  to_dir   = "/work/tmp/dir2"
  actions = [
    "mv aws_security_group.foo aws_security_group.foo2",
    "mv aws_security_group.bar aws_security_group.bar2",
  ]
}
bash-5.0# cat ../dir2/main.tf 
resource "aws_security_group" "foo2" {
  name = "foo"
}

resource "aws_security_group" "bar2" {
  name = "bar"
}
bash-5.0# TFMIGRATE_LOG=DEBUG tfmigrate plan tfmigrate_mv_dir1_dir2.hcl 
2021/10/09 03:21:10 [DEBUG] [main] start: tfmigrate plan tfmigrate_mv_dir1_dir2.hcl
2021/10/09 03:21:10 [DEBUG] [main] tfmigrate version: 0.2.9
2021/10/09 03:21:10 [DEBUG] [command] config: &config.TfmigrateConfig{MigrationDir:".", History:(*history.Config)(nil)}
2021/10/09 03:21:10 [DEBUG] [command] option: &tfmigrate.MigratorOption{ExecPath:"", PlanOut:""}
2021/10/09 03:21:10 [INFO] [runner] load migration file: tfmigrate_mv_dir1_dir2.hcl
2021/10/09 03:21:10 [INFO] [migrator] multi start state migrator plan
2021/10/09 03:21:10 [DEBUG] [executor@/work/tmp/dir1]$ terraform version
2021/10/09 03:21:10 [INFO] [migrator@/work/tmp/dir1] terraform version: 1.0.8
2021/10/09 03:21:10 [INFO] [migrator@/work/tmp/dir1] initialize work dir
2021/10/09 03:21:11 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color
2021/10/09 03:21:11 [INFO] [migrator@/work/tmp/dir1] switch to remote workspace default
2021/10/09 03:21:12 [DEBUG] [executor@/work/tmp/dir1]$ terraform workspace select default
2021/10/09 03:21:12 [INFO] [migrator@/work/tmp/dir1] get the current remote state
2021/10/09 03:21:12 [DEBUG] [executor@/work/tmp/dir1]$ terraform state pull
2021/10/09 03:21:12 [INFO] [migrator@/work/tmp/dir1] override backend to local
2021/10/09 03:21:12 [INFO] [executor@/work/tmp/dir1] create an override file
2021/10/09 03:21:12 [INFO] [migrator@/work/tmp/dir1] creating local workspace folder in: /work/tmp/dir1/terraform.tfstate.d/default
2021/10/09 03:21:12 [INFO] [executor@/work/tmp/dir1] switch backend to local
2021/10/09 03:21:14 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
2021/10/09 03:21:14 [DEBUG] [executor@/work/tmp/dir2]$ terraform version
2021/10/09 03:21:14 [INFO] [migrator@/work/tmp/dir2] terraform version: 1.0.8
2021/10/09 03:21:14 [INFO] [migrator@/work/tmp/dir2] initialize work dir
2021/10/09 03:21:15 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color
2021/10/09 03:21:15 [INFO] [migrator@/work/tmp/dir2] switch to remote workspace default
2021/10/09 03:21:16 [DEBUG] [executor@/work/tmp/dir2]$ terraform workspace select default
2021/10/09 03:21:16 [INFO] [migrator@/work/tmp/dir2] get the current remote state
2021/10/09 03:21:16 [DEBUG] [executor@/work/tmp/dir2]$ terraform state pull
2021/10/09 03:21:16 [INFO] [migrator@/work/tmp/dir2] override backend to local
2021/10/09 03:21:16 [INFO] [executor@/work/tmp/dir2] create an override file
2021/10/09 03:21:16 [INFO] [migrator@/work/tmp/dir2] creating local workspace folder in: /work/tmp/dir2/terraform.tfstate.d/default
2021/10/09 03:21:16 [INFO] [executor@/work/tmp/dir2] switch backend to local
2021/10/09 03:21:18 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
2021/10/09 03:21:18 [INFO] [migrator] compute new states (/work/tmp/dir1 => /work/tmp/dir2)
2021/10/09 03:21:18 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp606534563 -state-out=/tmp/tmp764914854 -backup=/dev/null aws_security_group.foo aws_security_group.foo
2021/10/09 03:21:18 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp626163149 -state-out=/tmp/tmp429340360 -backup=/dev/null aws_security_group.foo aws_security_group.foo2
2021/10/09 03:21:19 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp247318407 -state-out=/tmp/tmp407996730 -backup=/dev/null aws_security_group.bar aws_security_group.bar
2021/10/09 03:21:19 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp750598481 -state-out=/tmp/tmp517987452 -backup=/dev/null aws_security_group.bar aws_security_group.bar2
2021/10/09 03:21:19 [INFO] [migrator@/work/tmp/dir1] check diffs
2021/10/09 03:21:19 [DEBUG] [executor@/work/tmp/dir1]$ terraform plan -state=/tmp/tmp112175019 -out=/tmp/tfplan772214030 -input=false -no-color -detailed-exitcode
2021/10/09 03:21:19 [INFO] [migrator@/work/tmp/dir2] check diffs
2021/10/09 03:21:21 [DEBUG] [executor@/work/tmp/dir2]$ terraform plan -state=/tmp/tmp198648085 -out=/tmp/tfplan739372912 -input=false -no-color -detailed-exitcode
2021/10/09 03:21:21 [DEBUG] [executor@/work/tmp/dir2] failed to run command: (*exec.ExitError)(0xc0002d1080)(exit status 2)
2021/10/09 03:21:21 [ERROR] [migrator@/work/tmp/dir2] unexpected diffs
2021/10/09 03:21:21 [INFO] [executor@/work/tmp/dir2] remove the override file
2021/10/09 03:21:21 [INFO] [executor@/work/tmp/dir2] remove the workspace state folder
2021/10/09 03:21:21 [INFO] [executor@/work/tmp/dir2] switch back to remote
2021/10/09 03:21:24 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
2021/10/09 03:21:24 [INFO] [executor@/work/tmp/dir1] remove the override file
2021/10/09 03:21:24 [INFO] [executor@/work/tmp/dir1] remove the workspace state folder
2021/10/09 03:21:24 [INFO] [executor@/work/tmp/dir1] switch back to remote
2021/10/09 03:21:26 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
terraform plan command returns unexpected diffs: failed to run command (exited 2): terraform plan -state=/tmp/tmp198648085 -out=/tmp/tfplan739372912 -input=false -no-color -detailed-exitcode
stdout:
aws_security_group.foo: Refreshing state... [id=sg-8dea8701]
aws_security_group.bar2: Refreshing state... [id=sg-8a179b01]
aws_security_group.bar: Refreshing state... [id=sg-8a179b01]
aws_security_group.foo2: Refreshing state... [id=sg-8dea8701]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the
last "terraform apply":

  # aws_security_group.bar2 has been changed
  ~ resource "aws_security_group" "bar2" {
        id                     = "sg-8a179b01"
        name                   = "bar"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }
  # aws_security_group.foo has been changed
  ~ resource "aws_security_group" "foo" {
        id                     = "sg-8dea8701"
        name                   = "foo"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }
  # aws_security_group.foo2 has been changed
  ~ resource "aws_security_group" "foo2" {
        id                     = "sg-8dea8701"
        name                   = "foo"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }
  # aws_security_group.bar has been changed
  ~ resource "aws_security_group" "bar" {
        id                     = "sg-8a179b01"
        name                   = "bar"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }

Unless you have made equivalent changes to your configuration, or ignored the
relevant attributes using ignore_changes, the following plan may include
actions to undo or respond to these changes.

─────────────────────────────────────────────────────────────────────────────

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_security_group.bar will be destroyed
  - resource "aws_security_group" "bar" {
      - arn                    = "arn:aws:ec2:ap-northeast-1:000000000000:security-group/sg-8a179b01" -> null
      - description            = "Managed by Terraform" -> null
      - egress                 = [
          - {
              - cidr_blocks      = [
                  - "0.0.0.0/0",
                ]
              - description      = ""
              - from_port        = 0
              - ipv6_cidr_blocks = []
              - prefix_list_ids  = []
              - protocol         = "-1"
              - security_groups  = []
              - self             = false
              - to_port          = 0
            },
        ] -> null
      - id                     = "sg-8a179b01" -> null
      - ingress                = [] -> null
      - name                   = "bar" -> null
      - owner_id               = "000000000000" -> null
      - revoke_rules_on_delete = false -> null
      - tags                   = {} -> null
      - tags_all               = {} -> null
    }

  # aws_security_group.foo will be destroyed
  - resource "aws_security_group" "foo" {
      - arn                    = "arn:aws:ec2:ap-northeast-1:000000000000:security-group/sg-8dea8701" -> null
      - description            = "Managed by Terraform" -> null
      - egress                 = [
          - {
              - cidr_blocks      = [
                  - "0.0.0.0/0",
                ]
              - description      = ""
              - from_port        = 0
              - ipv6_cidr_blocks = []
              - prefix_list_ids  = []
              - protocol         = "-1"
              - security_groups  = []
              - self             = false
              - to_port          = 0
            },
        ] -> null
      - id                     = "sg-8dea8701" -> null
      - ingress                = [] -> null
      - name                   = "foo" -> null
      - owner_id               = "000000000000" -> null
      - revoke_rules_on_delete = false -> null
      - tags                   = {} -> null
      - tags_all               = {} -> null
    }

Plan: 0 to add, 0 to change, 2 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: /tmp/tfplan739372912

To perform exactly these actions, run the following command to apply:
    terraform apply "/tmp/tfplan739372912"

stderr:
minamijoyo commented 3 years ago

Looks a strange result. The plan will destroy aws_security_group.foo and aws_security_group.bar. It means dir2 has state of foo and bar before migration. I guess the dir2 has a garbage state or dir2 store the remote state to the same location of dir1.

antigenius0910 commented 3 years ago

yeah that is what I think therefore I raise this issue.

for assumption 1:

bash-5.0# cd ../dir2
bash-5.0# ls -al
total 12
drwxr-xr-x    6 root     root           192 Oct  9 03:44 .
drwxr-xr-x    4 root     root           128 Oct  9 03:17 ..
drwxr-xr-x    4 root     root           128 Oct  9 03:44 .terraform
-rw-r--r--    1 root     root           252 Oct  9 03:21 .terraform.lock.hcl
-rw-r--r--    1 root     root          1114 Oct  9 03:19 config.tf
-rw-r--r--    1 root     root           113 Oct  9 03:17 main.tf
bash-5.0# rm -rf .terraform*
bash-5.0# ls -al
total 8
drwxr-xr-x    4 root     root           128 Oct  9 04:11 .
drwxr-xr-x    4 root     root           128 Oct  9 03:17 ..
-rw-r--r--    1 root     root          1114 Oct  9 03:19 config.tf
-rw-r--r--    1 root     root           113 Oct  9 03:17 main.tf
bash-5.0# TFMIGRATE_LOG=DEBUG tfmigrate plan tfmigrate_mv_dir1_dir2.hcl 

2021/10/09 04:11:56 [DEBUG] [main] start: tfmigrate plan tfmigrate_mv_dir1_dir2.hcl
2021/10/09 04:11:56 [DEBUG] [main] tfmigrate version: 0.2.9
2021/10/09 04:11:56 [DEBUG] [command] config: &config.TfmigrateConfig{MigrationDir:".", History:(*history.Config)(nil)}
2021/10/09 04:11:56 [DEBUG] [command] option: &tfmigrate.MigratorOption{ExecPath:"", PlanOut:""}
2021/10/09 04:11:56 [INFO] [runner] load migration file: tfmigrate_mv_dir1_dir2.hcl
2021/10/09 04:11:56 [INFO] [migrator] multi start state migrator plan
2021/10/09 04:11:56 [DEBUG] [executor@/work/tmp/dir1]$ terraform version
2021/10/09 04:11:56 [INFO] [migrator@/work/tmp/dir1] terraform version: 1.0.8
2021/10/09 04:11:56 [INFO] [migrator@/work/tmp/dir1] initialize work dir
2021/10/09 04:11:58 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color
2021/10/09 04:11:58 [INFO] [migrator@/work/tmp/dir1] switch to remote workspace default
2021/10/09 04:11:58 [DEBUG] [executor@/work/tmp/dir1]$ terraform workspace select default
2021/10/09 04:11:58 [INFO] [migrator@/work/tmp/dir1] get the current remote state
2021/10/09 04:11:59 [DEBUG] [executor@/work/tmp/dir1]$ terraform state pull
2021/10/09 04:11:59 [INFO] [migrator@/work/tmp/dir1] override backend to local
2021/10/09 04:11:59 [INFO] [executor@/work/tmp/dir1] create an override file
2021/10/09 04:11:59 [INFO] [migrator@/work/tmp/dir1] creating local workspace folder in: /work/tmp/dir1/terraform.tfstate.d/default
2021/10/09 04:11:59 [INFO] [executor@/work/tmp/dir1] switch backend to local
2021/10/09 04:12:01 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
2021/10/09 04:12:01 [DEBUG] [executor@/work/tmp/dir2]$ terraform version
2021/10/09 04:12:01 [INFO] [migrator@/work/tmp/dir2] terraform version: 1.0.8
2021/10/09 04:12:01 [INFO] [migrator@/work/tmp/dir2] initialize work dir
2021/10/09 04:12:02 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color
2021/10/09 04:12:02 [INFO] [migrator@/work/tmp/dir2] switch to remote workspace default
2021/10/09 04:12:03 [DEBUG] [executor@/work/tmp/dir2]$ terraform workspace select default
2021/10/09 04:12:03 [INFO] [migrator@/work/tmp/dir2] get the current remote state
2021/10/09 04:12:03 [DEBUG] [executor@/work/tmp/dir2]$ terraform state pull
2021/10/09 04:12:03 [INFO] [migrator@/work/tmp/dir2] override backend to local
2021/10/09 04:12:03 [INFO] [executor@/work/tmp/dir2] create an override file
2021/10/09 04:12:03 [INFO] [migrator@/work/tmp/dir2] creating local workspace folder in: /work/tmp/dir2/terraform.tfstate.d/default
2021/10/09 04:12:03 [INFO] [executor@/work/tmp/dir2] switch backend to local
2021/10/09 04:12:05 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
2021/10/09 04:12:05 [INFO] [migrator] compute new states (/work/tmp/dir1 => /work/tmp/dir2)
2021/10/09 04:12:05 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp518146889 -state-out=/tmp/tmp750608404 -backup=/dev/null aws_security_group.foo aws_security_group.foo
2021/10/09 04:12:05 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp481165923 -state-out=/tmp/tmp939930214 -backup=/dev/null aws_security_group.foo aws_security_group.foo2
2021/10/09 04:12:05 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp400547981 -state-out=/tmp/tmp023251592 -backup=/dev/null aws_security_group.bar aws_security_group.bar
2021/10/09 04:12:05 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp919773767 -state-out=/tmp/tmp940621050 -backup=/dev/null aws_security_group.bar aws_security_group.bar2
2021/10/09 04:12:05 [INFO] [migrator@/work/tmp/dir1] check diffs
2021/10/09 04:12:06 [DEBUG] [executor@/work/tmp/dir1]$ terraform plan -state=/tmp/tmp889071633 -out=/tmp/tfplan452379196 -input=false -no-color -detailed-exitcode
2021/10/09 04:12:06 [INFO] [migrator@/work/tmp/dir2] check diffs
2021/10/09 04:12:08 [DEBUG] [executor@/work/tmp/dir2]$ terraform plan -state=/tmp/tmp828791403 -out=/tmp/tfplan737042126 -input=false -no-color -detailed-exitcode
2021/10/09 04:12:08 [DEBUG] [executor@/work/tmp/dir2] failed to run command: (*exec.ExitError)(0xc00040e320)(exit status 2)
2021/10/09 04:12:08 [ERROR] [migrator@/work/tmp/dir2] unexpected diffs
2021/10/09 04:12:08 [INFO] [executor@/work/tmp/dir2] remove the override file
2021/10/09 04:12:08 [INFO] [executor@/work/tmp/dir2] remove the workspace state folder
2021/10/09 04:12:08 [INFO] [executor@/work/tmp/dir2] switch back to remote
2021/10/09 04:12:10 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
2021/10/09 04:12:10 [INFO] [executor@/work/tmp/dir1] remove the override file
2021/10/09 04:12:10 [INFO] [executor@/work/tmp/dir1] remove the workspace state folder
2021/10/09 04:12:10 [INFO] [executor@/work/tmp/dir1] switch back to remote
2021/10/09 04:12:12 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
terraform plan command returns unexpected diffs: failed to run command (exited 2): terraform plan -state=/tmp/tmp828791403 -out=/tmp/tfplan737042126 -input=false -no-color -detailed-exitcode
stdout:
aws_security_group.foo: Refreshing state... [id=sg-8dea8701]
aws_security_group.bar: Refreshing state... [id=sg-8a179b01]
aws_security_group.foo2: Refreshing state... [id=sg-8dea8701]
aws_security_group.bar2: Refreshing state... [id=sg-8a179b01]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the
last "terraform apply":

  # aws_security_group.foo2 has been changed
  ~ resource "aws_security_group" "foo2" {
        id                     = "sg-8dea8701"
        name                   = "foo"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }
  # aws_security_group.bar has been changed
  ~ resource "aws_security_group" "bar" {
        id                     = "sg-8a179b01"
        name                   = "bar"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }
  # aws_security_group.bar2 has been changed
  ~ resource "aws_security_group" "bar2" {
        id                     = "sg-8a179b01"
        name                   = "bar"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }
  # aws_security_group.foo has been changed
  ~ resource "aws_security_group" "foo" {
        id                     = "sg-8dea8701"
        name                   = "foo"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }

Unless you have made equivalent changes to your configuration, or ignored the
relevant attributes using ignore_changes, the following plan may include
actions to undo or respond to these changes.

─────────────────────────────────────────────────────────────────────────────

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_security_group.bar will be destroyed
  - resource "aws_security_group" "bar" {
      - arn                    = "arn:aws:ec2:ap-northeast-1:000000000000:security-group/sg-8a179b01" -> null
      - description            = "Managed by Terraform" -> null
      - egress                 = [
          - {
              - cidr_blocks      = [
                  - "0.0.0.0/0",
                ]
              - description      = ""
              - from_port        = 0
              - ipv6_cidr_blocks = []
              - prefix_list_ids  = []
              - protocol         = "-1"
              - security_groups  = []
              - self             = false
              - to_port          = 0
            },
        ] -> null
      - id                     = "sg-8a179b01" -> null
      - ingress                = [] -> null
      - name                   = "bar" -> null
      - owner_id               = "000000000000" -> null
      - revoke_rules_on_delete = false -> null
      - tags                   = {} -> null
      - tags_all               = {} -> null
    }

  # aws_security_group.foo will be destroyed
  - resource "aws_security_group" "foo" {
      - arn                    = "arn:aws:ec2:ap-northeast-1:000000000000:security-group/sg-8dea8701" -> null
      - description            = "Managed by Terraform" -> null
      - egress                 = [
          - {
              - cidr_blocks      = [
                  - "0.0.0.0/0",
                ]
              - description      = ""
              - from_port        = 0
              - ipv6_cidr_blocks = []
              - prefix_list_ids  = []
              - protocol         = "-1"
              - security_groups  = []
              - self             = false
              - to_port          = 0
            },
        ] -> null
      - id                     = "sg-8dea8701" -> null
      - ingress                = [] -> null
      - name                   = "foo" -> null
      - owner_id               = "000000000000" -> null
      - revoke_rules_on_delete = false -> null
      - tags                   = {} -> null
      - tags_all               = {} -> null
    }

Plan: 0 to add, 0 to change, 2 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: /tmp/tfplan737042126

To perform exactly these actions, run the following command to apply:
    terraform apply "/tmp/tfplan737042126"

stderr:

For assumption 2: (how can I confirm the state are not in the same location? the terraform.tfstate file looks strange to me I though they should have 2 entries)

bash-5.0# pwd
/work/tmp/dir1
bash-5.0# cat .terraform/terraform.tfstate 
{
    "version": 3,
    "serial": 7,
    "lineage": "e2df0afd-129a-3422-0223-0ad8a990e64c",
    "backend": {
        "type": "s3",
        "config": {
            "access_key": "dummy",
            "acl": null,
            "assume_role_duration_seconds": null,
            "assume_role_policy": null,
            "assume_role_policy_arns": null,
            "assume_role_tags": null,
            "assume_role_transitive_tag_keys": null,
            "bucket": "tfstate-test",
            "dynamodb_endpoint": null,
            "dynamodb_table": null,
            "encrypt": null,
            "endpoint": "http://localstack:4566",
            "external_id": null,
            "force_path_style": true,
            "iam_endpoint": null,
            "key": "test/terraform.tfstate",
            "kms_key_id": null,
            "max_retries": null,
            "profile": null,
            "region": "ap-northeast-1",
            "role_arn": null,
            "secret_key": "dummy",
            "session_name": null,
            "shared_credentials_file": null,
            "skip_credentials_validation": true,
            "skip_metadata_api_check": true,
            "skip_region_validation": null,
            "sse_customer_key": null,
            "sts_endpoint": null,
            "token": null,
            "workspace_key_prefix": null
        },
        "hash": 3459050205
    },
    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {},
            "depends_on": []
        }
    ]
}

and

bash-5.0# pwd
/work/tmp/dir2
bash-5.0# cat .terraform/terraform.tfstate 
{
    "version": 3,
    "serial": 3,
    "lineage": "d17f3ead-0684-9fd5-dcd3-847da8e54812",
    "backend": {
        "type": "s3",
        "config": {
            "access_key": "dummy",
            "acl": null,
            "assume_role_duration_seconds": null,
            "assume_role_policy": null,
            "assume_role_policy_arns": null,
            "assume_role_tags": null,
            "assume_role_transitive_tag_keys": null,
            "bucket": "tfstate-test",
            "dynamodb_endpoint": null,
            "dynamodb_table": null,
            "encrypt": null,
            "endpoint": "http://localstack:4566",
            "external_id": null,
            "force_path_style": true,
            "iam_endpoint": null,
            "key": "test/terraform.tfstate",
            "kms_key_id": null,
            "max_retries": null,
            "profile": null,
            "region": "ap-northeast-1",
            "role_arn": null,
            "secret_key": "dummy",
            "session_name": null,
            "shared_credentials_file": null,
            "skip_credentials_validation": true,
            "skip_metadata_api_check": true,
            "skip_region_validation": null,
            "sse_customer_key": null,
            "sts_endpoint": null,
            "token": null,
            "workspace_key_prefix": null
        },
        "hash": 3459050205
    },
    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {},
            "depends_on": []
        }
    ]
}
minamijoyo commented 3 years ago

Looks the assumption 2 is true. The dir1 and dir2 use the same remote state path. Could you change terraform.backend.s3.key in dir2/config.tf from test/terraform.tfstate to dir2/terraform.tfstate?

antigenius0910 commented 3 years ago

that's exactly what went wrong! thanks for such a detail troubleshooting! Let me think about how we can make other people don't fall into the same mistake I made here. I think multi state is really a great feature and that really apply how people migrate/refactoring resource .tf file in real life. I am currently working on if I can move the resource .tf context to another directory as well so this repo can work with terraformer import right out of box! thanks @minamijoyo!!!

bash-5.0# cat ../dir2/config.tf 
terraform {
  # https://www.terraform.io/docs/backends/types/s3.html
  backend "s3" {
    region = "ap-northeast-1"
    bucket = "tfstate-test"
    key    = "dir2/terraform.tfstate"

    // mock s3 endpoint with localstack
    endpoint                    = "http://localstack:4566"
    access_key                  = "dummy"
    secret_key                  = "dummy"
    skip_credentials_validation = true
    skip_metadata_api_check     = true
    force_path_style            = true
  }
}

# https://www.terraform.io/docs/providers/aws/index.html
# https://www.terraform.io/docs/providers/aws/guides/custom-service-endpoints.html#localstack
provider "aws" {
  region = "ap-northeast-1"

  access_key                  = "dummy"
  secret_key                  = "dummy"
  skip_credentials_validation = true
  skip_metadata_api_check     = true
  skip_region_validation      = true
  skip_requesting_account_id  = true
  s3_force_path_style         = true

  // mock endpoints with localstack
  endpoints {
    s3  = "http://localstack:4566"
    ec2 = "http://localstack:4566"
    iam = "http://localstack:4566"
  }
}
bash-5.0# TFMIGRATE_LOG=DEBUG tfmigrate plan tfmigrate_mv_dir1_dir2.hcl 

2021/10/09 04:45:50 [DEBUG] [main] start: tfmigrate plan tfmigrate_mv_dir1_dir2.hcl
2021/10/09 04:45:50 [DEBUG] [main] tfmigrate version: 0.2.9
2021/10/09 04:45:50 [DEBUG] [command] config: &config.TfmigrateConfig{MigrationDir:".", History:(*history.Config)(nil)}
2021/10/09 04:45:50 [DEBUG] [command] option: &tfmigrate.MigratorOption{ExecPath:"", PlanOut:""}
2021/10/09 04:45:50 [INFO] [runner] load migration file: tfmigrate_mv_dir1_dir2.hcl
2021/10/09 04:45:50 [INFO] [migrator] multi start state migrator plan
2021/10/09 04:45:50 [DEBUG] [executor@/work/tmp/dir1]$ terraform version
2021/10/09 04:45:50 [INFO] [migrator@/work/tmp/dir1] terraform version: 1.0.8
2021/10/09 04:45:50 [INFO] [migrator@/work/tmp/dir1] initialize work dir
2021/10/09 04:45:52 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color
2021/10/09 04:45:52 [INFO] [migrator@/work/tmp/dir1] switch to remote workspace default
2021/10/09 04:45:52 [DEBUG] [executor@/work/tmp/dir1]$ terraform workspace select default
2021/10/09 04:45:52 [INFO] [migrator@/work/tmp/dir1] get the current remote state
2021/10/09 04:45:53 [DEBUG] [executor@/work/tmp/dir1]$ terraform state pull
2021/10/09 04:45:53 [INFO] [migrator@/work/tmp/dir1] override backend to local
2021/10/09 04:45:53 [INFO] [executor@/work/tmp/dir1] create an override file
2021/10/09 04:45:53 [INFO] [migrator@/work/tmp/dir1] creating local workspace folder in: /work/tmp/dir1/terraform.tfstate.d/default
2021/10/09 04:45:53 [INFO] [executor@/work/tmp/dir1] switch backend to local
2021/10/09 04:45:55 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
2021/10/09 04:45:55 [DEBUG] [executor@/work/tmp/dir2]$ terraform version
2021/10/09 04:45:55 [INFO] [migrator@/work/tmp/dir2] terraform version: 1.0.8
2021/10/09 04:45:55 [INFO] [migrator@/work/tmp/dir2] initialize work dir
2021/10/09 04:45:56 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color
2021/10/09 04:45:56 [INFO] [migrator@/work/tmp/dir2] switch to remote workspace default
2021/10/09 04:45:56 [DEBUG] [executor@/work/tmp/dir2]$ terraform workspace select default
2021/10/09 04:45:56 [INFO] [migrator@/work/tmp/dir2] get the current remote state
2021/10/09 04:45:57 [DEBUG] [executor@/work/tmp/dir2]$ terraform state pull
2021/10/09 04:45:57 [INFO] [migrator@/work/tmp/dir2] override backend to local
2021/10/09 04:45:57 [INFO] [executor@/work/tmp/dir2] create an override file
2021/10/09 04:45:57 [INFO] [migrator@/work/tmp/dir2] creating local workspace folder in: /work/tmp/dir2/terraform.tfstate.d/default
2021/10/09 04:45:57 [INFO] [executor@/work/tmp/dir2] switch backend to local
2021/10/09 04:45:59 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
2021/10/09 04:45:59 [INFO] [migrator] compute new states (/work/tmp/dir1 => /work/tmp/dir2)
2021/10/09 04:45:59 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp726231998 -state-out=/tmp/tmp734514693 -backup=/dev/null aws_security_group.foo aws_security_group.foo
2021/10/09 04:46:00 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp181922720 -state-out=/tmp/tmp555175039 -backup=/dev/null aws_security_group.foo aws_security_group.foo2
2021/10/09 04:46:00 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp085790162 -state-out=/tmp/tmp558717705 -backup=/dev/null aws_security_group.bar aws_security_group.bar
2021/10/09 04:46:00 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp743281876 -state-out=/tmp/tmp373301283 -backup=/dev/null aws_security_group.bar aws_security_group.bar2
2021/10/09 04:46:00 [INFO] [migrator@/work/tmp/dir1] check diffs
2021/10/09 04:46:01 [DEBUG] [executor@/work/tmp/dir1]$ terraform plan -state=/tmp/tmp441942822 -out=/tmp/tfplan905604685 -input=false -no-color -detailed-exitcode
2021/10/09 04:46:01 [INFO] [migrator@/work/tmp/dir2] check diffs
2021/10/09 04:46:02 [DEBUG] [executor@/work/tmp/dir2]$ terraform plan -state=/tmp/tmp649327944 -out=/tmp/tfplan219320327 -input=false -no-color -detailed-exitcode
2021/10/09 04:46:02 [INFO] [executor@/work/tmp/dir2] remove the override file
2021/10/09 04:46:02 [INFO] [executor@/work/tmp/dir2] remove the workspace state folder
2021/10/09 04:46:02 [INFO] [executor@/work/tmp/dir2] switch back to remote
2021/10/09 04:46:05 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
2021/10/09 04:46:05 [INFO] [executor@/work/tmp/dir1] remove the override file
2021/10/09 04:46:05 [INFO] [executor@/work/tmp/dir1] remove the workspace state folder
2021/10/09 04:46:05 [INFO] [executor@/work/tmp/dir1] switch back to remote
2021/10/09 04:46:07 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
2021/10/09 04:46:07 [INFO] [migrator] multi state migrator plan success!
bash-5.0# TFMIGRATE_LOG=DEBUG tfmigrate apply tfmigrate_mv_dir1_dir2.hcl 

2021/10/09 04:46:23 [DEBUG] [main] start: tfmigrate apply tfmigrate_mv_dir1_dir2.hcl
2021/10/09 04:46:23 [DEBUG] [main] tfmigrate version: 0.2.9
2021/10/09 04:46:23 [DEBUG] [command] config: &config.TfmigrateConfig{MigrationDir:".", History:(*history.Config)(nil)}
2021/10/09 04:46:23 [DEBUG] [command] option: &tfmigrate.MigratorOption{ExecPath:"", PlanOut:""}
2021/10/09 04:46:23 [INFO] [runner] load migration file: tfmigrate_mv_dir1_dir2.hcl
2021/10/09 04:46:23 [INFO] [migrator] start multi state migrator plan phase for apply
2021/10/09 04:46:23 [DEBUG] [executor@/work/tmp/dir1]$ terraform version
2021/10/09 04:46:23 [INFO] [migrator@/work/tmp/dir1] terraform version: 1.0.8
2021/10/09 04:46:23 [INFO] [migrator@/work/tmp/dir1] initialize work dir
2021/10/09 04:46:25 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color
2021/10/09 04:46:25 [INFO] [migrator@/work/tmp/dir1] switch to remote workspace default
2021/10/09 04:46:25 [DEBUG] [executor@/work/tmp/dir1]$ terraform workspace select default
2021/10/09 04:46:25 [INFO] [migrator@/work/tmp/dir1] get the current remote state
2021/10/09 04:46:26 [DEBUG] [executor@/work/tmp/dir1]$ terraform state pull
2021/10/09 04:46:26 [INFO] [migrator@/work/tmp/dir1] override backend to local
2021/10/09 04:46:26 [INFO] [executor@/work/tmp/dir1] create an override file
2021/10/09 04:46:26 [INFO] [migrator@/work/tmp/dir1] creating local workspace folder in: /work/tmp/dir1/terraform.tfstate.d/default
2021/10/09 04:46:26 [INFO] [executor@/work/tmp/dir1] switch backend to local
2021/10/09 04:46:28 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
2021/10/09 04:46:28 [DEBUG] [executor@/work/tmp/dir2]$ terraform version
2021/10/09 04:46:28 [INFO] [migrator@/work/tmp/dir2] terraform version: 1.0.8
2021/10/09 04:46:28 [INFO] [migrator@/work/tmp/dir2] initialize work dir
2021/10/09 04:46:30 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color
2021/10/09 04:46:30 [INFO] [migrator@/work/tmp/dir2] switch to remote workspace default
2021/10/09 04:46:30 [DEBUG] [executor@/work/tmp/dir2]$ terraform workspace select default
2021/10/09 04:46:30 [INFO] [migrator@/work/tmp/dir2] get the current remote state
2021/10/09 04:46:31 [DEBUG] [executor@/work/tmp/dir2]$ terraform state pull
2021/10/09 04:46:31 [INFO] [migrator@/work/tmp/dir2] override backend to local
2021/10/09 04:46:31 [INFO] [executor@/work/tmp/dir2] create an override file
2021/10/09 04:46:31 [INFO] [migrator@/work/tmp/dir2] creating local workspace folder in: /work/tmp/dir2/terraform.tfstate.d/default
2021/10/09 04:46:31 [INFO] [executor@/work/tmp/dir2] switch backend to local
2021/10/09 04:46:33 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
2021/10/09 04:46:33 [INFO] [migrator] compute new states (/work/tmp/dir1 => /work/tmp/dir2)
2021/10/09 04:46:33 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp663726483 -state-out=/tmp/tmp029937622 -backup=/dev/null aws_security_group.foo aws_security_group.foo
2021/10/09 04:46:33 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp097629501 -state-out=/tmp/tmp750478712 -backup=/dev/null aws_security_group.foo aws_security_group.foo2
2021/10/09 04:46:33 [DEBUG] [executor@/work/tmp/dir1]$ terraform state mv -state=/tmp/tmp022955639 -state-out=/tmp/tmp967913322 -backup=/dev/null aws_security_group.bar aws_security_group.bar
2021/10/09 04:46:33 [DEBUG] [executor@/work/tmp/dir2]$ terraform state mv -state=/tmp/tmp523533249 -state-out=/tmp/tmp424273964 -backup=/dev/null aws_security_group.bar aws_security_group.bar2
2021/10/09 04:46:33 [INFO] [migrator@/work/tmp/dir1] check diffs
2021/10/09 04:46:34 [DEBUG] [executor@/work/tmp/dir1]$ terraform plan -state=/tmp/tmp751284635 -out=/tmp/tfplan177173566 -input=false -no-color -detailed-exitcode
2021/10/09 04:46:34 [INFO] [migrator@/work/tmp/dir2] check diffs
2021/10/09 04:46:35 [DEBUG] [executor@/work/tmp/dir2]$ terraform plan -state=/tmp/tmp043938437 -out=/tmp/tfplan146169888 -input=false -no-color -detailed-exitcode
2021/10/09 04:46:35 [INFO] [executor@/work/tmp/dir2] remove the override file
2021/10/09 04:46:35 [INFO] [executor@/work/tmp/dir2] remove the workspace state folder
2021/10/09 04:46:35 [INFO] [executor@/work/tmp/dir2] switch back to remote
2021/10/09 04:46:37 [DEBUG] [executor@/work/tmp/dir2]$ terraform init -input=false -no-color -reconfigure
2021/10/09 04:46:37 [INFO] [executor@/work/tmp/dir1] remove the override file
2021/10/09 04:46:37 [INFO] [executor@/work/tmp/dir1] remove the workspace state folder
2021/10/09 04:46:37 [INFO] [executor@/work/tmp/dir1] switch back to remote
2021/10/09 04:46:39 [DEBUG] [executor@/work/tmp/dir1]$ terraform init -input=false -no-color -reconfigure
2021/10/09 04:46:39 [INFO] [migrator] start multi state migrator apply phase
2021/10/09 04:46:39 [INFO] [migrator@/work/tmp/dir2] push the new state to remote
2021/10/09 04:46:40 [DEBUG] [executor@/work/tmp/dir2]$ terraform state push /tmp/tmp887411455
2021/10/09 04:46:40 [INFO] [migrator@/work/tmp/dir1] push the new state to remote
2021/10/09 04:46:40 [DEBUG] [executor@/work/tmp/dir1]$ terraform state push /tmp/tmp543065682
2021/10/09 04:46:40 [INFO] [migrator] multi state migrator apply success!

yeah!!!

bash-5.0# cd ../dir2
bash-5.0# terraform state list
aws_security_group.bar2
aws_security_group.foo2

ash-5.0# terraform plan
aws_security_group.bar2: Refreshing state... [id=sg-8a179b01]
aws_security_group.foo2: Refreshing state... [id=sg-8dea8701]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the last "terraform apply":

  # aws_security_group.foo2 has been changed
  ~ resource "aws_security_group" "foo2" {
        id                     = "sg-8dea8701"
        name                   = "foo"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }
  # aws_security_group.bar2 has been changed
  ~ resource "aws_security_group" "bar2" {
        id                     = "sg-8a179b01"
        name                   = "bar"
      + tags                   = {}
        # (7 unchanged attributes hidden)
    }

Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan may
include actions to undo or respond to these changes.

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

No changes. Your infrastructure matches the configuration.
minamijoyo commented 3 years ago

Glad to hear that. I'll add an example for how to use multi_state mv. Thanks!

antigenius0910 commented 3 years ago

happy weekend!