はじめに
terraformでインフラ運用している中で、credentials情報をローカルに持てない等のセキュリティポリシーが理由でローカル(コーディング環境)からterraform実行できないケースがあると思います。
そんなとき、書式ミスや変数参照ミスなどをterraform実行環境にデプロイしてみないとわからないのは、非効率ですよね。仮にデプロイをパイプライン等で自動化していても、パイプライン実行の待ち時間が無駄ですし、タイポなどのしょうもないミスでcommit履歴が汚れるのは微妙です。。
そこで、gitのpre-commit機能を利用してcommit前にterraform fmt/init/validate
を自動実行するようにしてみました。これによりコマンドが成功した場合のみcommitされ、失敗した場合は、commitされずにエラー内容が出力されます。
うまく動かない等があれば、コメントいただければと思います。
実行例
成功例
$ git commit -m "test"
Directory: terraform/ terraform fmt: Passed
Directory: terraform/ terraform init: Passed
Directory: terraform/ terraform validate: Passed
Directory: terraform/environment/iam/ terraform fmt: Passed
Directory: terraform/environment/iam/ terraform init: Passed
Directory: terraform/environment/iam/ terraform validate: Passed
Directory: terraform/environment/lambda/ terraform fmt: Passed
Directory: terraform/environment/lambda/ terraform init: Passed
Directory: terraform/environment/lambda/ terraform validate: Passed
[master 9b47d9e] test
8 files changed, 77 insertions(+), 14 deletions(-)
create mode 100644 terraform/environment/iam/dev.tfvars
create mode 100644 terraform/environment/iam/prd.tfvars
create mode 100644 terraform/environment/iam/variables.tf
create mode 100644 terraform/environment/lambda/variables.tf
失敗例
$ git commit -m "test"
Directory: terraform/ terraform fmt: Passed
Directory: terraform/ terraform init: Passed
Directory: terraform/ terraform validate: Passed
Directory: terraform/environment/iam/ terraform fmt: Passed
Directory: terraform/environment/iam/ terraform init: Passed
Directory: terraform/environment/iam/ terraform validate: Passed
Directory: terraform/environment/lambda/ terraform fmt: Passed
Directory: terraform/environment/lambda/ terraform init: Passed
Error: Missing required argument
on main.tf line 16, in module "get_lambda":
16: module "get_lambda" {
The argument "memory_size" is required, but no definition was found.
Error: Unsupported argument
on main.tf line 23, in module "get_lambda":
23: memory_sze = 256
An argument named "memory_sze" is not expected here. Did you mean
"memory_size"?
Directory: terraform/environment/lambda/ terraform validate: Failed
実行環境
- WSL (Ubuntu 18.04)
- git version 2.17.1
- Terraform v0.12.19
準備から実行まで
準備1. terraformインストール
使用しているversionに合わせたterraformをこちらからインストールします。
(すでにインストール済みの場合は不要)
準備2. .gitignore
に.terraform/
を追加
ローカルでterraform init
するので、.terraform/
配下にpluginやmoduleがインストールされます。
これらはgit管理する必要がないので.gitignore
ファイルに以下を追加します。
(すでに記載済みの場合は不要)
.terraform/
準備3. pre-commit
ファイルを配置
.git/hooks
にpre-commit
というファイル名で以下の内容を配置する
#!/bin/bash -u
work_dir=`pwd`
# 戻り値チェック
check_return_code() {
cmd_name="$1"
dir_name="$2"
rc=$3
if [ ${rc} -eq 0 ];then
echo "Directory: ${dir_name} terraform ${cmd_name}: Passed"
else
echo "Directory: ${dir_name} terraform ${cmd_name}: Failed"
exit 1
fi
}
# terraform実行ディレクトリを抽出する.
# .tfファイルを含むディレクトリ名を変数target_dirに格納. .tfstate及びmoduleは除外.
target_file=$(git diff --cached --name-only --diff-filter=AMRC | grep -E ".tf$|.tfvars$")
if [ -n "${target_file}" ]; then
target_dir=$(echo ${target_file} | xargs dirname | sort -u)
else
echo "No change in TF file."
exit 0
fi
# terraform init/validate
for dir in ${target_dir}
do
cd ${work_dir}/${dir} || exit 1
# terraform fmt
fmt_file=$(terraform fmt)
check_return_code fmt ${dir} $?
# fmtにより変更されたファイルをstageする.
if [ -n "${fmt_file}" ];then
cd ${work_dir}
for file in ${fmt_file}
do
git add ${dir}/${file}
done
cd ${dir}
fi
# terraform init
terraform init -backend=false 1>/dev/null
check_return_code init ${dir} $?
# terraform validate
terraform validate 1>/dev/null
check_return_code validate ${dir} $?
#exit 1
done
実行
上記実施後にcommitすると、実行例のようにterraform fmt/init/validate
が変更対象のディレクトリごとに実行されます。
注意点
tf version 0.11以前でtfvarsファイルを使用している場合、terraform validateでエラーになります。
その場合、-var-fileオプションでtfvarsを明示的に指定する必要があります。