TT Lab
はじめる
学ぶ 学習パス コース

Terraform/OpenTofu基礎

値を作る側の文法

TT Labで続きを見る

一言でいうと

組み込み関数は、設定ファイルで値を計算して作れるようにしてくれて、その結果は、適用してみる前に、コンソールで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つも直接書かない設定を作って、採点ツールが別の入力で適用しても、結果がついてくるかを確認します。