Terraformの『terraform state mv』コマンドの具体的な動きについてメモ

## はじめに
Terraformのコマンドの1つに```terraform state mv```があります。

https://developer.hashicorp.com/terraform/cli/commands/state/mv?optInFrom=terraform-io

これはリソース名をリネームしたり、リソースブロックを移動したい場合に使うコマンドなのですが、コマンド実行後にStateがどうなっているのか、具体的な解説が見つからなかったので動かしながら検証してみることにしました。

※検証環境はAzureでローカルから実行しています。

## 事前準備

リポジトリは[こちら](https://github.com/hiroaki-saito/technical-investigation-terraform-state-mv)です。

まずはAzureにログインして、リソースを作成するサブスクリプションを設定します。

``` 
$ az login
$ az account set --subscription "サブスクリプション名"
```

developディレクトリで下記コマンドを実行、リソースグループとAppServicePlanを作成します。

```
$ terraform init
$ terraform plan
$ terraform apply
```

以上でAzure上にリソースが作成されました。

Stateファイルの中身は下記の通りとなります。

```develop/terraform.tfstate
{
  "version": 4,
  "terraform_version": "1.3.2",
  "serial": 3,
  "lineage": "XXXX",
  "outputs": {},
  "resources": [
    {
      "module": "module.common_app_service_plan",
      "mode": "managed",
      "type": "azurerm_service_plan",
      "name": "common_module_app_service_plan",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "app_service_environment_id": "",
            "id": "XXXX",
            "kind": "linux",
            "location": "japaneast",
            "maximum_elastic_worker_count": 1,
            "name": "plan-common-dev-je-001",
            "os_type": "Linux",
            "per_site_scaling_enabled": false,
            "reserved": true,
            "resource_group_name": "rg-common-dev-je-001",
            "sku_name": "B1",
            "tags": null,
            "timeouts": null,
            "worker_count": 1
          },
          "sensitive_attributes": [],
          "private": "XXX",
          "dependencies": [
            "module.common_resource_group.azurerm_resource_group.common_module_resource_group"
          ]
        }
      ]
    },
    {
      "module": "module.common_resource_group",
      "mode": "managed",
      "type": "azurerm_resource_group",
      "name": "common_module_resource_group",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "id": "XXXX",
            "location": "japaneast",
            "name": "rg-common-dev-je-001",
            "tags": null,
            "timeouts": null
          },
          "sensitive_attributes": [],
          "private": "XXXX"
        }
      ]
    }
  ],
  "check_results": []
}

```
<br>

これで事前準備は完了ですね。

あとは```terraform state mv```コマンドで、Stateがどういった動きになるのか検証していきます。

## ユースケース1：Terraform上のリソース名を変更したい

例えば、下記の```common_module_app_service_plan```の名前を変更したい場合にコマンドが使えます。

```module/app_service_plan/main.tf
resource "azurerm_service_plan" "common_module_app_service_plan" {
  name                = var.common_app_service_plan_config.name
~~~~~~省略~~~~~~
```

当然Stateファイルにも```common_module_app_service_plan```の名称が記載されています。

```develop/terraform.tfstate
~~~~~~省略~~~~~~
      "module": "module.common_app_service_plan",
      "mode": "managed",
      "type": "azurerm_service_plan",
      "name": "common_module_app_service_plan",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
~~~~~~省略~~~~~~
```

なので、普通にrenameしてしまうとTerraformとしては別物として扱われしまい、既存のものはdestoryとなり、新しくrenameしたリソースが作成されます。

ということで、これを回避するために```terraform state mv```コマンドを実行していきます。

### リソース名の変更

まずはじめに、リソース名を```hoge_module_app_service_plan```にします

```module/app_service_plan/main.tf
resource "azurerm_service_plan" "hoge_module_app_service_plan" {
  name                = var.common_app_service_plan_config.name
  resource_group_name = var.common_app_service_plan_config.resource_group_name
  location            = var.common_config.location
~~~~~~省略~~~~~~
```

### コマンドの実行

```terraform state mv```を実行します。
ちなみに```terraform state list```コマンドでリソース名を取得できます。
```
$ terraform state mv module.common_app_service_plan.azurerm_service_plan.common_module_app_service_plan module.common_app_service_plan.azurerm_service_plan.hoge_module_app_service_plan
```

State内のnameが変わっており無事成功しています。
破壊的なコマンドなので自動でバックアップが作成されるようです。

```develop/terraform.tfstate
~~~~~~省略~~~~~~
      "module": "module.common_app_service_plan",
      "mode": "managed",
      "type": "azurerm_service_plan",
      "name": "hoge_module_app_service_plan",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [
~~~~~~省略~~~~~~
```

## さいごに
眠いのでここまでにして、明日以降ここに追記していきます。