up スクリプトは実行されて終了コードゼロを返すのに、その中のタスクは、ターミナルからなら二秒後に完璧に動くプライベートサービスに到達できない。原因はタイミングだと考え、ふつうはスリープで直そうとするが、それは競合を理解せずに隠すだけだ。より有用な読み方は、「up」はフックの名前であって、準備完了の保証ではないということだ。up はトンネルデバイスが設定された時点で発火するのであり、それはルートや DNS より早く、トンネルの向こう側にあるアプリケーションより確実に早い。

シェルでのテストが成功したのは、すべてが落ち着いた後に実行されたからだ。フックはある特定の瞬間に実行された。

up が起動順序のどこに位置するか

OpenVPN はトンネルデバイスを設定してから up フックを実行する。ルートのインストールは後の段階で、それには専用のフックがあるため、up に置かれたルート依存のタスクは、有用な経路を持たないデバイスを見ることになる。ルート作業を route-up に置けば、タイミングの問題はたいてい消える。

マニュアルにはこの順序と、各フックが受け取る環境が記載されている。この順序こそが「自分のシェルからは動く」という定番の報告の説明であり、同じスクリプトがあるマシンでは通り、ルート段階が遅い別のマシンでは失敗する理由でもある。どちらの結果もスクリプトの品質については何も語っていない。

DNS とアプリケーションの準備はさらに後になる。ルートがインストールされていても、遠端のエンドポイントが待ち受けていること、名前が解決すること、あるいはユーザー単位のタスク向けのデスクトップセッションが存在することの証明にはならない。

フックが実際に引き継ぐもの

フックは OpenVPN プロセスのアカウントと環境の下で実行される が、これは対話型シェルと同じではない。ユーザーのセッションバス、デスクトップ環境、あるいはログイン時にしか解除されない資格情報が欠けている可能性がある。そのうちどれがタスクに本当に必要かを書き出そう。

これは、ネットワークのように見えてもユーザーコンテキストに依存するタスク——ユーザー資格情報で共有をマウントする、ユーザー単位のプロキシを設定する、プリンターを構成する——では重要だ。特権的なトンネルフックはそれらを置く場所として間違っており、どれだけ待っても欠けたセッションは直らない。

フックでタスクが失敗したら、アカウント、環境、そして最初に失敗した操作を記録する。それにより、早すぎるタイミングと権限やコンテキストの問題を切り分けられる。両者の修理方法はまったく異なり、そのどちらかを推測で決めることが、五分で済む修正を丸一日の作業に変えてしまう。

スリープを足すことが準備確認にならない理由

スリープはスクリプトを遅らせ、競合の窓をずらすだけだ。速い日にはタスクが成功し、遅い日には再び失敗し、遅延が効いているように見えるために失敗の再現は難しくなる。軽い負荷でしか効かない遅延は偶然であって、修理ではない。

依存先がルートなら、ルートのインストールに対応するフックを使う。依存先がトンネルの向こう側のサービスなら、その特定の条件を待ち、決して訪れないときには明確に失敗する、上限付きのチェックを使う。

失敗は明示的にしておくべきで、実際の作業が失敗したのに終了コードゼロを返すフックは、失敗するフックより悪い。サービスマネージャーが成功として記録し、誰も二度と見なくなるからだ。スクリプト自身が出力するログの一行が、それを正直に保つ最も安価な方法だ。

後片付けと再接続にも同じ注意が必要だ

共有状態を変えるスクリプトには、対応する取り消し経路が必要だ。フックが追加したルート、リゾルバーのエントリ、ファイアウォールのマークは冪等かつ可逆であるべきで、そうでなければ再接続で二つ目のコピーが一つ目の上に積み重なる。

再接続は、サービスの完全な起動よりも頻繁にフックを実行することがある。セッションを再確立する常駐インターフェースは up と route-up のサイクルを再び引き起こす可能性があるため、起動ごとに一度だけ実行されると仮定したスクリプトは、いずれ誤動作する。フラッピングが続く一日のログで実行回数を数え、実際にどれくらいの頻度で動くのかを確認しよう。そして、その回数だけ実行しても安全なスクリプトにしよう。

失敗したライフサイクルをテストするのであって、後続のコマンドをテストするのではない。起動や再接続を再現し、フックの実行を観察し、実際に実行されるその瞬間にタスクが成功したことを確認する。その後に対話型シェルから成功したとしても、それは依存関係についての証拠であって、起動経路が機能することの証明ではない。

各タスクが依存するイベントに名前を付け、そのイベントに結び付けよう。それ以外は、チェックのふりをした遅延にすぎない。

関連記事