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

Infrastructure as Code

冪等なリソース保証スクリプト

TT Labで続きを見る

目標

ディレクトリ・ファイル・行・権限を保証する冪等なスクリプトを作り、2回続けて適用して、changedが0になることで冪等性を証明します。状態ファイルとドリフトの検知、ロックまで付けます。

なぜ重要なのか

冪等性は、同じ作業を何度実行しても結果が同じになるという性質で、自動化を再実行しても安全だという保証です。証明方法は、2回適用して、2回目のplanが変更なしかどうかを見ることです。冪等性が崩れる場所は、ほぼ決まっています。専用のモジュールの代わりに、shellやcommandでコマンドを直接実行する場所と、>>で行を追記する場所です。そのため、このラボのスクリプトは、すべて「変更する前に確認する」という同じ骨格を持っています。最後に付ける状態ファイルとロックは、実際のIaCツールがなぜそのような付属機能を備えているのかを、体感で理解させてくれます。

ステップ

  1. /root/iac2/ensure_dir.sh <경로>を作成してください(プレースホルダーはパスです)。ディレクトリがなければ作成してchanged、すでにあればunchangedを出力します。どちらの場合も終了コードは0です。出力は、その単語だけを含む1行でなければなりません(採点は、unchangedを行全体と正確に比較します)。
  2. /root/iac2/ensure_file.sh <경로> <내용>を作成してください(プレースホルダーは、順にパスと内容です)。ファイルがないか、内容が違えば、内容を書き込んでchanged、すでに同じならunchangedを出力します。
  3. /root/iac2/ensure_line.sh <파일> "<줄>"を作成してください(プレースホルダーは、順にファイルと行です)。その行がすでに正確にあればunchanged、同じキー(行の最初の単語)を持つ別の行があれば、その場所を新しい行に置き換えてchanged、何もなければ末尾に追加してchangedを出力します。何回実行しても、該当の行はファイルにちょうど1つで、他の行はそのまま残っている必要があります。
  4. /root/iac2/ensure_mode.sh <파일> <8진수모드>を作成してください(プレースホルダーは、順にファイルと8進数のモードです)。stat -c %aで現在の権限を読み、違っていればchmodのあとにchanged、同じならunchangedを出力します。ファイルが存在しなければ、0ではない終了コードを返します。
  5. /root/iac2/run.shを作成してください。上の4つのスクリプトを使って、リソースをちょうど4つ保証します(例: ディレクトリ1+ファイル2+権限1)。最後の行に、要約をunchanged=<수> changed=<수>の順で出力します(プレースホルダーは件数です)。最初の実行の出力を/root/iac2/run1.txtに、続けて2回目の実行の出力を/root/iac2/run2.txtに保存します。最初の実行のchangedは1以上、2回目の実行の要約はunchanged=4 changed=0でなければなりません。
  6. /root/iac2/state.jsonを作成してください。resources配列に、先ほど保証したリソースを記録し(2個以上)、各要素にpath、type(fileまたはdir)、sha256を入れます。typeがdirではない項目は、実際のファイルが存在する必要があり、sha256の値がsha256sum <경로>の最初のフィールドとまったく同じでなければなりません(プレースホルダーはパスです)。最上位にapplied_at(適用時刻)も入れてください。
  7. /root/iac2/drift.sh <상태파일>を作成してください(プレースホルダーは状態ファイルです)。引数として受け取った状態ファイルを読み、記録されたリソースを検証します。すべて一致すれば終了コード0、内容が変わっていたりファイルが消えていたりすれば、食い違ったパスを出力して、0ではないコードを返します。typeがdirの項目は、存在するかどうかだけを確認します。
  8. /root/iac2/apply-lock.shを作成してください。ロックファイルのパスはLOCK_FILE環境変数で受け取り、なければ/root/iac2/.lockを使います。ロックがなければ、条件付きで作成して取得し、やるべきことを行ったあと、正常終了するときに必ず削除します(終了コード0で、ロックファイルが残ってはいけません)。すでにロックされていれば、待たずに終了コード2ですぐに失敗し、lockという単語が入ったメッセージを出力します。このとき、他者のロックファイルを削除してはいけません。

参考

ディレクトリを保証する

/root/iac2/ensure_dir.sh <경로>を作成してください(プレースホルダーはパスです)。ディレクトリがなければ作成してchanged、すでにあればunchangedを出力します。どちらの場合も終了コードは0です。出力は、その単語だけを含む1行でなければなりません(採点は、unchangedを行全体と正確に比較します)。

ensure_dir.sh <경로>は、なければ作成してchanged、すでにあればunchangedを出力します(プレースホルダーはパスです)。どちらも終了コードは0です。出力は、その1単語だけを含む1行でなければなりません。採点は、unchangedを行全体と正確に比較します。

ファイルの内容を保証する

/root/iac2/ensure_file.sh <경로> <내용>を作成してください(プレースホルダーは、順にパスと内容です)。ファイルがないか、内容が違えば、内容を書き込んでchanged、すでに同じならunchangedを出力します。

