纯标准库实现,对齐 PRD 5.6「⑥ 部署底座」(不真执行 k8s/helm,模拟编排): - deploy_plan.py:DeployStep(4 类:pre_check/deploy/health_check/post_check) + DeployPlan(顺序约束自动校验,default_helm_release 默认 4 步计划)+ DeployOrchestrator(按序执行,必需步骤失败即中止并标记 needs_rollback, deploy/health_check 为回滚检查点,pre_check 失败无需回滚)+ HealthCheckContract(对齐 deploy/k8s/healthz 99.8% 目标)。 - rollback.py:RollbackPoint(部署前快照,values_hash SHA1 检测漂移)+ RollbackManager(快照栈 + rollback_to_latest/rollback(n),失败压回栈顶 保持一致性,FIFO 淘汰,支持回滚后健康检查)+ RollbackResult(4 状态)。 - tests:30 用例覆盖计划构造/顺序约束、全成功/各类失败、回滚检查点判定、 action 异常、dry_run、空计划、快照压栈/FIFO、回滚成功/失败/多版本/空栈/ 异常、健康检查契约、values 漂移、报告序列化。 - _sanity_check.py:冒烟验证快照→部署成功→部署失败→回滚全流程。
52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""部署编排 + 回滚冒烟脚本(Issue #60)。
|
||
|
||
直接运行 ``python _sanity_check.py`` 验证:默认 Helm 计划全成功部署、
|
||
快照压栈、模拟部署失败触发回滚到上一稳定版本。零第三方依赖。
|
||
"""
|
||
import os
|
||
import sys
|
||
|
||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||
sys.path.insert(0, HERE)
|
||
|
||
from deploy_plan import ( # noqa: E402
|
||
DeployOrchestrator, DeployPlan, DeployStepKind)
|
||
from rollback import RollbackManager # noqa: E402
|
||
|
||
|
||
def main() -> int:
|
||
# 1) 部署前快照(当前稳定版本 v1.0.0)
|
||
mgr = RollbackManager()
|
||
stable = DeployPlan.default_helm_release(version="v1.0.0")
|
||
mgr.snapshot(stable, reason="部署 v1.1.0 前的稳定版本")
|
||
print(f"[OK] 快照压栈:稳定版本 {mgr.latest().version}")
|
||
|
||
# 2) 部署 v1.1.0 全成功
|
||
new_plan = DeployPlan.default_helm_release(version="v1.1.0")
|
||
report = DeployOrchestrator(new_plan).execute()
|
||
assert report.succeeded, report.outcome.reason
|
||
mgr.snapshot(new_plan, reason="v1.1.0 部署成功")
|
||
print(f"[OK] 部署 v1.1.0 成功:{len(report.results)} 步,无需回滚")
|
||
|
||
# 3) 模拟 v1.2.0 部署失败(health_check 失败)→ 触发回滚
|
||
def _bad_health(ctx):
|
||
return False, "/health 503(服务未就绪)"
|
||
bad_plan = DeployPlan.default_helm_release(
|
||
version="v1.2.0",
|
||
step_actions={DeployStepKind.HEALTH_CHECK: _bad_health})
|
||
bad_report = DeployOrchestrator(bad_plan).execute()
|
||
assert not bad_report.succeeded
|
||
assert bad_report.outcome.needs_rollback
|
||
print(f"[OK] v1.2.0 部署失败:{bad_report.outcome.reason}")
|
||
|
||
result = mgr.rollback_to_latest(reason="v1.2.0 健康检查失败")
|
||
assert result.succeeded, result.detail
|
||
print(f"[OK] 回滚到 {result.target.version}:{result.detail}")
|
||
print("部署编排 + 回滚冒烟通过 ✅")
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
raise SystemExit(main())
|