Terraform AWS Provider v4.0.0 への変更を自動生成する

Terraform AWS Provider v4.0.0 では主にS3まわりのリソース定義に大きなBreaking Changeが入り、バージョンをアップデートする前に tf ファイルを書き換えていく必要があります。

書き換え方法は以下にまとまっています。

[Terraform AWS Provider Version 4 Upgrade Guide](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/guides/version-4-upgrade)

とは言っても、S3の定義はたくさんあるだろうし、手動で書き換えていくのはたいへんです。

自動で生成できないかと [hclwrite](https://pkg.go.dev/github.com/hashicorp/hcl/v2/hclwrite) を使ってツールを実装し始めていたのですが、このライブラリの使用例をGitHubで検索したところ、既に同じことをやっているツールが存在したのでご紹介します。

## tfrefactor

Repository: [tfmigrate](https://github.com/anGie44/ohmyhcl/tree/main/tfrefactor)

### インストール方法

バイナリでの提供はないので、Goのコードをビルドする必要があります。

```bash
git clone https://github.com/anGie44/ohmyhcl
cd ohmyhcl/tfrefactor
go build -o path/to/bin/tfrefactor
```

### 使い方

s3.tf というファイルに `aws_s3_bucket` の定義があったとします。

```hcl: s3.tf
resource "aws_s3_bucket" "example" {
  bucket = "test-test-test-test"

  cors_rule {
    allowed_methods = [
      "GET",
      "POST",
    ]
    allowed_origins = [
      "*",
    ]
  }

  logging {
    target_bucket = "test-log-bucket"
  }

  versioning {
    enabled = true
  }

  lifecycle_rule {
    enabled = false
    id      = "default"
    expiration {
      days = 10
    }
    transition {
      storage_class = "STANDARD_IA"
      days          = 5
    }
    noncurrent_version_expiration {
      days = 10
    }
    noncurrent_version_transition {
      days          = 5
      storage_class = "STANDARD_IA"
    }
  }
}

```

以下のようなコマンドで移行後の tf ファイルを生成できます。
特定のAttributeの移行を除外するとかリソース名を除外するとかのオプションがありますので、必要に応じて `tfrefactor resource --help` 等で確認しましょう。

```bash
tfrefactor resource -c aws_s3_bucket s3.tf
```

実行するとファイル名に `_migrated` が挿入された形でファイルが生成されます。
今回の例だと `s3_migrated.tf` になります。

```hcl: s3_migrated.tf
resource "aws_s3_bucket" "example" {
  bucket = "test-test-test-test"




}


resource "aws_s3_bucket_cors_configuration" "example_cors_configuration" {
  bucket = aws_s3_bucket.example.id
  cors_rule {
    allowed_methods = [
      "GET",
      "POST",
    ]
    allowed_origins = [
      "*",
    ]
  }
}

resource "aws_s3_bucket_lifecycle_configuration" "example_lifecycle_configuration" {
  bucket = aws_s3_bucket.example.id
  rule {
    status = "Disabled"
    id     = "default"
    expiration {
      days = 10
    }
    transition {
      storage_class = "STANDARD_IA"
      days          = 5
    }
    noncurrent_version_expiration {
      noncurrent_days = 10
    }
    noncurrent_version_transition {
      storage_class  = "STANDARD_IA"
      noncurent_days = 5
    }
  }
}

resource "aws_s3_bucket_logging" "example_logging" {
  bucket        = aws_s3_bucket.example.id
  target_bucket = "test-log-bucket"
}

resource "aws_s3_bucket_versioning" "example_versioning" {
  bucket = aws_s3_bucket.example.id
  versioning_configuration {
    status = "Enabled"
  }
}
```

`-c` オプションをつけることで新たに生成したリソースの一覧をCSVで出力することができます。
`terraform import` コマンドを使う時に有用だと思います。

```csv: s3_new_resource.csv
aws_s3_bucket_cors_configuration.example_cors_configuration,aws_s3_bucket.example
aws_s3_bucket_lifecycle_configuration.example_lifecycle_configuration,aws_s3_bucket.example
aws_s3_bucket_logging.example_logging,aws_s3_bucket.example
aws_s3_bucket_versioning.example_versioning,aws_s3_bucket.example
```


## 雑談

今回りファクタリングで別リソースに切り出された項目のいくつかは、私が6、7年前にコントリビュートしたものであるため、非常に感慨深く感じました。
もうこんなに経ったんだぁ......

* [versioning](https://github.com/hashicorp/terraform/pull/2942)
* [cors](https://github.com/hashicorp/terraform/pull/3387)
* [logging](https://github.com/hashicorp/terraform/pull/4482)
* [notification](https://github.com/hashicorp/terraform/pull/5473)
* [lifecycle](https://github.com/hashicorp/terraform/pull/6220)


## ChangeLog
* 2022-02-22: tfmigrateからtfrefactorに名前が変わっていた点を反映