fix(runner): classify harbor 110 repair waiting runs
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 33s
CD Pipeline / build-and-deploy (push) Failing after 2m37s
AWOOOI Harbor 110 Local Repair / workflow-shape (push) Successful in 0s
CD Pipeline / post-deploy-checks (push) Has been skipped
AWOOOI Harbor 110 Local Repair / harbor-110-local-repair (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-30 20:48:16 +08:00
parent 49a9f73094
commit 01deee4a7d
3 changed files with 131 additions and 0 deletions

View File

@@ -1,3 +1,17 @@
## 2026-06-30 — 20:45 Harbor 110 repair waiting readback classifier
**照主線修正的問題**
- `ops/runner/read-public-gitea-actions-queue.py` 新增 `harbor-110-local-repair.yaml` 專用 readbackrun id、status、kind、title、commit、waiting / running / blocked 與 no-matching runner label。
- Rollups 新增 `harbor_110_repair_run_visible``harbor_110_repair_run_status``harbor_110_repair_waiting``harbor_110_repair_running``harbor_110_repair_blocked`,避免 110 local repair workflow 只藏在 `top_visible_runs` 靠人眼判讀。
- Live readback 目前精準收斂CD `#4061` failureclassifier=`harbor_registry_public_route_unavailable``registry_v2_status=502`、CD non110 self-heal skip=`not_110_host`scheduled Harbor repair `#4060` visible 且 `Waiting`
**驗證**
- `py_compile``ruff check``pytest ops/runner/test_read_public_gitea_actions_queue.py -q` 通過(`15 passed`)。
- `read-public-gitea-actions-queue.py --json` 成功讀出 `latest_visible_harbor_110_repair_run_id=4060``latest_visible_harbor_110_repair_run_status=Waiting`
- `git diff --check` 通過。
**邊界**:只讀 public Gitea / 本機 source未讀 secret / token / `.env` / raw sessions / SQLite / auth未使用 GitHub / `gh` / GitHub API未 workflow_dispatch未 SSH / Docker / Nginx / K3s / DB / firewall runtime 寫入。
## 2026-06-30 — 20:29 Harbor self-heal skip reason classifier
**照主線修正的問題**

View File

@@ -182,6 +182,14 @@ def build_readback(
(run for run in visible_runs if run.get("workflow") == "cd.yaml"),
{},
)
latest_harbor_110_repair_run = next(
(
run
for run in visible_runs
if run.get("workflow") == "harbor-110-local-repair.yaml"
),
{},
)
cd_jobs = cd_jobs_payload if isinstance(cd_jobs_payload, dict) else {}
actions_list = actions_list_payload if isinstance(actions_list_payload, dict) else {}
actions_list_message = str(actions_list.get("message") or "")
@@ -228,6 +236,10 @@ def build_readback(
build_log_classifier = classify_cd_build_log(latest_cd_build_log_text)
tests_log_classifier = classify_cd_tests_log(latest_cd_tests_log_text)
latest_cd_visible_blocked = latest_cd_run.get("status", "") == "Blocked"
harbor_110_repair_status = latest_harbor_110_repair_run.get("status", "")
harbor_110_repair_waiting = harbor_110_repair_status == "Waiting"
harbor_110_repair_running = harbor_110_repair_status == "Running"
harbor_110_repair_blocked = harbor_110_repair_status == "Blocked"
readback = {
"actions_page_visible_run_count": len(visible_runs),
@@ -281,6 +293,25 @@ def build_readback(
"harbor_public_route_blocked"
],
"latest_visible_cd_tests_log_http_status": latest_cd_tests_log_http_status,
"latest_visible_harbor_110_repair_run_id": (
latest_harbor_110_repair_run.get("run_id", "")
),
"latest_visible_harbor_110_repair_run_status": harbor_110_repair_status,
"latest_visible_harbor_110_repair_run_kind": (
latest_harbor_110_repair_run.get("kind", "")
),
"latest_visible_harbor_110_repair_run_title": (
latest_harbor_110_repair_run.get("title", "")
),
"latest_visible_harbor_110_repair_run_commit_sha": (
latest_harbor_110_repair_run.get("commit_sha", "")
),
"latest_visible_harbor_110_repair_no_matching_runner_label": (
latest_harbor_110_repair_run.get("no_matching_runner_label", "")
),
"latest_visible_harbor_110_repair_waiting": harbor_110_repair_waiting,
"latest_visible_harbor_110_repair_running": harbor_110_repair_running,
"latest_visible_harbor_110_repair_blocked": harbor_110_repair_blocked,
"latest_visible_cd_host_pressure_classifier": tests_log_classifier[
"host_pressure_classifier"
],
@@ -316,6 +347,12 @@ def build_readback(
if build_log_classifier["harbor_public_route_blocked"]
else "blocked_host_web_build_pressure"
if tests_log_classifier["host_pressure_blocked_or_waiting"]
else "harbor_110_repair_waiting_for_runner_or_queue"
if harbor_110_repair_waiting
else "harbor_110_repair_running"
if harbor_110_repair_running
else "blocked_harbor_110_repair_run"
if harbor_110_repair_blocked
else "cd_jobs_stale_or_mismatched"
if cd_jobs_stale_or_mismatched
else "no_matching_runner_not_visible"
@@ -351,6 +388,14 @@ def build_readback(
"host_pressure_refused"
],
"no_matching_online_runner_visible": bool(no_matching),
"harbor_110_repair_run_visible": bool(latest_harbor_110_repair_run),
"harbor_110_repair_run_status": harbor_110_repair_status,
"harbor_110_repair_waiting": harbor_110_repair_waiting,
"harbor_110_repair_running": harbor_110_repair_running,
"harbor_110_repair_blocked": harbor_110_repair_blocked,
"harbor_110_repair_no_matching_runner_label": (
latest_harbor_110_repair_run.get("no_matching_runner_label", "")
),
},
"operation_boundaries": {
"public_gitea_read_only": True,
@@ -498,6 +543,18 @@ def _human_summary(payload: dict[str, Any]) -> str:
"LATEST_VISIBLE_CD_HOST_PRESSURE_CLASSIFIER="
f"{readback['latest_visible_cd_host_pressure_classifier']}"
),
(
"LATEST_VISIBLE_HARBOR_110_REPAIR_RUN_ID="
f"{readback['latest_visible_harbor_110_repair_run_id']}"
),
(
"LATEST_VISIBLE_HARBOR_110_REPAIR_RUN_STATUS="
f"{readback['latest_visible_harbor_110_repair_run_status']}"
),
(
"LATEST_VISIBLE_HARBOR_110_REPAIR_NO_MATCHING_RUNNER_LABEL="
f"{readback['latest_visible_harbor_110_repair_no_matching_runner_label']}"
),
"WRITE_PERFORMED=false",
"TOKEN_COLLECTED=false",
]

View File

@@ -91,6 +91,40 @@ def _actions_html_single_cd_run() -> str:
"""
def _actions_html_cd_running_harbor_repair_waiting() -> str:
return """
<div class="flex-list run-list">
<div class="flex-item tw-items-center">
<div class="flex-item-leading">
<span data-tooltip-content="Running"></span>
</div>
<div class="flex-item-main">
<a class="flex-item-title" title="fix(cd): keep harbor repair workflow on controlled profile" href="/wooo/awoooi/actions/runs/4061">
fix(cd): keep harbor repair workflow on controlled profile
</a>
<div class="flex-item-body">
<span><b>cd.yaml #4061</b>:</span>Commit
<a href="/wooo/awoooi/commit/49a9f73094592150f5d748e6be68a9e49ba1b7df">49a9f7309</a>
</div>
</div>
</div>
<div class="flex-item tw-items-center">
<div class="flex-item-leading">
<span data-tooltip-content="Waiting"></span>
</div>
<div class="flex-item-main">
<a class="flex-item-title" title="fix(cd): schedule bounded 110 harbor repair" href="/wooo/awoooi/actions/runs/4060">
fix(cd): schedule bounded 110 harbor repair
</a>
<div class="flex-item-body">
<span><b>harbor-110-local-repair.yaml #4060</b>:</span>Scheduled
</div>
</div>
</div>
</div>
"""
def _actions_html_failed_cd_run() -> str:
return """
<div class="flex-list run-list">
@@ -190,6 +224,32 @@ def test_build_readback_reports_latest_visible_cd_run() -> None:
assert payload["readback"]["cd_run_jobs_stale_or_mismatched"] is False
def test_build_readback_surfaces_harbor_110_repair_waiting_run() -> None:
module = _load_module()
payload = module.build_readback(
actions_html=_actions_html_cd_running_harbor_repair_waiting(),
actions_list_http_status=401,
actions_list_payload={"message": "token is required"},
cd_jobs_http_status=200,
cd_jobs_payload={"jobs": [], "total_count": 0},
)
assert payload["status"] == "harbor_110_repair_waiting_for_runner_or_queue"
assert payload["readback"]["latest_visible_cd_run_id"] == "4061"
assert payload["readback"]["latest_visible_cd_run_status"] == "Running"
assert payload["readback"]["latest_visible_harbor_110_repair_run_id"] == "4060"
assert (
payload["readback"]["latest_visible_harbor_110_repair_run_status"]
== "Waiting"
)
assert payload["readback"]["latest_visible_harbor_110_repair_waiting"] is True
assert payload["readback"]["latest_visible_harbor_110_repair_running"] is False
assert payload["rollups"]["harbor_110_repair_run_visible"] is True
assert payload["rollups"]["harbor_110_repair_waiting"] is True
assert payload["rollups"]["harbor_110_repair_run_status"] == "Waiting"
assert payload["operation_boundaries"]["workflow_dispatch_performed"] is False
def test_build_readback_classifies_harbor_public_route_blocker() -> None:
module = _load_module()
payload = module.build_readback(