ensure_file.sh <경로> <내용>です(プレースホルダーは、順にパスと内容です)。書く前に、現在の内容と比較してください。なかったり違ったりすれば、書いてchanged、同じなら触れずにunchangedです。無条件に書くと、常にchangedになって、冪等性の証明が崩れます。

行を保証する(重複なしで)

/root/iac2/ensure_line.sh <파일> "<줄>"を作成してください(プレースホルダーは、順にファイルと行です)。その行がすでに正確にあればunchanged、同じキー(行の最初の単語)を持つ別の行があれば、その場所を新しい行に置き換えてchanged、何もなければ末尾に追加してchangedを出力します。何回実行しても、該当の行はファイルにちょうど1つで、他の行はそのまま残っている必要があります。

ensure_line.sh <파일> "<줄>"です(プレースホルダーは、順にファイルと行です)。>>で追記すると、実行するたびに行がたまります。同じ行がすでにあればunchanged、同じキー(最初の単語)の別の行があれば、その場所を置き換えてchanged、なければ末尾に追加してchangedです。他の行はそのまま残っている必要があります。

権限を保証する

/root/iac2/ensure_mode.sh <파일> <8진수모드>を作成してください(プレースホルダーは、順にファイルと8進数のモードです)。stat -c %aで現在の権限を読み、違っていればchmodのあとにchanged、同じならunchangedを出力します。ファイルが存在しなければ、0ではない終了コードを返します。

ensure_mode.sh <파일> <8진수모드>は、stat -c %aで現在の権限を読んで比較します(プレースホルダーは、順にファイルと8進数のモードです)。違えばchmodのあとにchanged、同じならunchangedです。ないファイルにchmodを試みて成功したと報告してはいけないので、存在確認を先に行ってください。

2回実行して冪等性を証明する

/root/iac2/run.shを作成してください。上の4つのスクリプトを使って、リソースをちょうど4つ保証します(例: ディレクトリ1+ファイル2+権限1)。最後の行に、要約をunchanged=<수> changed=<수>の順で出力します(プレースホルダーは件数です)。最初の実行の出力を/root/iac2/run1.txtに、続けて2回目の実行の出力を/root/iac2/run2.txtに保存します。最初の実行のchangedは1以上、2回目の実行の要約はunchanged=4 changed=0でなければなりません。

run.shでリソースをちょうど4つ保証し、最後の行にunchanged=<수> changed=<수>の順で要約を出力します(プレースホルダーは件数です)。順序が重要です。最初の実行の出力は/root/iac2/run1.txtに、続けて2回目の実行の出力は/root/iac2/run2.txtに保存してください。

状態ファイルを残す

/root/iac2/state.jsonを作成してください。resources配列に、先ほど保証したリソースを記録し(2個以上)、各要素にpath、type(fileまたはdir)、sha256を入れます。typeがdirではない項目は、実際のファイルが存在する必要があり、sha256の値がsha256sum <경로>の最初のフィールドとまったく同じでなければなりません(プレースホルダーはパスです)。最上位にapplied_at(適用時刻)も入れてください。

/root/iac2/state.jsonに、先ほど適用したリソースを記録します。各要素はpath、type、sha256を持ち、ファイル項目のハッシュは、sha256sum <경로>の最初のフィールドとまったく同じでなければなりません(プレースホルダーはパスです)。最上位にapplied_atも入れてください。run.shを実行したあとに作らないと、ハッシュが合いません。

ドリフトを検知する

/root/iac2/drift.sh <상태파일>を作成してください(プレースホルダーは状態ファイルです)。引数として受け取った状態ファイルを読み、記録されたリソースを検証します。すべて一致すれば終了コード0、内容が変わっていたりファイルが消えていたりすれば、食い違ったパスを出力して、0ではないコードを返します。typeがdirの項目は、存在するかどうかだけを確認します。

drift.sh <상태파일>は、引数として受け取った状態ファイルを読みます(プレースホルダーは状態ファイルです)。パスをハードコードすると、採点ツールが作る一時的な状態ファイルを読めません。内容の変更とファイルの削除のどちらも検出する必要があり、食い違ったパスを出力してこそ、人が何を見ればよいかがわかります。

状態をロックする

/root/iac2/apply-lock.shを作成してください。ロックファイルのパスはLOCK_FILE環境変数で受け取り、なければ/root/iac2/.lockを使います。ロックがなければ、条件付きで作成して取得し、やるべきことを行ったあと、正常終了するときに必ず削除します(終了コード0で、ロックファイルが残ってはいけません)。すでにロックされていれば、待たずに終了コード2ですぐに失敗し、lockという単語が入ったメッセージを出力します。このとき、他者のロックファイルを削除してはいけません。

apply-lock.shは、LOCK_FILE環境変数を尊重します。ロックがなければ条件付きで作成し、正常終了のときに必ず削除します(0)。すでにロックされていれば、待たずに終了コード2ですぐに失敗し、ロックが理由であることをメッセージで知らせます。他者のロックファイルは、決して削除しないでください。