値を作る側の文法
一言でいうと
組み込み関数は、設定ファイルで値を計算して作れるようにしてくれて、その結果は、適用してみる前に、コンソールで1行で確認できます。
なぜ関数が必要だったのか
宣言的な設定の第一印象は、「値をそのまま書く」です。ところが、少し大きくなると、そのまま書けないものが出てきます。名前は、環境とサービスと番号を組み合わせて作り、タグは、共通の分と個別の分を合わせて作り、ポートは、環境によって違います。これを値として書くと、環境が1つ増えるたびに、直す箇所があちこちに散らばります。
さらに悪いのは、手でつないだシリアライズです。JSONの設定を、文字列の足し算で作ると、引用符とエスケープを人が責任を持つことになり、値にダブルクォートが1つ入った瞬間に壊れます。そのため、言語の中に関数が入ってきました。
どう動くのか
関数は、大きくいくつかの系統に分かれます。文字列を扱うもの、コレクションを扱うもの、型を変えるもの、失敗を扱うもの、そしてテンプレートとシリアライズです。
join("-", ["web", "prod", "01"]) -> "web-prod-01"
format("%s-%03d", "node", 7) -> "node-007"
merge({ a = 1 }, { a = 9, b = 2 }) -> { a = 9, b = 2 } 뒤가 이긴다
lookup({ web = 80 }, "api", 0) -> 0 없으면 기본값
distinct(["a", "b", "a"]) -> ["a", "b"]
formatlist("%s=%d", names, ports) -> 두 목록을 나란히 돌며 서식 적용
条件式は、조건 ? 참일때 : 거짓일때の形です(プレースホルダーは、順に条件、真のとき、偽のときです)。2つの枝の型が同じである必要があり、違うと、ツールが1つに合わせようとして、思わぬ変換が生じます。
失敗を扱う2つの関数は、性格が違います。tryは、前の引数の評価が失敗したら、次の引数を返し、canは、成功したかどうかを真偽に変えます。重要な制限があります。どちらも、実行中に生じるエラーだけを捕まえます。 宣言すらない変数やlocalsを参照するのは、静的なエラーなので、tryでも包めません。
locals {
cfg = try(jsondecode(file("${path.module}/in.json")), {}) # 깨진 JSON 이면 빈 맵
name = try(local.cfg.name, "unknown") # 키가 없으면 기본값
}
テンプレートは、値が複数あるときに使います。テンプレートファイルの中で、繰り返しと条件のディレクティブを使えて、ディレクティブの行が、結果に空行として残らないように、空白除去マーカーを付けます。
%{ for p in ports ~}
listen ${p};
%{ endfor ~}
シリアライズの関数は、値をJSONやYAMLの表記に移します。手で引用符を付けなくてよく、何よりも、読み直すと同じデータが出てきます。 同じマップを2つの関数で出力して、それぞれ読み直してみれば、まったく同じであることが確認できます。
型変換の関数は、静かな失敗がないのがよい点です。変換できない値に出会うと、その場でエラーを出します。
tonumber("007") -> 7
parseint("ff", 16) -> 255
tostring(true) -> "true"
tonumber("abc") -> 오류
try(tonumber("abc"), -1) -> -1
そして、これらすべてを、適用なしで確認する場所が、コンソールです。コンソールは、現在のディレクトリの変数とlocalsを読むので、設定を直さなくても、別の変数の値で、別の分岐を評価してみることができます。
現場での姿
最もよく見るのは、lookupのデフォルト値を抜かしたコードです。マップにキーが常にあると信じて書くと、新しい環境を追加した日に、その環境でだけ適用が止まります。デフォルト値を与える習慣1つで、この種の事故が丸ごとなくなります。
2つ目は、tryを盾と誤解する場合です。値がおかしいときに、静かにデフォルト値に落ち着くことが、常に正しいとは限りません。設定が間違っているのに、デフォルト値で適用が成功してしまうと、問題は、数週間後に本番で明らかになります。外から入ってくるデータには使い、自分たちのリポジトリの中の値には使わないほうがよいです。
3つ目は、テンプレートを使わずに、文字列をつないだ設定です。最初は短くて問題なさそうに見えますが、条件が2つ入るだけで、読めなくなります。複数行の成果物は、テンプレートファイルに切り出せば、そのファイルだけを見て、結果を推測できます。
次のラボですること
8つのステップを進めます。文字列関数6つをコンソールで確認し、マップを合成したり取り出したりする関数を、実際の出力として出し、条件式で環境ごとの値を選びます。続けて、壊れたJSONを吸収する設定を作り、テンプレートで6行の設定ファイルを出力し、同じデータを2つの形式で出力して、読み直したときに同じかを確認します。最後の2つのステップでは、変換関数とその失敗を確認し、値を1つも直接書かない設定を作って、採点ツールが別の入力で適用しても、結果がついてくるかを確認します。