fix(cicd): avoid no-op public edge restarts
This commit is contained in:
@@ -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 必须保留;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user