Terraformで使える便利なテクニック
背景
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
は古い構文だそうで、現在は推奨されていません。)
最後に
ここであげたようなテクニックを駆使するとこのようなことが実現できます。
Discussion