レビューの差分が空白だらけになった
目標
書式の判定・構造の検査・式のコンソールの3つを、直接実行してみて、それぞれが何を捕まえ、何を捕まえられないかの境界を確認します。最後に、3つを束ねて、コミット前に動くゲートを手で作ります。
なぜ重要なのか
適用してみなければわからないことと、適用する前にわかることを分けるのが、このモジュールのテーマです。書式は、ツールが正解を1つに決めてあるので、人が議論する必要がありません。判定だけを行うモードが別にあり、終了コードが違って出るので、そのままゲートになります。構造の検査は、設定ファイルだけを読んで、参照が存在するか、必須の引数があるか、型がスキーマと合っているかを見ます。状態も実物も見ないので、値が間違っていることは捕まえられません。その境界を知らないと、2つの事故が起きます。1つは、通ったから安全だと信じることで、もう1つは、静的な検査で捕まえられるものを、プランまで引っ張って、時間を無駄にすることです。コンソールは、その間を埋めます。紛らわしい式1つのために、適用を繰り返す代わりに、1行で値を確認します。
ステップ
/root/tfb-fmt/src/main.tfと/root/tfb-fmt/src/modules/net/main.tfを作成して、インデントと等号の位置揃えを、わざとずらして書いてください。/root/tfb-fmt/srcでtofu fmt -check -diff -recursiveを実行して、出力を/root/tfb-fmt/fmt-before.txtに保存し、最後の行にexit=<종료 코드>を追記してください(プレースホルダーは終了コードです)。/root/tfb-fmt/srcで、tofu fmt -recursiveで実際に直して、直されたファイル名の一覧を/root/tfb-fmt/fmt-files.txtに保存してください。そのあと、tofu fmt -check -recursiveをもう一度実行して、出力とexit=<종료 코드>を/root/tfb-fmt/fmt-after.txtに保存してください。/root/tfb-fmt/broken/main.tfに、値が抜けた引数(例:filename =のあとに何もない)を置いて、文法を壊してください。そのディレクトリでtofu fmt -check -recursiveを実行して、出力とexit=<종료 코드>を/root/tfb-fmt/fmt-broken.txtに保存してください。このファイルは直さずに、そのままにしておきます。/root/tfb-fmt/invalid/main.tfに、宣言していない変数を参照するリソースと、文字列の場所にリストを入れたリソースを一緒に置いて、initしてください。tofu validate -jsonの出力を/root/tfb-fmt/validate.jsonに保存し、そこから読み取った値で、/root/tfb-fmt/validate-summary.txtに、errors=<오류 개수>とsummaries=<요약들을 사전순으로 콤마로 이은 것>の2行を書いてください(プレースホルダーは、順にエラーの個数と、要約を辞書順にカンマでつないだものです)。/root/tfb-fmt/blind/main.tfに、デフォルト値のない変数seed_pathと、そのパスをfile()で読んでファイルを作るリソースを置いて、initしてください。tofu validateは通過するのに、tofu planは2つの理由で失敗します。値を与えないplanと、存在しないパスを与えたplanを、それぞれ実行して、後ろのほうの出力を/root/tfb-fmt/blind-plan.txtに保存し、/root/tfb-fmt/blind-report.txtに、validate=<종료 코드>、plan_novar=<종료 코드>、plan_missing=<종료 코드>の3行を書いてください(プレースホルダーは終了コードです)。存在しないパスには./inputs/seed.txtを与え、そのファイルは作らないでください。/root/tfb-fmt/srcをinitして、/root/tfb-fmt/console-in.txtに、4行の式を書いてください。join("-", [var.env, var.app, "01"])、length(toset(["a", "a", "b"]))、"5" + 5、1 == "1"です。そのファイルをtofu consoleに流し込んで、結果を/root/tfb-fmt/console-out.txtに保存してください。/root/tfb-fmt/src/name.tfに、local.nameを、ステップ6の最初の式とまったく同じに定義して、その値を1行で書くlocal_file.nameで、name.txtを作成してください。新しいファイルも書式が合っている必要があり(fmt -check -recursiveが0)、validateが通過して、applyまで終える必要があります。/root/tfb-fmt/precheck.shを作成してください。最初の引数として受け取ったディレクトリに対して、書式の判定を先に行い、通過したら構造の検査を行います。書式で引っかかればfmtという1単語を出力して、0ではないコードで、構造で引っかかればvalidateを出力して、0ではないコードで、どちらも通過すればokを出力して、0で終了する必要があります。/root/tfb-fmt/srcに実行した結果を/root/tfb-fmt/precheck-src.txtに、/root/tfb-fmt/brokenに実行した結果を/root/tfb-fmt/precheck-broken.txtに保存して、各ファイルの末尾にexit=<종료 코드>を追記してください(プレースホルダーは終了コードです)。
参考
tofu fmtは、判定だけを行うモードと、実際に直すモードが違います。ゲートには、リポジトリを変更しないほうを使います。tofu validateとtofu consoleは、プロバイダーのスキーマが必要なので、initを先に行う必要があります。tofu fmtは、initなしでも動きます。- よくある間違い: ステップ3の壊れたファイルを、直してしまうこと。このステップは、読み取れないファイルのときの終了コードを残すことが課題です。
- よくある間違い: ステップ5で、
./inputs/seed.txtを作って、planを成功させてしまうこと。このステップは、静的な検査が見られないものを示すことが課題です。 - tofu fmt・tofu validate・tofu console・関数の一覧・terraform fmt (HashiCorp)
書式が乱れたツリーを見つけ出す
/root/tfb-fmt/src/main.tfと/root/tfb-fmt/src/modules/net/main.tfを作成して、インデントと等号の位置揃えを、わざとずらして書いてください。/root/tfb-fmt/srcでtofu fmt -check -diff -recursiveを実行して、出力を/root/tfb-fmt/fmt-before.txtに保存し、最後の行にexit=<종료 코드>を追記してください(プレースホルダーは終了コードです)。
このコマンドは、ファイルを直さず、判定だけを行います。直すものがあるときの終了コードが0と違うという点が、ゲートとして使える理由です。-diffは、何をどう直すかを表示します。
直してから、もう一度確認する
/root/tfb-fmt/srcで、tofu fmt -recursiveで実際に直して、直されたファイル名の一覧を/root/tfb-fmt/fmt-files.txtに保存してください。そのあと、tofu fmt -check -recursiveをもう一度実行して、出力とexit=<종료 코드>を/root/tfb-fmt/fmt-after.txtに保存してください。
直すモードは、変更したファイルの名前だけを1行ずつ出力します。サブディレクトリまで回るオプションがなければ、ルートのファイルだけを見ます。両方が一覧に入っている必要があります。
文法が壊れたファイルは、書式の判定と終了コードが違うことを確認する
/root/tfb-fmt/broken/main.tfに、値が抜けた引数(例: filename =のあとに何もない)を置いて、文法を壊してください。そのディレクトリでtofu fmt -check -recursiveを実行して、出力とexit=<종료 코드>を/root/tfb-fmt/fmt-broken.txtに保存してください。このファイルは直さずに、そのままにしておきます。
書式を直すには、まずファイルを読み取れる必要があります。読み取れないときの終了コードは、「直すものがある」とまた違います。ゲートを作るとき、この2つをひとまとめに扱ってよいかを、考えてみてください。
validateが捕まえるもの: 参照・必須の引数・型
/root/tfb-fmt/invalid/main.tfに、宣言していない変数を参照するリソースと、文字列の場所にリストを入れたリソースを一緒に置いて、initしてください。tofu validate -jsonの出力を/root/tfb-fmt/validate.jsonに保存し、そこから読み取った値で、/root/tfb-fmt/validate-summary.txtに、errors=<오류 개수>とsummaries=<요약들을 사전순으로 콤마로 이은 것>の2行を書いてください(プレースホルダーは、順にエラーの個数と、要約を辞書順にカンマでつないだものです)。
validateは、値ではなく構造を見ます。参照が存在するか、必須の引数があるか、入れた値の型がスキーマと合っているかです。-jsonを使えば、人ではなくCIが読めます。
validateが捕まえられないもの: 値
/root/tfb-fmt/blind/main.tfに、デフォルト値のない変数seed_pathと、そのパスをfile()で読んでファイルを作るリソースを置いて、initしてください。tofu validateは通過するのに、tofu planは2つの理由で失敗します。値を与えないplanと、存在しないパスを与えたplanを、それぞれ実行して、後ろのほうの出力を/root/tfb-fmt/blind-plan.txtに保存し、/root/tfb-fmt/blind-report.txtに、validate=<종료 코드>、plan_novar=<종료 코드>、plan_missing=<종료 코드>の3行を書いてください(プレースホルダーは終了コードです)。存在しないパスには./inputs/seed.txtを与え、そのファイルは作らないでください。
静的な検査は、設定ファイルだけを読みます。変数にどんな値が入ってくるか、そのパスにファイルがあるかは、設定ファイルの外の事実なので、知ることができません。そのため、validateに通ったことは、「適用してよい」という意味ではありません。
式はコンソールで1行で確認する
/root/tfb-fmt/srcをinitして、/root/tfb-fmt/console-in.txtに、4行の式を書いてください。join("-", [var.env, var.app, "01"])、length(toset(["a", "a", "b"]))、"5" + 5、1 == "1"です。そのファイルをtofu consoleに流し込んで、結果を/root/tfb-fmt/console-out.txtに保存してください。
コンソールは、現在のディレクトリの変数とlocalsを、そのまま読みます。後ろの2行は、わざと紛らわしくしたものです。足し算で起きる変換と、等しいかの比較で起きない変換が、違います。
確認した式を設定に入れる
/root/tfb-fmt/src/name.tfに、local.nameを、ステップ6の最初の式とまったく同じに定義して、その値を1行で書くlocal_file.nameで、name.txtを作成してください。新しいファイルも書式が合っている必要があり(fmt -check -recursiveが0)、validateが通過して、applyまで終える必要があります。
コンソールで確認した式をそのまま移せば、値が合っているかを、また悩む必要がありません。ファイルを新しく作ったので、書式の判定も、もう一度通過する必要があります。ゲートを作る前に、身につけておくべき順序です。
コミット前に動く、静的な検査のゲートを作る
/root/tfb-fmt/precheck.shを作成してください。最初の引数として受け取ったディレクトリに対して、書式の判定を先に行い、通過したら構造の検査を行います。書式で引っかかればfmtという1単語を出力して、0ではないコードで、構造で引っかかればvalidateを出力して、0ではないコードで、どちらも通過すればokを出力して、0で終了する必要があります。/root/tfb-fmt/srcに実行した結果を/root/tfb-fmt/precheck-src.txtに、/root/tfb-fmt/brokenに実行した結果を/root/tfb-fmt/precheck-broken.txtに保存して、各ファイルの末尾にexit=<종료 코드>を追記してください(プレースホルダーは終了コードです)。
順序が重要です。読み取れないファイルが混ざっていると、構造の検査も意味がないので、書式の判定が先です。判定だけを行い、直さないオプションを使わないと、ゲートがリポジトリを変更してしまいます。