CloudEdge 自主实验室 (cloudedge-labctl)

实验性功能(CloudEdge)。这是一个单命令线束,允许代理在无需人工审查 Runbook 的情况下运行 CloudEdge Selective Address Mobility (SAM) 故障转移实验室。该线束固定接口,并实现所有非云端逻辑(run-id/标签规范、TTL + 清理成本守卫、故障原语、连接矩阵、证据组装)。实际的逐提供商配置要么封装现有的
examples/cloudedge-mobility-demo/包,要么标记为TODO(lab-operator)以供 Terraform/CLI 集成。
线束为 scripts/cloudedge-labctl.sh,有 2 个辅助工具:
scripts/cloudedge-connectivity-matrix.sh— 有向 ping+ssh 矩阵 + 断言。scripts/cloudedge-evidence-schema.json— 运行证据的 JSON schema。
--help、dry 路径、down --expired 不需要云端凭据。
观测收敛而不重复整套测试
SAM在provider Ready之后判定通信。每次validation将原有的900秒provider收敛预算与流量观测共用。仅重新获取失败或缺失的必需项目,每项最多观测3次;成功项目和相同的cloud-ingress flow在同一次validation及相同故障状态内共享证据。成功flow不运行traceroute。无法确认管理SSH执行完成时,标记为 OBSERVATION_INCONCLUSIVE(退出码3),而不判定为产品ping失败。包含恢复前失败的原始记录保留在 matrix/<label>/flows.*/。
L2 采集失败或指标缺失判为无法确定,并保留 stdout/stderr;只有成功采集后的数值零才有效。gateway unchanged 比较每个流在源主机上通信前后的路由,不是整个部署的基线。failover action 必须匹配本次故障开始时间、地址和 standby。恢复时间包含 coordinator/API/SSH/poll 开销,仅超过此上界不能证明产品退化;60 秒目标保持不变。netns 测试或 cleanup 失败时保留工作目录和 cleanup log。FreeBSD 同一网络栈内的 VXLAN ping 不能证明经过 WireGuard 的转发;该 smoke 报告配置、handshake、所有权和 restart 证据,并注明转发未经验证。IPC 请求在现有等待预算内设定期限,无法采集使用 exit 3。bus 慢 subscriber 测试使用检测阻塞的 watchdog,而非吞吐量门槛。
诊断采集与验收判定分离。收敛等待循环不再反复执行 doctor sam,仅在诊断时采集一次。同一诊断快照中的 status、已应用 BGP 路径和 global RIB 各读取一次,摘要从保存的响应生成。诊断采集失败不改变流量判定。
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 重放相关响应及负例,不创建资源。通过 make cloudedge-representative-redundancy-offline-test 检查实际matrix/profile调用路径。这些测试通过不代表已完成云端实机测试。
生命周期
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>清理一个运行。down --expired清理所有超过 TTL 的运行(无实验室时安全地 no-op — exit 0)。up预先验证--ttl,对无效时长进行硬性失败(非零退出)。不会在成本守卫损坏/已过期的情况下启动实验室。- 线束的 EXIT trap 会在
up被中断或提供商启动途中失败时清理运行(仅在进行中的阶段激活,正常完成时解除。正常的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 拒绝(ID 范围缩小) | ID 策略 |
stale-replay | 重放过时的 pathSig 操作。必须被 fence | probe_stale_gate_on_aws_b |
注入故障后重新运行 smoke 和 evidence collect,证明恢复情况。
证据 schema
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/fencing 断言(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 导入。
自主性章程(概要)
代理拥有实验室启动 -> 部署 -> 故障注入 -> 数据平面验证 -> 证据 -> 清理 -> issue/PR 更新的完整循环,无需人工阅读 Runbook 即可执行。云端操作默认为 dry,由显式的凭据/预算审批进行门控。代理必须始终将实验室保持在已清理或 TTL 成本守卫内的状态,PASS 必须附带 schema 有效的证据包。
人工门控
以下情况仅需人工参与。其余全部自动化:
- 预算 — 批准支出 / 提升 TTL 或预算上限。
- 凭据/权限 — 提供云端凭据和 executor 使用的最小权限 ID/角色(secret 不提交,也不传递给插件)。
- 合并 — PR 的最终审批。
- 生产 — 生产环境部署(实验室线束绝不执行)。
注意事项
- 这是实验室线束,不是生产就绪的交钥匙方案。
- 初始实现:实际的逐提供商分配/清理/节点推送是
TODO(lab-operator)的桩或演示包的薄层封装 — 请接入使用 run-id 标签过滤的 Terraform/OpenTofu 或提供商 CLI。 - 绝不提交实际的账户 ID / 订阅 ID / OCID / ENI/VNIC ID / secret / 私钥。使用
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次尝试和指标文件名,后续成功不删除失败尝试。