🕌

Terraformで使える便利なテクニック

2022/09/03に公開

背景

terraformは独自の言語を使用しますが、冪等性を担保するためか、割と窮屈です。あんなことができたらとか思いつつ実現できないと諦めていないでしょうか? ドキュメントを読み込むと思わぬところに便利機能が隠れています。そこで私が見つけたものを紹介していこうと思います。

関数編

one()

リストの要素が

  • 1つの時、その要素が返ります。one()の名前の由来でしょう。
  • 空の時、nullが返ります。エラーにはならないため便利に使えます。
  • 2つ以上の時、エラーになります。

count = some_var ? 1 : 0 とリソース作成有無を分岐させている時にone()でいい感じにアクセスできるでしょう。

try()

他の言語によくあるtry-catch構文がterraformでは関数の形になっています。1つ目の式を評価し、エラーが発生したら2つ目の式が評価されます。
try(some_var.some_list, []) のようにデフォルト値を与えるのに使えます。ちなみにterraform 1.3.0でデフォルト値が正式機能となりますが、try()は式の途中で使えるので、まだまだ出番はあるでしょう。

can()

try()の簡単版です。式を評価して、エラーが起きないかを返します。
mapに特定のキーがあるかを判定する際、keys()でキー一覧を作成してcontains()で存在するか判定する、といったまどろっこしい手順を踏まなくてもcan(some_var.some_key)で得られます。
can(regex())で正規表現にマッチしたか否かの判定にも使えます。

toset()

listをsetに変換してくれます。自動的に重複を排除します。
for_eachに渡す際に使えるので、メジャーな方かもしれません。

構文編

if

他の言語によくあるif文ではなく、forループ内でフィルタリングのためにだけ使えます。他の言語によくあるif文としては三項演算子?:を使います。

インデックス付きループ

listに対してインデックス番号が欲しいなという時ありませんか? あります。mapに対してforループする際、keyとvalueを受け取れますが、listに対してforループする際、valueしか存在しないはずです。しかしmapと同様にkeyを受け取ろうとするとインデックス番号が得られます。
例えば { for i, v in some_list: "${i}" => v } で、キーがインデックス番号、値がlistの値となるmapに変換できます。

...

どうでもいいけどgooglability最悪ですね。...には2つの機能があります。

引数展開

function_name(list_var...) と書くと、listの中身を展開して関数が呼び出されます。concat()を呼び出したいけど既にlistになっちゃってるというときにflatten(list_var)に逃げずにconcat(list_var...)とできます。いえまぁ支障がなければflatten()に逃げればいいんですが。

グループ化

forループの結果をグループ化できます。

[*]

こちらも2つの機能があります。

リスト化

listかもしれないし、objectかもしれない。objectだったら単一要素のlistに変換したい、という場合に some_var[*] でリスト化できます。

splatting

リストの各要素の同じメンバーを取り出したいというとき、forでループしますよね? 実はこれ [for it in some_list: it.member]some_list[*].member で取り出せます。
some_list.*.memberは古い構文だそうで、現在は推奨されていません。)

最後に

ここであげたようなテクニックを駆使するとこのようなことが実現できます。

https://zenn.dev/sayurin/articles/646a3254520519

Discussion