🎉

terraformでリソース名一括変更

2024/09/26に公開

背景

複数のリソースを管理している際、リソース名に共通の文言が入っている場合、複数のリソースに割り当てている文言Aを文言Bに一括変更したい。
通常、

resource "aws_api_gateway_rest_api" "example" {

resource "aws_api_gateway_rest_api" "example1" {

に変更してterraform applyすると旧リソース名が削除され、新リソース名が新規に作成されるが、terraform state mvを使ってリソース移動したい。

aws_api_gateway_rest_api.example
aws_api_gateway_resource.example
aws_api_gateway_method.example
aws_api_gateway_integration.example

この時、リファクタリング時に一括でexampleを違う名前に変更したい。

やること

前提: 1種類のリソースタイプに1つの名称変更のみであること

  1. terraform initを実施
  2. コード上の変更したい名前に変更
resource "aws_api_gateway_rest_api" "example" {
# ->
resource "aws_api_gateway_rest_api" "example1" {
  1. 削除されるリソースと作成されるリソースを読み取りterraform state mvコマンドを作成するスクリプトを実行
#!/bin/bash

# リソース名変更用のterraform state mvコマンドをplanから作成する
# ※リソースタイプ1種類につき1リソースしか無い場合に限る

# プランファイルの生成
terraform plan -out=tfplan.binary
plan_status=$?

# plan コマンドが失敗した場合、スクリプトを終了
if [ $plan_status -ne 0 ]; then
    echo "Terraform plan failed with status $plan_status"
    exit $plan_status
fi

# プランを読みやすい形式に変換
terraform show -json tfplan.binary > tfplan.json

# 一時ファイルの削除
rm tfplan.binary

# 削除されたリソースと作成されたリソースを対応付ける
jq -r '
    .resource_changes[]
    | select(.change.actions | index("delete") or index("create"))
    | [.address, .type, .change.actions[]]
    | @csv
' tfplan.json | awk -F, '
    {
        gsub(/"/, "", $1);
        gsub(/"/, "", $2);
        gsub(/"/, "", $3);
        if ($3 == "delete") {
            deletes[$1]=$2;
        }
        if ($3 == "create") {
            creates[$1]=$2;
        }
    }
    END {
        for (del in deletes) {
            for (create in creates) {
                if (deletes[del] == creates[create]) {
                    print "terraform state mv \x27"del"\x27 \x27"create"\x27";
                }
            }
        }
    }
' | while read line; do
    echo "$line"
done

# JSONファイルの削除
rm tfplan.json

出力結果

...
To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan.binary"
terraform state mv 'aws_api_gateway_rest_api.example' 'aws_api_gateway_rest_api.example1'
  1. 2で出力されたterraform state mvコマンドをコピー&ペーストで実施
  2. terraform planを再度実施
  3. 差分が無いことを確認

Discussion