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

FDE総合演習:倉庫に同じ注文が3回届いた

インストールは完了と出たのに、エージェントは起動直後に落ちた

TT Labで続きを見る

目標

顧客のホストのインストール要件をチェックし、pass・warn・failをJSONの報告書と終了コードで出す、事前チェックのスクリプトを作ります。採点ツールが用意したさまざまな環境で判定が正しく、チェックは何も直してはいけません。

なぜ重要なのか

顧客の現場のインストールの時間枠は、一度きりの場合が多いです。前回のインストールは「完了」で終わりましたが、ポートは社内プロキシが使っていて、証明書はすでに期限が切れていました。事前チェックは、こうした事実を、インストールの前に根拠とともに明らかにするツールです。 判定だけでなく観測値を残してはじめて、顧客の担当者が確認し直せ、終了コードが一定であってはじめて、インストールの自動化が、続行と中断を分けられます。 採点ツールは、あなたの文言を信じません。一時ディレクトリに、占有されたポート・TIME_WAITのポート・期限間近または期限切れの証明書・存在しないディレクトリを自分で作り、ポート番号・基準値・パスを実行のたびに変えて、スクリプトを実行します。

ステップ

  1. 顧客メモを読み、要件7種を、契約のキー名で記録します(ファイル: /root/preflight/spec.json)。古い文書の値と、サポートのポリシーを区別します。
  2. python_minとportsのチェック、報告書(summary・exit_code・checks)、終了コード0・1・2を実装します(ファイル: /root/preflight/preflight.py)。仕様にないキーのチェックは行いません。
  3. preflight.pyのポートのチェックが、TIME_WAITだけが残ったポートを、使用中と誤検出しないように直します。リッスンしているポートは、引き続きfailでなければなりません。
  4. preflight.pyに、diskのチェックを入れます。空きMiBをobservedに、測ったパスをmeasured_pathに書き、まだないパスは作らずに、最も近い親を測ります。
  5. preflight.pyに、certsのチェックを入れます。notAfterをエポック秒でobservedに、残り日数をdays_leftに書き、期限切れ・読めない場合はfail、warn_days未満はwarnです。
  6. preflight.pyに、files・hosts・writable_dirsのチェックを入れます。observedは契約の状態名を使い、書き込みの試験のファイルは消し、存在しないディレクトリは作りません。
  7. 正常・警告・失敗のホストの完全な仕様と、壊れた仕様を区別できるかを確認します。終了コードは0・1・2で、仕様を読めない場合は、報告書なしで3です。
  8. spec.jsonでこのホストをチェックして、報告書を残し(ファイル: /root/preflight/report.json)、報告書のハッシュ・判定(go・go-with-warnings・no-go)・blockers・warningsを記録します(ファイル: /root/preflight/decision.json)。

参考

顧客メモを仕様に移す

顧客メモの要件7種を、契約のキー名で記録してください(ファイル: /root/preflight/spec.json)。

メモには、古い文書の値と、「動くには動いた」という体験談が混ざっています。チェックの基準は、今回のバージョンと、サプライヤーのサポートのポリシーです。ポートは整数の配列、disk・certsはオブジェクトの配列です。

Pythonのバージョンとポートから判定する

python_min・portsをチェックし、報告書と終了コード0・1・2を出すようにしてください(ファイル: /root/preflight/preflight.py)。

ポートが空いているかは、0.0.0.0に実際にbindしてみればわかります。バージョンの比較は、sys.version_infoと整数のタプルで行います。summaryは、failが1つでもあればfailです。採点ツールは、毎回異なるポートとバージョンの基準で実行します。

終わった接続を占有と誤検出しない

ポートのチェックが、TIME_WAITだけが残ったポートはfree、リッスンしているポートはin_useと区別するようにしてください(ファイル: /root/preflight/preflight.py)。

サーバー側が先に閉じた接続は、そのポートにTIME_WAITを残します。オプションなしのbindは、これも妨げられます。ソケットオプション1つで、TIME_WAITは通過し、本物のリスナーは引き続き妨げられるようにできます。

空き容量を警告と失敗に分ける

diskのチェックを入れ、observed(空きMiB)・measured_path・pass/warn/failを出すようにしてください(ファイル: /root/preflight/preflight.py)。

shutil.disk_usageのfreeを1024*1024で割った商です。パスがなければ、os.path.dirnameで上へたどりながら、存在する場所を探しますが、作ってはいけません。採点ツールは、いまの空き容量を基準にして、基準値を変えながら、不足したディスクを模擬します。

証明書の残り日数をnotAfterで測る

certsのチェックを入れ、observed(notAfterのエポック秒)・days_left・判定を出すようにしてください(ファイル: /root/preflight/preflight.py)。

openssl x509 -enddate -noout -in <ファイル>の出力の、notAfter=のあとを、ssl.cert_time_to_secondsで変換します。読めなかったファイルは、observedがnullでfailです。採点ツールは、余裕のある・期限間近・期限切れ・壊れた証明書を作って混ぜます。

設定・ホスト名・書き込み権限を確認する

files・hosts・writable_dirsのチェックを入れてください(ファイル: /root/preflight/preflight.py)。存在しないディレクトリは作らず、書き込みの試験のファイルは消します。

ファイルは、存在しない・ファイルではない・空のファイルを区別します。名前解決は、socket.getaddrinfoが失敗すると、socket.gaierrorを出します。書き込みは、os.accessの代わりに、tempfile.mkstempで実際に作ってみて、消します。

ホスト3台と、壊れた仕様を区別する

全体の仕様で、正常・警告・失敗を終了コード0・1・2で、読めない仕様を報告書なしで3で終えるかを確認してください(ファイル: /root/preflight/preflight.py)。

仕様のキーの順序が変わっても、チェックidは、仕様に書かれたものと正確に同じでなければなりません。仕様のJSONが壊れていたなら、判定する根拠がないので、報告書は書きません。

顧客のホストにgo / no-goを下す

spec.jsonでチェックして報告書を残し(ファイル: /root/preflight/report.json)、report_sha256・decision・blockers・warningsを記録してください(ファイル: /root/preflight/decision.json)。

decisionは、summaryから決まります(pass→go、warn→go-with-warnings、fail→no-go)。blockersはfailのチェックid、warningsはwarnのチェックidです。採点ツールは、いま再びチェックして、報告書が古くなっていないかと、ハッシュを確認します。妨げとなる項目を直して通過させる段階ではありません。