CloudEdge 自律ラボ (cloudedge-labctl)

実験的機能(CloudEdge)。エージェントが人間の Runbook 確認なしに CloudEdge Selective Address Mobility (SAM) フェイルオーバーラボを実行できる、単一コマンドのハーネスです。インターフェースを固定し、クラウド以外のロジック(run-id/タグ規約、TTL + teardown コストガード、障害プリミティブ、接続マトリクス、エビデンス組み立て)をすべて実装しています。実際のプロバイダーごとのプロビジョニングは、既存の
examples/cloudedge-mobility-demo/パッケージをラップするか、Terraform/CLI 連携用にTODO(lab-operator)としてマークされています。
ハーネスは scripts/cloudedge-labctl.sh で、2 つのヘルパーがあります:
scripts/cloudedge-connectivity-matrix.sh— 方向付き ping+ssh マトリクス + アサーション。scripts/cloudedge-evidence-schema.json— ランエビデンスの JSON スキーマ。
--help、dry パス、down --expired にはクラウド認証情報は不要です。
全体を繰り返さずに収束を観測する
SAMはprovider Readyを待ってから通信を判定します。1回のvalidation内で、既存のprovider収束予算900秒を通信観測と共有します。失敗・欠落した必須項目だけを、各項目最大3回まで再取得します。成功項目と同一のcloud-ingress flowは、そのvalidationと同じ障害状態の中で証拠を共有します。成功flowではtracerouteを実行しません。管理SSHの実行完了を確認できない場合は、製品ping失敗と分けて OBSERVATION_INCONCLUSIVE(終了コード3)にします。回復前の失敗を含む原本は matrix/<label>/flows.*/ に残します。
L2 の取得失敗・指標欠落は未判定とし stdout/stderr を保存します。数値ゼロは取得成功後だけ有効です。gateway の unchanged は各フローの送信元で通信直前・直後の経路を比較し、展開全体の基準ではありません。failover の action は今回の障害開始時刻・アドレス・standby に一致する必要があります。復旧時間には coordinator/API/SSH/poll の時間も含まれ、この上限超過だけで製品退行とは判定しません。60秒の目標は維持します。netns の失敗・cleanup 失敗では作業ディレクトリと cleanup log を保存します。FreeBSD の同一スタック VXLAN ping は WireGuard 経由の転送を実証せず、設定・handshake・所有権・restart の証跡と転送未実証を報告します。IPC 取得は既存の待機予算内で要求ごとに期限を設け、取得不能は exit 3 です。bus の遅い subscriber 試験は throughput 条件を使わず停止検出の watchdog を使います。
診断採取と受入判定は分離します。収束待ちループで doctor sam を連打せず、診断時に1回採取します。同じ診断スナップショット内のstatus・適用済みBGP経路・global RIBは各1回取得し、保存応答から要約を作ります。診断採取の失敗で通信の判定を変更しません。
retained ARPでは、監視HTTPの80ms timeout、100ms counter周期、400ms連続coverage、全区間controller進行は診断用の制約であり、受入条件ではありません。診断失敗でpcapやsender採取を止めません。完全なself ARP捕捉、実target commandとpacketの対応、新鮮な要求とTTL、完了した通信、process identityは維持し、必要証拠の欠落は不成立として区別します。既存の時刻・target・command sequence・provider resource IDを原本に残し、対応付けに使います。
cleanup inventoryではlifecycle変化とidentity不整合を区別します。AWS/OCIのidentityが一致し状態観測だけが異なる場合、同じinventory実行内で該当providerだけを最大2回追加観測し、各回の原本を保持します。identity・tag・accountの不一致、不正な応答、通信失敗を不在と扱いません。他providerのinventoryは継続し、不成立scopeはcountをnullにして資源ゼロ判定を通しません。既存の資源回収・削除ガードは維持します。
次の有料試験の前に、tools/release-qa-labs/tests/ の test_sam_observation.py、test_inventory_resources.py、test_inventory_driver.py で該当する保存応答・負例を再現します。資源は作成しません。実matrix/profile呼出し経路は make cloudedge-representative-redundancy-offline-test で確認します。これらの成功はクラウド実機試験の実施を意味しません。
ライフサイクル
scripts/cloudedge-labctl.sh up --profile full --provider aws,oci,azure,onprem --ttl 4h
scripts/cloudedge-labctl.sh deploy --commit HEAD # または --build <dist path>
scripts/cloudedge-labctl.sh smoke --matrix d3 --out /tmp/matrix.json
scripts/cloudedge-labctl.sh failover --provider aws --fault stop-active
scripts/cloudedge-labctl.sh smoke --matrix d3 --out /tmp/matrix-after.json
scripts/cloudedge-labctl.sh evidence collect --out evidence/<run-id> --matrix-json /tmp/matrix-after.json
scripts/cloudedge-labctl.sh down --run-id <run-id> --force
up は run-id を stdout に出力します。これをキャプチャして後続のコマンドに渡してください。クラウドへの変更操作はデフォルトで DRY(CE_DRY_RUN=1)です。認証情報と予算の承認後に CE_DRY_RUN=0 を設定して実際に実行します。
プロファイル
| プロファイル | サイト数 | 用途 |
|---|---|---|
minimal | on-prem + クラウド 1 | 最安のスモーク、インターフェース/CI の検証 |
provider | 1 プロバイダーの A/B ルーター + クライアント | プロバイダーパリティ(AWS/OCI/Azure seize) |
full | on-prem + AWS + OCI + Azure | 4 サイト /24 12 フローデモ |
soak | TTL 全期間稼働させる full ラン | 長時間の再収束チェック |
soak は運用上は長い --ttl で維持する full ランです(TTL まで down を実行しないでください)。BFD/BGP 再収束の検証に使います。
TTL とコストポリシー
すべてのクラウドリソースは以下のタグを必ず付与します(ヘルパー cloudedge_tags() が出力し、up がスタンプします):
routerd.cloudedge.run_id <UTCdate>T<time>-cloudedge-<scenario>
routerd.cloudedge.owner
routerd.cloudedge.ttl_expires_at 絶対 UTC RFC3339
routerd.cloudedge.provider
routerd.cloudedge.purpose
コストガードルール:
up --ttl <dur>でttl_expires_atをスタンプします。ランに適した最短の TTL を選んでください。down --run-id <id>は 1 つのランを teardown します。down --expiredは TTL を過ぎたすべてのランを teardown します(ラボがない場合は安全に no-op — exit 0)。upは--ttlを事前に検証し、不正な期間ではハードフェイル(非ゼロ終了)します。壊れた/すでに期限切れのコストガードでラボが起動されることはありません。- ハーネスの EXIT トラップは、
upが中断されたり、プロバイダーが起動途中で失敗した場合にランを teardown します(進行中の期間のみ有効化され、正常完了時に解除されます。正常なupはラボを明示的なdownまたは TTL まで存続させます)。up --keepを指定すると、調査用に部分状態を残します。 - 失敗時も含め、毎回のラン後に必ず
down(または janitor からのdown --expired)を実行してください。TTL 超過のラボは run-id なしでクリーンアップ可能です。
障害プリミティブ (failover --fault)
| 障害 | 意味 | 初期配線 |
|---|---|---|
stop-active | アクティブルーター VM/インスタンスを停止 | プロバイダー stop CLI(reset-lab.sh 参照) |
drain | アクティブの MobilityPool で maintenance.drain=true | run-demo.sh の *-drain.yaml を再利用 |
routerd-bgp-stop | routerd-bgp を停止(BGP セッション切断) | ssh systemctl stop routerd-bgp |
executor-fail | プロバイダーアクション executor 拒否(識別情報のスコープダウン) | 識別情報ポリシー |
stale-replay | 古い pathSig アクションをリプレイ。フェンスされる必要あり | probe_stale_gate_on_aws_b |
障害を注入してから smoke と evidence collect を再実行し、復旧を証明します。
エビデンススキーマ
evidence collect --out <dir> は <dir>/result.json を出力します。scripts/cloudedge-evidence-schema.json に対して検証され、summary.md と(指定されていれば)接続マトリクス JSON も出力されます。形式:
{
"runId": "20260601T031500Z-cloudedge-aws-failover",
"commit": "<sha>",
"scenario": "aws-active-stop-seize",
"result": "pass",
"providers": {
"aws": {"dataplane": "pass", "providerState": "pass"},
"oci": {"dataplane": "pass", "providerState": "pass"},
"azure": {"dataplane": "pass", "providerState": "pass"},
"onprem": {"dataplane": "pass", "providerState": "pass"}
},
"assertions": [
{"name": "ownership_epoch_bumped", "result": "pass"},
{"name": "allow_reassignment_maintained_until_success", "result": "pass"},
{"name": "source_ip_preserved", "result": "pass"},
{"name": "default_gateway_unchanged", "result": "pass"},
{"name": "old_holder_residue_absent", "result": "pass"},
{"name": "stale_action_fenced", "result": "pass"}
],
"costGuard": {"ttlHours": 4, "teardown": "completed"}
}
データプレーンのチェックと source_ip_preserved / default_gateway_unchanged は接続マトリクスから自動的に導出されます。seize/フェンシングアサーション(ownership_epoch_bumped、allow_reassignment_maintained_until_success、old_holder_residue_absent、stale_action_fenced)と providerState は最初 na で、ラボ運用者がプロバイダーインベントリ、BGP mobility パス、プロバイダー trap アクションプラン、アクションジャーナルから取り込みます(collect-evidence.sh 参照)。ランが PASS となるのは result == pass かつすべての必須アサーションがパスした場合のみです。
接続マトリクス
cloudedge-connectivity-matrix.sh は共有 /24 上のすべての方向付き src -> dst フローを実行し、フローごとに以下をアサートします:
- source-IP-preserved — 宛先がクライアントサイトの実際のソース IP(mobility
/32)をピアアドレスとして認識する(NAT なし)。 - default-gw-unchanged — ソースクライアントのデフォルトゲートウェイが変更されていない。
- no-NAT — ping が宛先に到達し、SSH のピア IP がソース IP と一致する。
実行は MATRIX_RUNNER の間接指定を通じて行われるため、マトリクスはオフラインで単体実行可能です(MATRIX_RUNNER にスタブを設定)。実際のラボでは、デフォルトのランナーがデモ環境に対して ssh/ping を使います。出力はフローごとの JSON で、evidence collect --matrix-json で取り込めます。
自律性チャーター(概要)
エージェントはラボ起動 -> デプロイ -> 障害注入 -> データプレーン検証 -> エビデンス -> teardown -> issue/PR 更新のフルループを所有し、人間が Runbook を読むことなく実行します。クラウドアクションはデフォルトで dry であり、明示的な認証情報/予算の承認でゲートされています。エージェントは常にラボを teardown 済みか TTL コストガード内の状態にしなければならず、PASS には必ずスキーマ有効なエビデンスバンドルを添付する必要があります。
人間のゲート
以下のみ人間が必要です。それ以外はすべて自動化されています:
- 予算 — 支出の承認 / TTL または予算上限の引き上げ。
- 認証情報/権限 — クラウド認証情報と executor が使用する最小権限の識別情報/ロールの付与(秘密はコミットされず、プラグインにも渡されません)。
- マージ — PR の最終承認。
- 本番 — 本番ロールアウト(ラボハーネスでは一切実行されません)。
注意事項
- これはラボハーネスであり、本番用のターンキーソリューションではありません。
- 初期実装: 実際のプロバイダーごとの割り当て/teardown/ノードプッシュは
TODO(lab-operator)のスタブか、デモパッケージの薄いラッパーです — run-id タグでフィルタリングした Terraform/OpenTofu またはプロバイダー CLI を接続してください。 - 実際のアカウント ID / サブスクリプション ID / OCID / ENI/VNIC ID / 秘密情報 / 秘密鍵は決してコミットしないでください。
env.exampleのようにプレースホルダーの論理アドレスを使用してください。
ゲスト準備の証跡
provider CLI の導入は OpenTofu cloud-init と SAM 準備に分かれています。 AWS は既存の代替導入を維持し、Azure/OCI は既存の cloud-init installer を使います。 コマンド列は失敗時に停止します。準備は cloud-init の状態・出力を保存し、 routerd 配置前に root のサービス PATH で必須 CLI を実行します。操作ホストの CLI や起動完了マーカーだけでは、ゲストの依存を確認できません。
収束・warm-up の各試行は stdout/stderr、終了コード、UTC 時刻を保存します。
診断は sudo で journal を読み、WireGuard の公開フィールドを採取します。
GoBGP がない場合は JSON 解析せず取得不能を記録します。既存試験群の前提対応表は
tools/release-qa-labs/test-prerequisites.md にあります。
共通の cloud-init CLI 準備は各試行を保存します。取得には curl の一時障害再試行を使い、既知のネットワーク・パッケージロックによる導入失敗だけを最大3回まで局所再試行します。恒久エラーや再試行枯渇では失敗を保存して準備を停止します。クライアントの APT 準備は既存の4回を維持し、既知の一時障害に限って再試行します。シナリオ全体は繰り返しません。
performance の局所再試行は、server/client の各試行の生出力・退出コード・時刻を保存します。既存の3回とメトリクス用ファイル名は維持し、後続の成功で失敗試行を消しません。