fix(cicd): avoid no-op public edge restarts

This commit is contained in:
pikastech
2026-07-20 16:59:55 +02:00
parent 4ccbe58406
commit 1f865acbd4
2 changed files with 41 additions and 21 deletions
+5
View File
@@ -166,6 +166,11 @@ bun scripts/cli.ts hwlab nodes control-plane legacy-cicd --help
- installed commit 与 candidate 相同则幂等返回;
- installed commit 不是 candidate 祖先时,以 `stale-or-diverged-source-commit` 拒绝;
- 禁止旧 PipelineRun、分叉提交或人工补跑覆盖较新的运行面。
- 精确变更判定:
- 任意 `master` 事件可以进入 reconcile,但不能直接等同于共享边缘配置变化;
- 健康运行面的 managed Caddy 与 Compose 指纹均未变化时,只推进 provenance
禁止重建 Caddy 或中断既有 HTTPS、流式响应和 WebSocket
- 只有受管配置指纹变化或运行面漂移时,才允许进入受控 recreate。
- 共享 Caddy 更新必须使用 owner managed block
- public-edge controller只替换 `public-edge-*` blocks
- 非 public-edge managed block 必须保留;
+36 -21
View File
@@ -1052,20 +1052,50 @@ PY
)"
current_compose_sha=""
if [ -f ${shQuote(target.runtime.composePath)} ]; then current_compose_sha="sha256:$(sha256sum ${shQuote(target.runtime.composePath)} | awk '{print $1}')"; fi
write_candidate_state() {
state_candidate="$tmp/reconcile-state.json"
if ! python3 - "$state_candidate" ${shQuote(provenance.authorityId)} ${shQuote(provenance.sourceCommit)} ${shQuote(desiredCaddyFingerprint)} ${shQuote(desiredComposeFingerprint)} ${sites.length} <<'PY'
import datetime, json, pathlib, sys
path = pathlib.Path(sys.argv[1])
path.write_text(json.dumps({
"version": 1,
"authorityId": sys.argv[2],
"sourceCommit": sys.argv[3],
"managedCaddyFingerprint": sys.argv[4],
"composeFingerprint": sys.argv[5],
"siteCount": int(sys.argv[6]),
"updatedAt": datetime.datetime.now(datetime.timezone.utc).isoformat(),
}, separators=(",", ":")) + "\\n", encoding="utf-8")
PY
then
return 1
fi
chmod 0644 "$state_candidate" || return 1
mv "$state_candidate" ${shQuote(target.runtime.statePath)}
}
if [ "$new_running" -eq 1 ] \
&& [ "$installed_commit" = ${shQuote(provenance.sourceCommit)} ] \
&& [ "$installed_caddy_sha" = ${shQuote(desiredCaddyFingerprint)} ] \
&& [ "$installed_compose_sha" = ${shQuote(desiredComposeFingerprint)} ] \
&& [ "$current_managed_sha" = ${shQuote(desiredCaddyFingerprint)} ] \
&& [ "$current_compose_sha" = ${shQuote(desiredComposeFingerprint)} ]; then
python3 - ${shQuote(provenance.authorityId)} ${shQuote(provenance.sourceCommit)} "$dns_warnings" <<'PY'
provenance_updated=false
if [ "$installed_commit" != ${shQuote(provenance.sourceCommit)} ] \
|| [ "$installed_caddy_sha" != ${shQuote(desiredCaddyFingerprint)} ] \
|| [ "$installed_compose_sha" != ${shQuote(desiredComposeFingerprint)} ]; then
if ! write_candidate_state; then
printf '%s\\n' '{"ok":false,"mutation":false,"error":"provenance-update-failed","valuesPrinted":false}'
exit 1
fi
provenance_updated=true
fi
python3 - ${shQuote(provenance.authorityId)} ${shQuote(provenance.sourceCommit)} "$dns_warnings" "$provenance_updated" <<'PY'
import json, sys
warnings = []
with open(sys.argv[3], encoding="utf-8") as handle:
for line in handle:
hostname, expected_a = line.rstrip("\\n").split("\\t", 1)
warnings.append({"code": "public-edge-dns-mismatch", "level": "warning", "blocking": False, "hostname": hostname, "expectedA": expected_a})
print(json.dumps({"ok": True, "mutation": False, "mode": "already-current", "authorityId": sys.argv[1], "sourceCommit": sys.argv[2], "warnings": warnings, "valuesPrinted": False}))
print(json.dumps({"ok": True, "mutation": False, "mode": "already-current", "authorityId": sys.argv[1], "sourceCommit": sys.argv[2], "provenanceUpdated": sys.argv[4] == "true", "warnings": warnings, "valuesPrinted": False}))
PY
exit 0
fi
@@ -1089,22 +1119,7 @@ if [ "$recreate_rc" -eq 0 ]; then
fi
state_rc=1
if [ "$recreate_rc" -eq 0 ] && [ "$ready_rc" -eq 0 ]; then
state_candidate="$tmp/reconcile-state.json"
python3 - "$state_candidate" ${shQuote(provenance.authorityId)} ${shQuote(provenance.sourceCommit)} ${shQuote(desiredCaddyFingerprint)} ${shQuote(desiredComposeFingerprint)} ${sites.length} <<'PY'
import datetime, json, pathlib, sys
path = pathlib.Path(sys.argv[1])
path.write_text(json.dumps({
"version": 1,
"authorityId": sys.argv[2],
"sourceCommit": sys.argv[3],
"managedCaddyFingerprint": sys.argv[4],
"composeFingerprint": sys.argv[5],
"siteCount": int(sys.argv[6]),
"updatedAt": datetime.datetime.now(datetime.timezone.utc).isoformat(),
}, separators=(",", ":")) + "\\n", encoding="utf-8")
PY
chmod 0644 "$state_candidate"
mv "$state_candidate" ${shQuote(target.runtime.statePath)} && state_rc=0
write_candidate_state && state_rc=0
fi
rollback_rc=-1