意外と思い出せないTerraformの書き方まとめ
業務でTerraformをずっと書いているのですが、moduleとかを書くような時に「あれ?こういう時にHCLではどう書くんだっけ?そもそも書けるんだっけ?」ということを思うことが何回かあったので、そういったときに必要になった書き方のメモを残しておきます。
変数の型がリストで、そのリストの各要素が満たす条件を記述する
can関数とfor式を組み合わせてcustom variable validation rulesに使うと実現できます。
例えばAWSのSubnet IDのリストを変数に持っているときに活用できます。Subnet IDは頭にsubnet-
という文字列があると期待できるので、以下の様に書いて制約を付けられます。この条件から外れた変数を設定しているときはerror_message
に設定したエラーメッセージが出てくるので変数の設定ミスを防げます。
variable "subnet_ids" { type = list(string) validation { condition = can([for subnet_id in var.subnet_ids : regex("^subnet-", subnet_id)]) error_message = "Subnet ID must start with \"subnet-\"." } }
can関数が使えるところでは基本try関数を使った方がいいらしいですが、HashiCorpのドキュメントによるとこういったcustom variable validation rulesに使うのがcan関数の主な目的らしいです。
ある特定のパラメータが自作モジュールに与えられてないときは無視し、与えたときにはその値を設定する
nullが活用できます。
基本はdefaultにnullを設定すればいいけれど、既存のリソースの関係上こういう書き方をせざるを得ないときもありますね。
resource "aws_iam_role" "eks_node" { name = var.node_group_role_name != null ? var.node_group_role_name : "${var.name} # 省略 }
この場合、node groupのIAM role の名前を与えた場合は名前をそれに設定し、そうで無ければデフォルト扱いのvar.name
という値にするという書き方です。
フラグが偽の場合はリソースを作らず、フラグが真の時のみリソースを作る
countを使って以下の様に書けます
resource "aws_s3_bucket" "example" { count = var.enable_example ? 1 : 0 bucket = "example_bucket" }
${var.flag} ? 1 : 0
と三項演算子*1を使うところがポイント。
最初に書く条件はbool値を返せればいいので、以下の様にvar.parameters
というリストの長さを基準にしてリストが空だったらリソースを作らない、なんてことも可能。
count = length(var.parameters) > 0 ? 1 : 0
これの欠点は、作成されたリソースの指定の時にインデックスを明示しないといけないこと。
例えば上のS3バケットの例ではaws_s3_bucket.example[0]
と指定しないといけないです。
また、この技法をdynamic blockと組み合わせて以下の様に応用できます。
resource "aws_eks_node_group" "varanus" { for_each = var.node_groups # 省略 dynamic "remote_access" { for_each = length(each.value.config.security_group_ids) > 0 ? [each.value.config] : []
こういうのはあらかじめこういう書き方ができると知っておかないとできないタイプのやつですね。
オライリーの学習プラットフォームのサブスクに加入していてその関係で『詳解Terraform 第3版』を読めるので、他にも何か便利な書き方が無いかどうか、読んでみて調べようかなって思ってます。
Amazonはこちら。
*1:terraform的にはConditional Expressionsというらしい