概要
terraform testとは?
v1.6から、terraform testコマンドが利用可能になりました。
HashiCorpブログ
terraform testコマンドを使用すれば、これから構築するリソースについて、指定した条件に沿っているかを簡単に確認することができます。
ユースケース
構築するリソースの詳細を知るためにはterraform planコマンドを使用するのが一般的かと思います。
ただ、たくさんのリソースを一気に作成するときなどはplanの結果もかなりの行数になり、想定外の構築内容になってしまっているのを見過ごしてしまうこともあるかと思います。
terraform testコマンドを利用すれば、重要な設定値などが正しく設定されているかを特に重点的にチェックすることができます。
例えば以下のようなユースケースが考えられます。
- 作成するインスタンスの元となるAMIのIDが合っているかの確認
- 作成後インスタンスのIPアドレスが合っているかの確認
- 指定のタグが正しくセットされているかの確認
(v1.6)terraform testを実際にやってみる
v1.6にてterraform testコマンドが追加され、v1.7でさらにアップデートがされましたが、まずはv1.6にてAWS構築の簡単な検証をやってみたいと思います。
その後、v1.7のモックでのテスト機能を検証します。
必要なもの
- 構築予定のリソースが定義されたterraformコード
- 今回はEC2インスタンス1台を構築するコードを作成しました
- テストしたい内容を記載したテスト用ファイル
- このファイルの名前は
.tftest.hclで終わる必要があります
- このファイルの名前は
検証の流れ
- EC2構築のTerraformコードを書く
- このとき、インスタンスのNameタグに値を設定する
- テスト用ファイルを書く
- テスト用ファイルでは、インスタンスのNameタグが指定の値になっているかをチェックする処理を記載する
- 今回はエラーの結果を見たいので、1のコードで設定したNameタグの値とは別の値かどうかを判定させる
terraform testコマンドを実行し、エラーになることを確認
1.EC2構築のTerraformコードを書く
まずはEC2インスタンスを構築するためのTerraformコードを書いていきます。
色々設定していますが、今回注目すべきはtagsブロックのNameタグです。
Nameタグに末尾test01を設定していますが、ここが後のテストで引っかかるようにします。
- ec2.tf
#####################################
# EC2 Instance
#####################################
resource "aws_instance" "test01" {
ami = var.test01.ami_test
instance_type = var.common.instance_type
subnet_id = aws_subnet.public_subnet_a.id
tenancy = "default"
key_name = aws_key_pair.test01.key_name
instance_initiated_shutdown_behavior = "stop"
monitoring = "true"
source_dest_check = "true"
disable_api_termination = "true"
vpc_security_group_ids = [aws_security_group.test01.id]
tags = {
Name = "${var.common.prefix}-${var.common.env}-test01"
owner = var.common.owner
}
}
2.テスト用ファイルを書く
続いて、テスト内容を記載したテスト用ファイルを書いていきます。
テスト用ファイルの記載方法についてはこちらを参照。
細かい記載方法は色々とありますが、代表的なものは下記の通りです。
- 少なくとも1つの
runブロックを記載する- テスト用ファイルにおいて一番重要なブロック
- Terraformは
runブロックを上から順番に実行し、runブロック内に記載されたコマンドの実行をシミュレートする
- 必要であれば、1つの
variablesブロックを記載する - 必要であれば、1つまたは複数の
providerブロックを記載する
runブロックの記載方法は下記の通りです。
commandフィールドを記載planかapplyか、どちらのコマンドを使ってテストするかを指定terraform plan,terraform applyと同様、planだったら実際の構築は行わずにテストし、反対にapplyだったら実際に構築処理を行ってテストした後、構築されたリソースは削除される- デフォルトは
apply
assertブロックを記載assertブロックはconditionとerror_messageで構成されるconditionではどうなっていたらOKと判定するかの条件を記載error_messageでは、OKでなかった場合に出力する文字列を記載
下記が今回作成したテスト用ファイルです。
runブロック:”valid_ec2_name_tag”を定義- 今回は実際の構築は行わないので、
commandにplanを設定 - conditionには、「インスタンスのNameタグが”sekiguchi-test-ap01″で終わるかどうか?」を記載
- 1で作成したコードではNameタグに別の値が設定されているので、ここでエラーになる想定
- error_messageでは、”Nameタグの値が予期した名前と一致しませんでした”を記載
ec2-nametag-check.tftest.hcl
run "valid_ec2_name_tag" {
command = plan
assert {
condition = aws_instance.test01.tags.Name == "sekiguchi-test-ap01"
error_message = "Nameタグの値が予期した名前と一致しませんでした"
}
}
3. terraform testコマンドを実行し、エラーになることを確認
1,2のファイルを同じフォルダに配置し、terraform initは実行済みです。
それではterraform testコマンドを実行し、エラーになることを確認していきます。
事前にAWSアカウントの認証を実行済みです。
※docker-composeを使用したterraformコマンド実行についてはこちらを参照
% docker-compose run --rm terraform test ec2-nametag-check.tftest.hcl... in progress run "valid_ec2_name_tag"... fail ╷ │ Error: Test assertion failed │ │ on ec2-nametag-check.tftest.hcl line 4, in run "valid_ec2_name_tag": │ 4: condition = aws_instance.test01.tags.Name == "sekiguchi-test-ap01" │ ├──────────────── │ │ aws_instance.test01.tags.Name is "sekiguchi-test-test01" │ │ Nameタグの値が予期した名前と一致しませんでした ╵ ec2-nametag-check.tftest.hcl... tearing down ec2-nametag-check.tftest.hcl... fail Failure! 0 passed, 1 failed.
テストファイルのconditionにて設定した条件に合っていないことを検知しFailure!となったこと、そしてerror_messageで設定したメッセージが出力されることを確認できました。
(v1.7)モックでのterraform testをやってみる
v1.7で追加されたモックでのテスト機能について
モックについての詳細はこちらを参照
Terraform v1.6で追加されたテストフレームワークでは、planまたはapply操作を使って実際にプロバイダー(今回はAWS)を呼び出すことで実行されていました。
v1.7からプロバイダー呼び出しのモック、つまり実際の呼び出しとは別に模擬的に呼びだすことができるようになり、実際のインフラを作成したりプロバイダー認証情報を要求したりすることなくテストができるようになりました。
このモックテストは、モック・プロバイダーとオーバーライドという2つの主要な機能によって可能となっています。
モック・プロバイダー
- フェイクのプロバイダーを意味しており、実際の構築時のプロバイダーとは別で定義が可能
- モックプロバイダーと実際の構築のためのプロバイダーを一緒に使うことで柔軟にテストが可能
mock_providerブロックにてモックプロバイダーを定義し、このブロック内でリソースやデータソースの値を指定できる
オーバーライド
- プロバイダーをモックした上で、特定のリソースをオーバーライドすることができる機能
- ユースケース
- プロビジョニングに時間がかかるリソースのテスト実行時間短縮
- 出力のシミュレーションのみ実行したい場合
- いろんなシナリオ用に、データソースの参照を多様化したい場合
必要なもの
v1.6で作成したものをそのまま利用します。
- 構築予定のリソースが定義されたterraformコード
- EC2インスタンス1台を構築するコード
- テストしたい内容を記載したテスト用ファイル
検証の流れ
v1.6のテストと同様の内容を、モック・プロバイダーを使用して実行していきます。
v1.6のテスト実行時はAWSアカウント認証を実行した上でterraform testコマンドを実行しましたが、モック・プロバイダーは模擬的にプロバイダー呼び出しを行うため、AWS認証は不要です。
そのため、AWS認証を実行していない状態でコマンドを打ってみて、テストが実行できるかを試してみたいと思います。
下記の流れで検証していきます。
- EC2構築のTerraformコードを書く
- 作成済み
- テスト用ファイルを書く
- テスト用ファイルでは、インスタンスのNameタグが指定の値になっているかをチェックする処理を記載する
- 今回はエラーの結果を見たいので、1のコードで設定したNameタグの値とは別の値かどうかを判定させる
terraform testコマンドを実行し、エラーになることを確認
コード作成
テスト用ファイルを今回の検証用に修正していきます。
上記の作成時からの変更点は下記の通りです。
- 冒頭に
mock_provider "aws" {}の1行を追加- この1行を記載することにより、このテストファイル内の処理はモックにて実行することが可能
runブロックからcommandフィールドを削除- HashiCorpのサイトに記載のある通り、mock_providerでのテスト時はリソースは実際に作成される
- これらのリソースは
terraform testが作成するTerraformステートファイルに格納され、テストを実行する間メモリに保持される
- これらのリソースは
- そのため
commandフィールドでの指定が不要
- HashiCorpのサイトに記載のある通り、mock_providerでのテスト時はリソースは実際に作成される
ec2-nametag-check.tftest.hcl
mock_provider "aws" {}
run "valid_ec2_name_tag" {
assert {
condition = aws_instance.test01.tags.Name == "sekiguchi-test-ap01"
error_message = "Nameタグの値が予期した名前と一致しませんでした"
}
}
terraform testコマンドを実行し、エラーになることを確認
それではterraform testコマンドを実行し、エラーになることを確認していきます。
AWSの認証を実行していない状態でterraform testコマンドを実行します。
terraform % docker-compose run --rm terraform test ec2-nametag-check.tftest.hcl... in progress run "valid_ec2_name_tag"... fail ╷ │ Error: Test assertion failed │ │ on ec2-nametag-check.tftest.hcl line 5, in run "valid_ec2_name_tag": │ 5: condition = aws_instance.test01.tags.Name == "sekiguchi-test-ap01" │ ├──────────────── │ │ aws_instance.test01.tags.Name is "sekiguchi-test-test01" │ │ Nameタグの値が予期した名前と一致しませんでした ╵ ec2-nametag-check.tftest.hcl... tearing down ec2-nametag-check.tftest.hcl... fail Failure! 0 passed, 1 failed.
先ほどと同様に、想定通りのエラーとなりました。
注目すべき観点としては、エラーの結果が返ってくるのがかなり早いということです。
モックを使用しない場合のテストでは裏でplanを実行しているためか、結果が返ってくるまでに30〜60秒ほどかかりましたが、モックを使用したテストの場合10秒とかからず結果が出力されます。
作成に時間がかかるインスタンスについてテストしたい場合に役に立ちそうだと思いました。
最後に
今回のテストを実行してみて、v1.7で追加されたモックでのテストはお手軽かつ結果がすぐ確認できるのが良いと思いました。
まだリリースされたばかりで有効な使い方が思いついていませんが、インフラ開発においてうまく使えると結構役に立つと思います。
例えば同一の環境を複数作成する時のチェック項目をテストファイルにまとめておき、そのテストファイルをプロジェクト内で共有することで各自で簡単にテストを実行できる…とかでしょうか。
Terraformでの開発時はデプロイ後の確認が結構大変なので、うまく活用していきたいと思いました。