🕶️
[Terraform小ネタ] 文字列をforする
Terraform でよく出てくるforについて
みなさんは Terrafor で resource や module を複数回ループさせたいときは for_each を使ってループ処理を行うかと思います。
以下の場合は、for_eachに変数として入ってくる数だけIAMユーザが作成されることになります。
hcl
resource "aws_iam_user" "the-accounts" {
for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
name = each.key
}
やりたかったこと
僕がやりたかったのは、 resource や module ではなく、文字列をforで生成したかったです。
例えば、Datadog の Monitor で、SlackやPagerDutyの通知のメッセージを作る時に、アプリケーションによって通知先を分けたい。という時ありますよね。
その場合は以下のように {{#is_match "service" "app-X"}}
のようなものが冗長だとダサいですよね。
そこで調べたら以下のような方法で実現できることがわかりましたので、忘備録と他の方の参考に記録しておきます。
hcl
resource "datadog_monitor" "monitor" {
name = var.name
type = var.type
query = var.query
----- 省略 ------
message = <<EOT
{{#is_match "env" "dev"}} @slack-dev {{/is_match}}
{{#is_match "service" "app-A"}}
{{#is_alert}} @pagerduty-app-A {{/is_alert}}
{{#is_recovery}} @pagerduty-app-A {{/is_recovery}}
{{/is_match}}
{{#is_match "service" "app-B"}}
{{#is_alert}} @pagerduty-app-B {{/is_alert}}
{{#is_recovery}} @pagerduty-app-B {{/is_recovery}}
{{/is_match}}
{{#is_match "service" "app-C"}}
{{#is_alert}} @pagerduty-app-C {{/is_alert}}
{{#is_recovery}} @pagerduty-app-C {{/is_recovery}}
{{/is_match}}
{{#is_match "service" "app-N"}}
{{#is_alert}} @pagerduty-app-N {{/is_alert}}
{{#is_recovery}} @pagerduty-app-N {{/is_recovery}}
{{/is_match}}
--- 以下省略 ---
EOT
}
結論
はい。以下のようにすることで実現できました。
hcl
variable "apps" {
type = list(string)
default = [
"app-A",
"app-B",
"app-C",
"app-N"
]
}
resource "datadog_monitor" "monitor" {
name = var.name
type = var.type
query = var.query
----- 省略 ------
message = <<EOT
{{#is_match "env" "dev"}} @slack-dev {{/is_match}}
%{ for app in var.apps ~}
{{#is_match "service" "${app}"}}
{{#is_alert}} @pagerduty-${app} {{/is_alert}}
{{#is_recovery}} @pagerduty-${app} {{/is_recovery}}
{{/is_match}}
%{ endfor ~}
EOT
}
解説
ループしたい範囲を %{ for xx in yy ~}
と %{ endfor ~}
で囲み、 yyに回したい複数の文字列を定義し、要素の数だけループ処理が行われます。
あとは xx の変数をfor内に書くくらいです。
以上、文字列をスマートにループする方法でした。
Discussion