🎉
terraformでリソース名一括変更
背景
複数のリソースを管理している際、リソース名に共通の文言が入っている場合、複数のリソースに割り当てている文言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つの名称変更のみであること
-
terraform init
を実施 - コード上の変更したい名前に変更
resource "aws_api_gateway_rest_api" "example" {
# ->
resource "aws_api_gateway_rest_api" "example1" {
- 削除されるリソースと作成されるリソースを読み取り
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'
- 2で出力されたterraform state mvコマンドをコピー&ペーストで実施
-
terraform plan
を再度実施 - 差分が無いことを確認
Discussion