Files
awoooi/ops/runner/read-public-gitea-actions-queue.py
Your Name ce5bcab8b5
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 35s
CD Pipeline / build-and-deploy (push) Failing after 27s
CD Pipeline / post-deploy-checks (push) Has been skipped
fix(agent): normalize ssh session timeout blocker
2026-07-01 12:47:14 +08:00

1625 lines
67 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import html
import json
import re
import sys
import urllib.error
import urllib.request
from dataclasses import dataclass
from pathlib import Path
from typing import Any
from urllib.parse import unquote
DEFAULT_ACTIONS_URL = "https://gitea.wooo.work/wooo/awoooi/actions"
DEFAULT_CD_WORKFLOW_ACTIONS_URL = (
"https://gitea.wooo.work/wooo/awoooi/actions?workflow=cd.yaml&actor=0&status=0"
)
DEFAULT_ACTIONS_LIST_API_URL = (
"https://gitea.wooo.work/api/v1/repos/wooo/awoooi/actions/runs?limit=10"
)
DEFAULT_CD_RUN_JOBS_API_URL = ""
DEFAULT_CD_BUILD_JOB_LOG_URL_TEMPLATE = (
"https://gitea.wooo.work/wooo/awoooi/actions/runs/{run_id}/jobs/3/logs"
)
DEFAULT_CD_TESTS_JOB_LOG_URL_TEMPLATE = (
"https://gitea.wooo.work/wooo/awoooi/actions/runs/{run_id}/jobs/2/logs"
)
DEFAULT_HARBOR_110_REPAIR_JOB_LOG_URL_TEMPLATE = (
"https://gitea.wooo.work/wooo/awoooi/actions/runs/{run_id}/jobs/1/logs"
)
SCHEMA_VERSION = "awoooi_public_gitea_actions_queue_readback_v1"
EXPECTED_HARBOR_110_REPAIR_JOB_NAMES = {
"workflow-shape",
"harbor-110-local-repair",
}
CD_WORKFLOW_JOB_NAMES = {
"build-and-deploy",
"post-deploy-checks",
"tests",
}
_RUN_ROW_RE = re.compile(
r'<span data-tooltip-content="([^"]+)">.*?'
r"<span><b>([^<]+)</b>:</span>([^<]+)</div>",
re.S,
)
_RUN_ITEM_SPLIT_RE = re.compile(r'<div class="flex-item tw-items-center">')
_RUN_LINK_RE = re.compile(
r'<a class="flex-item-title" title="([^"]*)" '
r'href="/wooo/awoooi/actions/runs/(\d+)">',
re.S,
)
_RUN_STATUS_RE = re.compile(r'<span data-tooltip-content="([^"]+)">')
_RUN_BODY_RE = re.compile(r"<span><b>([^<]+)</b>:</span>\s*([^<]+)", re.S)
_RUN_COMMIT_RE = re.compile(r"/wooo/awoooi/commit/([0-9a-f]{40})")
_RUN_NAME_RE = re.compile(r"^(?P<workflow>.+)\s+#(?P<run_id>\d+)$")
_WORKFLOW_FILTER_ITEM_RE = re.compile(
r'<a class="item" href="\?workflow=(?P<workflow>[^"&]+)[^"]*">'
r"(?P<body>.*?)</a>",
re.S,
)
_NO_MATCHING_LABEL_RE = re.compile(
r"No matching online runner with label:\s*(?P<label>[A-Za-z0-9_.:-]+)"
)
_HARBOR_ATTEMPT_RE = re.compile(
r"harbor_login_attempt=(?P<attempt>\d+)\s+registry_v2_status=(?P<status>\d{3})"
)
_HARBOR_BLOCKER_RE = re.compile(
r"BLOCKER harbor_registry_public_route_unavailable "
r"registry_v2_status=(?P<status>\d{3})"
)
_HARBOR_CONTROLLED_REPAIR_SKIP_RE = re.compile(
r"harbor_controlled_repair_skipped=(?P<reason>[A-Za-z0-9_.:-]+)"
)
_HARBOR_CONTROLLED_REPAIR_STATUS_RE = re.compile(
r"harbor_controlled_repair_public_registry_v2_status=(?P<status>\d{3})"
)
_HARBOR_110_REMOTE_SSH_REACHABLE_RE = re.compile(
r"harbor_110_remote_ssh_reachable=(?P<reachable>true|false)"
)
_HARBOR_110_REMOTE_SSH_TIMEOUT_RE = re.compile(
r"(Connection to 192\.168\.0\.110 port 22 timed out|"
r"ssh: connect to host 192\.168\.0\.110 port 22: Operation timed out)"
)
_HARBOR_110_REMOTE_SSH_BOOL_RE_TEMPLATE = (
r"{name}=(?P<value>true|false)"
)
_HARBOR_110_REMOTE_LOCAL_V2_STATUS_RE = re.compile(
r"harbor_110_remote_local_v2_http_status=(?P<status>\d{3})"
)
_HARBOR_110_PUBLIC_V2_STATUS_RE = re.compile(
r"harbor_public_registry_v2_http_status=(?P<status>\d{3})"
)
_HARBOR_110_REMOTE_LOCAL_V2_BLOCKER_RE = re.compile(
r"BLOCKED harbor_110_remote_local_registry_v2_unavailable "
r"status=(?P<status>\d{3})"
)
_HARBOR_110_PUBLIC_V2_BLOCKER_RE = re.compile(
r"BLOCKED harbor_public_registry_v2_unavailable status=(?P<status>\d{3})"
)
_HOST_PRESSURE_ATTEMPT_RE = re.compile(
r"host web/build/smoke pressure detected "
r"\(attempt (?P<attempt>\d+)/(?P<limit>\d+)\)"
)
_HOST_PRESSURE_LOAD_RE = re.compile(
r"host load5/core (?P<load>[0-9.]+) > (?P<threshold>[0-9.]+)"
)
_HOST_PRESSURE_POSTGRES_RE = re.compile(
r"(?P<container>k3s-postgres-recovery) CPU cores "
r"(?P<cores>[0-9.]+) > (?P<threshold>[0-9.]+)"
)
_HOST_PRESSURE_REFUSAL_RE = re.compile(
r"refusing to start AWOOI image build while host web/build/smoke pressure is still active"
)
_HOST_PRESSURE_INTERRUPTED_RE = re.compile(r"signal:\s*interrupt")
@dataclass(frozen=True)
class HttpRead:
http_status: int
text: str
def fetch_public_url(url: str, timeout_seconds: float) -> HttpRead:
request = urllib.request.Request(
url,
headers={"User-Agent": "awoooi-public-gitea-actions-readback/1.0"},
)
try:
with urllib.request.urlopen(request, timeout=timeout_seconds) as response:
raw = response.read()
status = int(getattr(response, "status", 200))
except urllib.error.HTTPError as exc:
raw = exc.read()
status = int(exc.code)
return HttpRead(
http_status=status,
text=raw.decode("utf-8", errors="replace"),
)
def parse_visible_runs(
actions_html: str,
*,
workflow_hint: str = "",
) -> list[dict[str, str]]:
visible_runs: list[dict[str, str]] = []
for chunk in _RUN_ITEM_SPLIT_RE.split(actions_html)[1:]:
status_match = _RUN_STATUS_RE.search(chunk)
link_match = _RUN_LINK_RE.search(chunk)
body_match = _RUN_BODY_RE.search(chunk)
if not status_match or not link_match or not body_match:
continue
raw_status = status_match.group(1)
raw_title = link_match.group(1)
raw_run_id = link_match.group(2)
raw_name = body_match.group(1)
raw_kind = body_match.group(2)
commit_match = _RUN_COMMIT_RE.search(chunk)
visible_runs.append(
_visible_run_from_parts(
raw_status=raw_status,
raw_name=raw_name,
raw_kind=raw_kind,
raw_run_id=raw_run_id,
raw_title=raw_title,
raw_commit_sha=commit_match.group(1) if commit_match else "",
workflow_hint=workflow_hint,
)
)
if visible_runs:
return visible_runs
for raw_status, raw_name, raw_kind in _RUN_ROW_RE.findall(actions_html):
visible_runs.append(
_visible_run_from_parts(
raw_status=raw_status,
raw_name=raw_name,
raw_kind=raw_kind,
workflow_hint=workflow_hint,
)
)
return visible_runs
def parse_workflow_no_matching_labels(actions_html: str) -> dict[str, str]:
labels: dict[str, str] = {}
for match in _WORKFLOW_FILTER_ITEM_RE.finditer(actions_html):
label_match = _NO_MATCHING_LABEL_RE.search(match.group("body"))
if not label_match:
continue
workflow = html.unescape(unquote(match.group("workflow"))).strip()
labels[workflow] = label_match.group("label")
return labels
def merge_visible_runs(
primary_runs: list[dict[str, str]],
fallback_runs: list[dict[str, str]],
) -> list[dict[str, str]]:
merged: list[dict[str, str]] = []
seen: set[tuple[str, str]] = set()
for run in primary_runs + fallback_runs:
key = (run.get("workflow", ""), run.get("run_id", ""))
if key in seen:
continue
seen.add(key)
merged.append(run)
return merged
def _visible_run_from_parts(
*,
raw_status: str,
raw_name: str,
raw_kind: str,
raw_run_id: str = "",
raw_title: str = "",
raw_commit_sha: str = "",
workflow_hint: str = "",
) -> dict[str, str]:
name = html.unescape(raw_name).strip()
kind = html.unescape(raw_kind).strip()
status = html.unescape(raw_status).strip()
match = _RUN_NAME_RE.match(name)
workflow = match.group("workflow") if match else (workflow_hint or name)
run_id = raw_run_id or (match.group("run_id") if match else "")
label_match = _NO_MATCHING_LABEL_RE.search(status)
return {
"run_id": run_id,
"workflow": workflow,
"kind": kind,
"status": status,
"title": html.unescape(raw_title).strip(),
"commit_sha": raw_commit_sha,
"no_matching_runner_label": (
label_match.group("label") if label_match else ""
),
}
def build_readback(
*,
actions_html: str,
cd_workflow_actions_html: str = "",
actions_list_http_status: int,
actions_list_payload: Any,
cd_jobs_http_status: int,
cd_jobs_payload: Any,
harbor_110_repair_jobs_http_status: int = 0,
harbor_110_repair_jobs_payload: Any | None = None,
latest_cd_build_log_http_status: int = 0,
latest_cd_build_log_text: str = "",
latest_cd_tests_log_http_status: int = 0,
latest_cd_tests_log_text: str = "",
latest_harbor_110_repair_log_http_status: int = 0,
latest_harbor_110_repair_log_text: str = "",
) -> dict[str, Any]:
visible_runs = parse_visible_runs(actions_html)
cd_workflow_visible_runs = parse_visible_runs(
cd_workflow_actions_html,
workflow_hint="cd.yaml",
)
combined_visible_runs = merge_visible_runs(visible_runs, cd_workflow_visible_runs)
workflow_no_matching_labels = parse_workflow_no_matching_labels(actions_html)
no_matching = next(
(run for run in combined_visible_runs if run["no_matching_runner_label"]),
{},
)
workflow_no_matching = next(
(
{"workflow": workflow, "no_matching_runner_label": label}
for workflow, label in workflow_no_matching_labels.items()
),
{},
)
latest_cd_run = next(
(run for run in combined_visible_runs if run.get("workflow") == "cd.yaml"),
{},
)
latest_harbor_110_repair_run = next(
(
run
for run in combined_visible_runs
if run.get("workflow") == "harbor-110-local-repair.yaml"
),
{},
)
cd_workflow_fallback_used = bool(
latest_cd_run
and not any(run.get("workflow") == "cd.yaml" for run in visible_runs)
)
cd_jobs = cd_jobs_payload if isinstance(cd_jobs_payload, dict) else {}
harbor_110_repair_jobs = (
harbor_110_repair_jobs_payload
if isinstance(harbor_110_repair_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 "")
jobs_total_count = _int(cd_jobs.get("total_count"))
jobs = cd_jobs.get("jobs") if isinstance(cd_jobs.get("jobs"), list) else []
harbor_jobs_total_count = _int(harbor_110_repair_jobs.get("total_count"))
harbor_jobs = (
harbor_110_repair_jobs.get("jobs")
if isinstance(harbor_110_repair_jobs.get("jobs"), list)
else []
)
latest_cd_run_id = latest_cd_run.get("run_id", "")
latest_cd_commit_sha = latest_cd_run.get("commit_sha", "")
job_head_shas = sorted(
{
str(job.get("head_sha") or "")
for job in jobs
if isinstance(job, dict) and job.get("head_sha")
}
)
job_run_ids = sorted(
{
str(job.get("run_id") or "")
for job in jobs
if isinstance(job, dict) and job.get("run_id") is not None
}
)
job_conclusion_counts: dict[str, int] = {}
for job in jobs:
if isinstance(job, dict):
conclusion = str(job.get("conclusion") or job.get("status") or "unknown")
job_conclusion_counts[conclusion] = job_conclusion_counts.get(conclusion, 0) + 1
harbor_job_conclusion_counts: dict[str, int] = {}
harbor_job_run_ids: set[str] = set()
harbor_job_names: set[str] = set()
harbor_job_labels: set[str] = set()
harbor_job_runner_names: set[str] = set()
for job in harbor_jobs:
if not isinstance(job, dict):
continue
job_name = str(job.get("name") or "")
if job_name:
harbor_job_names.add(job_name)
conclusion = str(job.get("conclusion") or job.get("status") or "unknown")
harbor_job_conclusion_counts[conclusion] = (
harbor_job_conclusion_counts.get(conclusion, 0) + 1
)
if job.get("run_id") is not None:
harbor_job_run_ids.add(str(job.get("run_id")))
labels = job.get("labels")
if isinstance(labels, list):
harbor_job_labels.update(str(label) for label in labels if label)
runner_name = str(job.get("runner_name") or "")
if runner_name:
harbor_job_runner_names.add(runner_name)
cd_jobs_head_sha_matches_visible = (
bool(latest_cd_commit_sha)
and latest_cd_commit_sha in job_head_shas
)
cd_jobs_run_id_matches_visible = (
bool(latest_cd_run_id)
and latest_cd_run_id in job_run_ids
)
cd_jobs_stale_or_mismatched = (
cd_jobs_http_status == 200
and jobs_total_count > 0
and bool(latest_cd_run)
and (
not cd_jobs_head_sha_matches_visible
or not cd_jobs_run_id_matches_visible
)
)
cd_jobs_head_sha_mismatch = (
cd_jobs_http_status == 200
and jobs_total_count > 0
and bool(latest_cd_commit_sha)
and not cd_jobs_head_sha_matches_visible
)
cd_jobs_run_id_mismatch = (
cd_jobs_http_status == 200
and jobs_total_count > 0
and bool(latest_cd_run_id)
and not cd_jobs_run_id_matches_visible
)
cd_jobs_payload_classifier = (
"cd_jobs_api_head_sha_and_run_id_mismatch_for_visible_cd_run"
if cd_jobs_head_sha_mismatch and cd_jobs_run_id_mismatch
else "cd_jobs_api_head_sha_mismatch_for_visible_cd_run"
if cd_jobs_head_sha_mismatch
else "cd_jobs_api_run_id_mismatch_for_visible_cd_run"
if cd_jobs_run_id_mismatch
else "cd_jobs_api_stale_or_mismatched_payload"
if cd_jobs_stale_or_mismatched
else ""
)
build_log_classifier = classify_cd_build_log(latest_cd_build_log_text)
tests_log_classifier = classify_cd_tests_log(latest_cd_tests_log_text)
harbor_110_repair_log_classifier = classify_harbor_110_repair_log(
latest_harbor_110_repair_log_text
)
latest_cd_status = latest_cd_run.get("status", "")
latest_cd_visible_blocked = latest_cd_status == "Blocked"
latest_cd_waiting = latest_cd_status == "Waiting"
host_pressure_waiting_from_stale_jobs = (
cd_jobs_stale_or_mismatched
and latest_cd_status in {"Blocked", "Canceled", "Failure"}
and tests_log_classifier["host_pressure_waiting"]
and not tests_log_classifier["host_pressure_refused"]
)
effective_tests_log_classifier = dict(tests_log_classifier)
if host_pressure_waiting_from_stale_jobs:
effective_tests_log_classifier["host_pressure_classifier"] = (
"host_web_build_pressure_waiting_from_stale_jobs_payload"
)
effective_tests_log_classifier["host_pressure_waiting"] = False
effective_tests_log_classifier["host_pressure_blocked_or_waiting"] = False
latest_cd_no_matching_runner_label = (
latest_cd_run.get("no_matching_runner_label", "")
or workflow_no_matching_labels.get("cd.yaml", "")
)
controlled_profile_no_matching_runner_labels = {
workflow: label
for workflow, label in workflow_no_matching_labels.items()
if label.startswith("awoooi-non110")
}
harbor_110_repair_status = latest_harbor_110_repair_run.get("status", "")
harbor_110_repair_run_id = latest_harbor_110_repair_run.get("run_id", "")
harbor_110_repair_no_matching_runner_label = (
latest_harbor_110_repair_run.get("no_matching_runner_label", "")
or workflow_no_matching_labels.get("harbor-110-local-repair.yaml", "")
)
harbor_110_repair_waiting = harbor_110_repair_status == "Waiting"
harbor_110_repair_running = harbor_110_repair_status == "Running"
harbor_110_repair_failed = harbor_110_repair_status == "Failure"
harbor_110_repair_status_blocked = harbor_110_repair_status == "Blocked"
harbor_110_repair_jobs_run_id_matches_visible = (
bool(harbor_110_repair_run_id)
and harbor_110_repair_run_id in harbor_job_run_ids
)
harbor_110_repair_jobs_unexpected_names = sorted(
harbor_job_names - EXPECTED_HARBOR_110_REPAIR_JOB_NAMES
)
harbor_110_repair_jobs_cross_workflow_mismatch = (
bool(harbor_job_names)
and harbor_job_names.issubset(CD_WORKFLOW_JOB_NAMES)
)
harbor_110_repair_jobs_payload_classifier = (
"cd_workflow_jobs_returned_for_harbor_110_repair_run"
if harbor_110_repair_jobs_cross_workflow_mismatch
else "unexpected_harbor_110_repair_job_names"
if harbor_110_repair_jobs_unexpected_names
else ""
)
harbor_110_repair_jobs_match_expected_workflow = (
bool(harbor_job_names)
and not harbor_110_repair_jobs_unexpected_names
and "harbor-110-local-repair" in harbor_job_names
)
harbor_110_repair_jobs_stale_or_mismatched = (
harbor_110_repair_jobs_http_status == 200
and harbor_jobs_total_count > 0
and not harbor_110_repair_jobs_match_expected_workflow
)
harbor_110_repair_jobs_all_success = (
harbor_110_repair_jobs_http_status == 200
and harbor_jobs_total_count > 0
and harbor_110_repair_jobs_match_expected_workflow
and harbor_job_conclusion_counts.get("success") == harbor_jobs_total_count
and harbor_110_repair_jobs_run_id_matches_visible
)
harbor_110_repair_visible_waiting_stale = (
harbor_110_repair_waiting and harbor_110_repair_jobs_all_success
)
harbor_110_repair_visible_failure_jobs_api_stale = (
harbor_110_repair_failed and harbor_110_repair_jobs_stale_or_mismatched
)
cd_harbor_repair_requires_110_controlled_lane = (
build_log_classifier["harbor_public_route_blocked_or_retrying"]
and build_log_classifier["harbor_controlled_repair_skip_reason"]
== "not_110_host"
)
cd_harbor_repair_blocked_by_no_matching_awoooi_host = (
cd_harbor_repair_requires_110_controlled_lane
and harbor_110_repair_no_matching_runner_label == "awoooi-host"
)
cd_harbor_repair_lane_classifier = (
"cd_harbor_repair_requires_110_controlled_lane_no_matching_awoooi_host"
if cd_harbor_repair_blocked_by_no_matching_awoooi_host
else "cd_harbor_repair_requires_110_controlled_lane_waiting"
if cd_harbor_repair_requires_110_controlled_lane
and harbor_110_repair_waiting
else "cd_harbor_repair_requires_110_controlled_lane"
if cd_harbor_repair_requires_110_controlled_lane
else ""
)
harbor_110_repair_waiting_after_cd_harbor_blocker = (
build_log_classifier["harbor_public_route_blocked_or_retrying"]
and harbor_110_repair_waiting
)
harbor_110_repair_blocked = (
harbor_110_repair_status_blocked
or harbor_110_repair_failed
or bool(harbor_110_repair_no_matching_runner_label)
or harbor_110_repair_waiting_after_cd_harbor_blocker
or bool(harbor_110_repair_log_classifier["failure_classifier"])
)
readback = {
"actions_page_visible_run_count": len(visible_runs),
"cd_workflow_actions_page_visible_run_count": len(cd_workflow_visible_runs),
"cd_workflow_fallback_used": cd_workflow_fallback_used,
"actions_list_without_token_http_status": actions_list_http_status,
"actions_list_without_token_message": actions_list_message,
"cd_run_jobs_http_status": cd_jobs_http_status,
"cd_run_jobs_total_count": jobs_total_count,
"cd_run_jobs_expected_run_id": latest_cd_run_id,
"cd_run_jobs_expected_head_sha": latest_cd_commit_sha,
"cd_run_jobs_head_shas": job_head_shas,
"cd_run_jobs_run_ids": job_run_ids,
"cd_run_jobs_conclusion_counts": job_conclusion_counts,
"cd_run_jobs_head_sha_matches_visible": cd_jobs_head_sha_matches_visible,
"cd_run_jobs_run_id_matches_visible": cd_jobs_run_id_matches_visible,
"cd_run_jobs_head_sha_mismatch": cd_jobs_head_sha_mismatch,
"cd_run_jobs_run_id_mismatch": cd_jobs_run_id_mismatch,
"cd_run_jobs_stale_or_mismatched": cd_jobs_stale_or_mismatched,
"cd_run_jobs_payload_classifier": cd_jobs_payload_classifier,
"latest_visible_no_matching_runner_run_id": no_matching.get("run_id", ""),
"latest_visible_no_matching_runner_workflow": no_matching.get(
"workflow", workflow_no_matching.get("workflow", "")
),
"latest_visible_no_matching_runner_kind": no_matching.get("kind", ""),
"latest_visible_no_matching_runner_status": no_matching.get("status", ""),
"latest_visible_no_matching_runner_label": no_matching.get(
"no_matching_runner_label",
workflow_no_matching.get("no_matching_runner_label", ""),
),
"workflow_no_matching_runner_labels": workflow_no_matching_labels,
"latest_visible_cd_run_id": latest_cd_run.get("run_id", ""),
"latest_visible_cd_run_status": latest_cd_status,
"latest_visible_cd_run_waiting": latest_cd_waiting,
"latest_visible_cd_run_blocked": latest_cd_visible_blocked,
"latest_visible_cd_run_kind": latest_cd_run.get("kind", ""),
"latest_visible_cd_run_title": latest_cd_run.get("title", ""),
"latest_visible_cd_run_commit_sha": latest_cd_run.get("commit_sha", ""),
"latest_visible_cd_no_matching_runner_label": (
latest_cd_no_matching_runner_label
),
"controlled_profile_no_matching_runner_labels": (
controlled_profile_no_matching_runner_labels
),
"controlled_profile_no_matching_runner_label_count": len(
controlled_profile_no_matching_runner_labels
),
"latest_visible_cd_build_log_http_status": latest_cd_build_log_http_status,
"latest_visible_cd_failure_classifier": build_log_classifier[
"failure_classifier"
],
"latest_visible_cd_failure_status_code": build_log_classifier[
"failure_status_code"
],
"latest_visible_cd_inflight_classifier": build_log_classifier[
"inflight_classifier"
],
"latest_visible_cd_harbor_latest_registry_v2_status": (
build_log_classifier["harbor_latest_registry_v2_status"]
),
"latest_visible_cd_harbor_login_attempt_count": build_log_classifier[
"harbor_login_attempt_count"
],
"latest_visible_cd_harbor_controlled_repair_attempted": build_log_classifier[
"harbor_controlled_repair_attempted"
],
"latest_visible_cd_harbor_controlled_repair_skip_reason": build_log_classifier[
"harbor_controlled_repair_skip_reason"
],
"latest_visible_cd_harbor_controlled_repair_public_registry_v2_status": (
build_log_classifier[
"harbor_controlled_repair_public_registry_v2_status"
]
),
"latest_visible_cd_harbor_repair_requires_110_controlled_lane": (
cd_harbor_repair_requires_110_controlled_lane
),
"latest_visible_cd_harbor_repair_blocked_by_no_matching_awoooi_host": (
cd_harbor_repair_blocked_by_no_matching_awoooi_host
),
"latest_visible_cd_harbor_repair_lane_classifier": (
cd_harbor_repair_lane_classifier
),
"latest_visible_cd_harbor_public_route_blocked": build_log_classifier[
"harbor_public_route_blocked"
],
"latest_visible_cd_harbor_public_route_retrying_unavailable": (
build_log_classifier["harbor_public_route_retrying_unavailable"]
),
"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": (
harbor_110_repair_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_failed": harbor_110_repair_failed,
"latest_visible_harbor_110_repair_status_blocked": (
harbor_110_repair_status_blocked
),
"latest_visible_harbor_110_repair_blocked": harbor_110_repair_blocked,
"latest_visible_harbor_110_repair_log_http_status": (
latest_harbor_110_repair_log_http_status
),
"latest_visible_harbor_110_repair_failure_classifier": (
harbor_110_repair_log_classifier["failure_classifier"]
),
"latest_visible_harbor_110_repair_remote_control_channel_unavailable": (
harbor_110_repair_log_classifier["remote_control_channel_unavailable"]
),
"latest_visible_harbor_110_repair_remote_ssh_reachable": (
harbor_110_repair_log_classifier["remote_ssh_reachable"]
),
"latest_visible_harbor_110_repair_bounded_ssh_timeout_seen": (
harbor_110_repair_log_classifier["bounded_ssh_timeout_seen"]
),
"latest_visible_harbor_110_repair_remote_ssh_tcp_connected": (
harbor_110_repair_log_classifier["remote_ssh_tcp_connected"]
),
"latest_visible_harbor_110_repair_remote_ssh_banner_seen": (
harbor_110_repair_log_classifier["remote_ssh_banner_seen"]
),
"latest_visible_harbor_110_repair_remote_ssh_userauth_service_accept_seen": (
harbor_110_repair_log_classifier[
"remote_ssh_userauth_service_accept_seen"
]
),
"latest_visible_harbor_110_repair_remote_ssh_publickey_offered": (
harbor_110_repair_log_classifier["remote_ssh_publickey_offered"]
),
"latest_visible_harbor_110_repair_remote_ssh_publickey_reply_timeout_seen": (
harbor_110_repair_log_classifier[
"remote_ssh_publickey_reply_timeout_seen"
]
),
"latest_visible_harbor_110_repair_remote_ssh_publickey_auth_stalled": (
harbor_110_repair_log_classifier["remote_ssh_publickey_auth_stalled"]
),
"latest_visible_harbor_110_repair_remote_ssh_server_accepts_key_then_session_timeout": (
harbor_110_repair_log_classifier[
"remote_ssh_server_accepts_key_then_session_timeout"
]
),
"latest_visible_harbor_110_repair_remote_ssh_auth_permission_denied": (
harbor_110_repair_log_classifier["remote_ssh_auth_permission_denied"]
),
"latest_visible_harbor_110_repair_local_registry_v2_status": (
harbor_110_repair_log_classifier["local_registry_v2_status"]
),
"latest_visible_harbor_110_repair_public_registry_v2_status": (
harbor_110_repair_log_classifier["public_registry_v2_status"]
),
"latest_visible_harbor_110_repair_verified": (
harbor_110_repair_log_classifier["repair_verified"]
),
"harbor_110_repair_waiting_after_cd_harbor_blocker": (
harbor_110_repair_waiting_after_cd_harbor_blocker
),
"harbor_110_repair_jobs_http_status": harbor_110_repair_jobs_http_status,
"harbor_110_repair_jobs_total_count": harbor_jobs_total_count,
"harbor_110_repair_jobs_conclusion_counts": harbor_job_conclusion_counts,
"harbor_110_repair_jobs_run_ids": sorted(harbor_job_run_ids),
"harbor_110_repair_jobs_names": sorted(harbor_job_names),
"harbor_110_repair_jobs_expected_names": sorted(
EXPECTED_HARBOR_110_REPAIR_JOB_NAMES
),
"harbor_110_repair_jobs_unexpected_names": (
harbor_110_repair_jobs_unexpected_names
),
"harbor_110_repair_jobs_cross_workflow_mismatch": (
harbor_110_repair_jobs_cross_workflow_mismatch
),
"harbor_110_repair_jobs_payload_classifier": (
harbor_110_repair_jobs_payload_classifier
),
"harbor_110_repair_jobs_labels": sorted(harbor_job_labels),
"harbor_110_repair_jobs_runner_names": sorted(harbor_job_runner_names),
"harbor_110_repair_jobs_run_id_matches_visible": (
harbor_110_repair_jobs_run_id_matches_visible
),
"harbor_110_repair_jobs_match_expected_workflow": (
harbor_110_repair_jobs_match_expected_workflow
),
"harbor_110_repair_jobs_stale_or_mismatched": (
harbor_110_repair_jobs_stale_or_mismatched
),
"harbor_110_repair_jobs_all_success": harbor_110_repair_jobs_all_success,
"harbor_110_repair_visible_waiting_stale": (
harbor_110_repair_visible_waiting_stale
),
"harbor_110_repair_visible_failure_jobs_api_stale": (
harbor_110_repair_visible_failure_jobs_api_stale
),
"latest_visible_cd_host_pressure_classifier": effective_tests_log_classifier[
"host_pressure_classifier"
],
"latest_visible_cd_host_pressure_attempt_count": effective_tests_log_classifier[
"host_pressure_attempt_count"
],
"latest_visible_cd_host_pressure_attempt_limit": effective_tests_log_classifier[
"host_pressure_attempt_limit"
],
"latest_visible_cd_host_pressure_latest_load5_per_core": (
effective_tests_log_classifier["latest_load5_per_core"]
),
"latest_visible_cd_host_pressure_load5_threshold": effective_tests_log_classifier[
"load5_per_core_threshold"
],
"latest_visible_cd_host_pressure_waiting": effective_tests_log_classifier[
"host_pressure_waiting"
],
"latest_visible_cd_host_pressure_refused": effective_tests_log_classifier[
"host_pressure_refused"
],
"latest_visible_cd_host_pressure_interrupted": effective_tests_log_classifier[
"host_pressure_interrupted"
],
"latest_visible_cd_postgres_recovery_cpu_pressure": (
effective_tests_log_classifier["postgres_recovery_cpu_pressure"]
),
"latest_visible_cd_postgres_recovery_cpu_cores": effective_tests_log_classifier[
"postgres_recovery_cpu_cores"
],
"latest_visible_cd_postgres_recovery_cpu_threshold": (
effective_tests_log_classifier["postgres_recovery_cpu_threshold"]
),
"latest_visible_cd_host_pressure_log_stale_or_mismatched": (
host_pressure_waiting_from_stale_jobs
),
"no_matching_online_runner_visible": bool(no_matching)
or bool(workflow_no_matching_labels),
"top_visible_runs": combined_visible_runs[:10],
"cd_workflow_visible_runs": cd_workflow_visible_runs[:10],
}
return {
"schema_version": SCHEMA_VERSION,
"status": (
"blocked_no_matching_online_runner"
if no_matching
else "blocked_latest_visible_cd_run"
if latest_cd_visible_blocked
else "blocked_current_cd_workflow_waiting_for_runner_or_queue"
if latest_cd_waiting
else "blocked_harbor_110_remote_ssh_publickey_auth_stalled"
if harbor_110_repair_log_classifier["remote_ssh_publickey_auth_stalled"]
else "blocked_harbor_110_remote_control_channel_unavailable"
if harbor_110_repair_log_classifier["remote_control_channel_unavailable"]
else "blocked_harbor_110_remote_local_registry_v2_unavailable"
if harbor_110_repair_log_classifier["local_registry_v2_unavailable"]
else "blocked_harbor_public_registry_v2_unavailable_after_remote_repair"
if harbor_110_repair_log_classifier["public_registry_v2_unavailable"]
else "blocked_harbor_110_repair_failed"
if (
build_log_classifier["harbor_public_route_blocked_or_retrying"]
and harbor_110_repair_failed
)
else (
"blocked_harbor_public_route_unavailable_after_harbor_110_repair_success"
)
if (
build_log_classifier["harbor_public_route_blocked_or_retrying"]
and harbor_110_repair_jobs_all_success
)
else "blocked_harbor_110_repair_no_matching_runner"
if (
build_log_classifier["harbor_public_route_blocked_or_retrying"]
and harbor_110_repair_no_matching_runner_label
)
else "blocked_harbor_110_repair_workflow_waiting"
if (
build_log_classifier["harbor_public_route_blocked_or_retrying"]
and harbor_110_repair_waiting_after_cd_harbor_blocker
)
else "blocked_harbor_public_route_unavailable"
if build_log_classifier["harbor_public_route_blocked"]
else "blocked_harbor_public_route_unavailable_pending_retry"
if build_log_classifier["harbor_public_route_retrying_unavailable"]
else "blocked_host_web_build_pressure"
if effective_tests_log_classifier["host_pressure_blocked_or_waiting"]
else "blocked_harbor_110_repair_no_matching_runner"
if harbor_110_repair_no_matching_runner_label
else "blocked_no_matching_online_runner"
if workflow_no_matching
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_failed"
if harbor_110_repair_failed
else "blocked_harbor_110_repair_run"
if harbor_110_repair_blocked
else "harbor_110_repair_jobs_stale_or_mismatched"
if harbor_110_repair_jobs_stale_or_mismatched
else "cd_jobs_stale_or_mismatched"
if cd_jobs_stale_or_mismatched
else "no_matching_runner_not_visible"
),
"readback": readback,
"rollups": {
"public_actions_readback_count": len(visible_runs),
"cd_workflow_actions_readback_count": len(cd_workflow_visible_runs),
"cd_workflow_fallback_used": cd_workflow_fallback_used,
"actions_list_requires_token": actions_list_http_status == 401,
"cd_run_jobs_total_count": jobs_total_count,
"cd_run_jobs_head_sha_mismatch": cd_jobs_head_sha_mismatch,
"cd_run_jobs_run_id_mismatch": cd_jobs_run_id_mismatch,
"cd_run_jobs_stale_or_mismatched": cd_jobs_stale_or_mismatched,
"cd_run_jobs_payload_classifier": cd_jobs_payload_classifier,
"current_main_cd_run_visible": bool(latest_cd_run),
"current_main_cd_run_status": latest_cd_status,
"current_main_cd_run_waiting": latest_cd_waiting,
"current_main_cd_run_blocked": latest_cd_visible_blocked,
"current_main_cd_no_matching_runner_label": (
latest_cd_no_matching_runner_label
),
"controlled_profile_no_matching_runner_label_count": len(
controlled_profile_no_matching_runner_labels
),
"controlled_profile_no_matching_runner_labels": (
controlled_profile_no_matching_runner_labels
),
"current_main_cd_failure_classifier": build_log_classifier[
"failure_classifier"
],
"current_main_cd_inflight_classifier": build_log_classifier[
"inflight_classifier"
],
"current_main_cd_harbor_public_route_blocked": build_log_classifier[
"harbor_public_route_blocked"
],
"current_main_cd_harbor_public_route_retrying_unavailable": (
build_log_classifier["harbor_public_route_retrying_unavailable"]
),
"current_main_cd_harbor_latest_registry_v2_status": (
build_log_classifier["harbor_latest_registry_v2_status"]
),
"current_main_cd_harbor_controlled_repair_attempted": build_log_classifier[
"harbor_controlled_repair_attempted"
],
"current_main_cd_harbor_controlled_repair_skip_reason": (
build_log_classifier["harbor_controlled_repair_skip_reason"]
),
"current_main_cd_harbor_repair_requires_110_controlled_lane": (
cd_harbor_repair_requires_110_controlled_lane
),
"current_main_cd_harbor_repair_blocked_by_no_matching_awoooi_host": (
cd_harbor_repair_blocked_by_no_matching_awoooi_host
),
"current_main_cd_harbor_repair_lane_classifier": (
cd_harbor_repair_lane_classifier
),
"current_main_cd_host_pressure_classifier": effective_tests_log_classifier[
"host_pressure_classifier"
],
"current_main_cd_host_pressure_waiting": effective_tests_log_classifier[
"host_pressure_waiting"
],
"current_main_cd_host_pressure_refused": effective_tests_log_classifier[
"host_pressure_refused"
],
"current_main_cd_host_pressure_interrupted": (
effective_tests_log_classifier["host_pressure_interrupted"]
),
"current_main_cd_postgres_recovery_cpu_pressure": (
effective_tests_log_classifier["postgres_recovery_cpu_pressure"]
),
"current_main_cd_host_pressure_log_stale_or_mismatched": (
host_pressure_waiting_from_stale_jobs
),
"no_matching_online_runner_visible": bool(no_matching)
or bool(workflow_no_matching_labels),
"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_failed": harbor_110_repair_failed,
"harbor_110_repair_blocked": harbor_110_repair_blocked,
"harbor_110_repair_waiting_after_cd_harbor_blocker": (
harbor_110_repair_waiting_after_cd_harbor_blocker
),
"harbor_110_repair_failure_classifier": (
harbor_110_repair_log_classifier["failure_classifier"]
),
"harbor_110_repair_remote_control_channel_unavailable": (
harbor_110_repair_log_classifier["remote_control_channel_unavailable"]
),
"harbor_110_repair_remote_ssh_reachable": (
harbor_110_repair_log_classifier["remote_ssh_reachable"]
),
"harbor_110_repair_bounded_ssh_timeout_seen": (
harbor_110_repair_log_classifier["bounded_ssh_timeout_seen"]
),
"harbor_110_repair_remote_ssh_tcp_connected": (
harbor_110_repair_log_classifier["remote_ssh_tcp_connected"]
),
"harbor_110_repair_remote_ssh_banner_seen": (
harbor_110_repair_log_classifier["remote_ssh_banner_seen"]
),
"harbor_110_repair_remote_ssh_userauth_service_accept_seen": (
harbor_110_repair_log_classifier[
"remote_ssh_userauth_service_accept_seen"
]
),
"harbor_110_repair_remote_ssh_publickey_offered": (
harbor_110_repair_log_classifier["remote_ssh_publickey_offered"]
),
"harbor_110_repair_remote_ssh_publickey_reply_timeout_seen": (
harbor_110_repair_log_classifier[
"remote_ssh_publickey_reply_timeout_seen"
]
),
"harbor_110_repair_remote_ssh_publickey_auth_stalled": (
harbor_110_repair_log_classifier["remote_ssh_publickey_auth_stalled"]
),
"harbor_110_repair_remote_ssh_server_accepts_key_then_session_timeout": (
harbor_110_repair_log_classifier[
"remote_ssh_server_accepts_key_then_session_timeout"
]
),
"harbor_110_repair_remote_ssh_auth_permission_denied": (
harbor_110_repair_log_classifier["remote_ssh_auth_permission_denied"]
),
"harbor_110_repair_local_registry_v2_status": (
harbor_110_repair_log_classifier["local_registry_v2_status"]
),
"harbor_110_repair_public_registry_v2_status": (
harbor_110_repair_log_classifier["public_registry_v2_status"]
),
"harbor_110_repair_verified": harbor_110_repair_log_classifier[
"repair_verified"
],
"harbor_110_repair_no_matching_runner_label": (
harbor_110_repair_no_matching_runner_label
),
"harbor_110_repair_jobs_total_count": harbor_jobs_total_count,
"harbor_110_repair_jobs_names": sorted(harbor_job_names),
"harbor_110_repair_jobs_expected_names": sorted(
EXPECTED_HARBOR_110_REPAIR_JOB_NAMES
),
"harbor_110_repair_jobs_stale_or_mismatched": (
harbor_110_repair_jobs_stale_or_mismatched
),
"harbor_110_repair_jobs_cross_workflow_mismatch": (
harbor_110_repair_jobs_cross_workflow_mismatch
),
"harbor_110_repair_jobs_payload_classifier": (
harbor_110_repair_jobs_payload_classifier
),
"harbor_110_repair_jobs_unexpected_names": (
harbor_110_repair_jobs_unexpected_names
),
"harbor_110_repair_jobs_all_success": (
harbor_110_repair_jobs_all_success
),
"harbor_110_repair_jobs_runner_names": sorted(harbor_job_runner_names),
"harbor_110_repair_visible_waiting_stale": (
harbor_110_repair_visible_waiting_stale
),
"harbor_110_repair_visible_failure_jobs_api_stale": (
harbor_110_repair_visible_failure_jobs_api_stale
),
},
"operation_boundaries": {
"public_gitea_read_only": True,
"token_required_but_not_collected": actions_list_http_status == 401,
"gitea_api_write_performed": False,
"workflow_dispatch_performed": False,
"host_write_performed": False,
"runner_registration_performed": False,
"runner_service_start_performed": False,
"secret_or_runner_token_read": False,
"github_api_used": False,
},
}
def classify_cd_build_log(text: str) -> dict[str, Any]:
attempt_statuses: list[str] = []
attempt_numbers: list[int] = []
for match in _HARBOR_ATTEMPT_RE.finditer(text):
attempt_numbers.append(_int(match.group("attempt")))
attempt_statuses.append(match.group("status"))
blocker_match = _HARBOR_BLOCKER_RE.search(text)
harbor_public_route_blocked = blocker_match is not None
failure_status_code = blocker_match.group("status") if blocker_match else ""
harbor_latest_registry_v2_status = attempt_statuses[-1] if attempt_statuses else ""
harbor_public_route_retrying_unavailable = (
not harbor_public_route_blocked
and bool(attempt_statuses)
and harbor_latest_registry_v2_status not in {"200", "401"}
)
repair_skip_matches = list(_HARBOR_CONTROLLED_REPAIR_SKIP_RE.finditer(text))
repair_status_matches = list(_HARBOR_CONTROLLED_REPAIR_STATUS_RE.finditer(text))
repair_attempted = (
"harbor_controlled_repair_check_start=1" in text
or bool(repair_skip_matches)
or bool(repair_status_matches)
)
return {
"failure_classifier": (
"harbor_registry_public_route_unavailable"
if harbor_public_route_blocked
else ""
),
"failure_status_code": failure_status_code,
"inflight_classifier": (
"harbor_registry_public_route_unavailable_pending_retry"
if harbor_public_route_retrying_unavailable
else ""
),
"harbor_latest_registry_v2_status": harbor_latest_registry_v2_status,
"harbor_login_attempt_count": max(attempt_numbers) if attempt_numbers else 0,
"harbor_controlled_repair_attempted": repair_attempted,
"harbor_controlled_repair_skip_reason": (
repair_skip_matches[-1].group("reason") if repair_skip_matches else ""
),
"harbor_controlled_repair_public_registry_v2_status": (
repair_status_matches[-1].group("status") if repair_status_matches else ""
),
"harbor_public_route_blocked": harbor_public_route_blocked,
"harbor_public_route_retrying_unavailable": (
harbor_public_route_retrying_unavailable
),
"harbor_public_route_blocked_or_retrying": (
harbor_public_route_blocked or harbor_public_route_retrying_unavailable
),
"harbor_registry_v2_statuses": attempt_statuses[-12:],
}
def classify_harbor_110_repair_log(text: str) -> dict[str, Any]:
ssh_reachable_matches = list(_HARBOR_110_REMOTE_SSH_REACHABLE_RE.finditer(text))
remote_ssh_reachable: bool | None = None
if ssh_reachable_matches:
remote_ssh_reachable = (
ssh_reachable_matches[-1].group("reachable") == "true"
)
bounded_ssh_timeout_seen = _HARBOR_110_REMOTE_SSH_TIMEOUT_RE.search(text) is not None
remote_ssh_tcp_connected = _last_bool_marker(
"harbor_110_remote_ssh_tcp_connected",
text,
)
remote_ssh_banner_seen = _last_bool_marker(
"harbor_110_remote_ssh_banner_seen",
text,
)
remote_ssh_userauth_service_accept_seen = _last_bool_marker(
"harbor_110_remote_ssh_userauth_service_accept_seen",
text,
)
remote_ssh_publickey_offered = _last_bool_marker(
"harbor_110_remote_ssh_publickey_offered",
text,
)
remote_ssh_publickey_reply_timeout_seen = _last_bool_marker(
"harbor_110_remote_ssh_publickey_reply_timeout_seen",
text,
)
remote_ssh_publickey_auth_stalled = (
"harbor_110_remote_ssh_publickey_auth_stalled=true" in text
or "BLOCKED harbor_110_remote_ssh_publickey_auth_stalled" in text
or (
remote_ssh_userauth_service_accept_seen is True
and remote_ssh_publickey_offered is True
and remote_ssh_publickey_reply_timeout_seen is True
)
)
remote_ssh_server_accepts_key_then_session_timeout = (
"harbor_110_remote_ssh_server_accepts_key_then_session_timeout=true" in text
or "classification=server_accepts_key_then_timeout" in text
or (
("Server accepts key" in text or "server_accepts_key_then_timeout" in text)
and _HARBOR_110_REMOTE_SSH_TIMEOUT_RE.search(text) is not None
)
)
remote_ssh_auth_permission_denied = _last_bool_marker(
"harbor_110_remote_ssh_auth_permission_denied",
text,
)
remote_control_channel_unavailable = (
"harbor_110_remote_control_channel_unavailable" in text
or (bounded_ssh_timeout_seen and remote_ssh_reachable is False)
or remote_ssh_publickey_auth_stalled
)
local_registry_v2_unavailable = (
_HARBOR_110_REMOTE_LOCAL_V2_BLOCKER_RE.search(text) is not None
)
public_registry_v2_unavailable = (
_HARBOR_110_PUBLIC_V2_BLOCKER_RE.search(text) is not None
)
local_status = _last_named_match_group(
_HARBOR_110_REMOTE_LOCAL_V2_STATUS_RE,
text,
"status",
) or _last_named_match_group(
_HARBOR_110_REMOTE_LOCAL_V2_BLOCKER_RE,
text,
"status",
)
public_status = _last_named_match_group(
_HARBOR_110_PUBLIC_V2_STATUS_RE,
text,
"status",
) or _last_named_match_group(
_HARBOR_110_PUBLIC_V2_BLOCKER_RE,
text,
"status",
)
return {
"failure_classifier": (
"harbor_110_remote_ssh_publickey_auth_stalled"
if remote_ssh_publickey_auth_stalled
else "harbor_110_remote_control_channel_unavailable"
if remote_control_channel_unavailable
else "harbor_110_remote_local_registry_v2_unavailable"
if local_registry_v2_unavailable
else "harbor_public_registry_v2_unavailable"
if public_registry_v2_unavailable
else ""
),
"remote_control_channel_unavailable": remote_control_channel_unavailable,
"remote_ssh_reachable": remote_ssh_reachable,
"bounded_ssh_timeout_seen": bounded_ssh_timeout_seen,
"remote_ssh_tcp_connected": remote_ssh_tcp_connected,
"remote_ssh_banner_seen": remote_ssh_banner_seen,
"remote_ssh_userauth_service_accept_seen": (
remote_ssh_userauth_service_accept_seen
),
"remote_ssh_publickey_offered": remote_ssh_publickey_offered,
"remote_ssh_publickey_reply_timeout_seen": (
remote_ssh_publickey_reply_timeout_seen
),
"remote_ssh_publickey_auth_stalled": remote_ssh_publickey_auth_stalled,
"remote_ssh_server_accepts_key_then_session_timeout": (
remote_ssh_server_accepts_key_then_session_timeout
),
"remote_ssh_auth_permission_denied": remote_ssh_auth_permission_denied,
"local_registry_v2_status": local_status,
"public_registry_v2_status": public_status,
"local_registry_v2_unavailable": local_registry_v2_unavailable,
"public_registry_v2_unavailable": public_registry_v2_unavailable,
"repair_verified": "harbor_110_remote_repair_verified=true" in text,
}
def classify_cd_tests_log(text: str) -> dict[str, Any]:
attempt_numbers: list[int] = []
attempt_limits: list[int] = []
for match in _HOST_PRESSURE_ATTEMPT_RE.finditer(text):
attempt_numbers.append(_int(match.group("attempt")))
attempt_limits.append(_int(match.group("limit")))
latest_load = ""
latest_threshold = ""
for match in _HOST_PRESSURE_LOAD_RE.finditer(text):
latest_load = match.group("load")
latest_threshold = match.group("threshold")
latest_postgres_cores = ""
latest_postgres_threshold = ""
postgres_recovery_cpu_pressure = False
for match in _HOST_PRESSURE_POSTGRES_RE.finditer(text):
postgres_recovery_cpu_pressure = True
latest_postgres_cores = match.group("cores")
latest_postgres_threshold = match.group("threshold")
host_pressure_refused = _HOST_PRESSURE_REFUSAL_RE.search(text) is not None
host_pressure_interrupted = _HOST_PRESSURE_INTERRUPTED_RE.search(text) is not None
host_pressure_waiting = bool(attempt_numbers) and not host_pressure_refused
host_pressure_blocked_or_waiting = host_pressure_waiting or host_pressure_refused
return {
"host_pressure_classifier": (
"host_web_build_pressure_refused"
if host_pressure_refused
else "host_web_build_pressure_interrupted"
if host_pressure_interrupted
else "host_web_build_pressure_waiting"
if host_pressure_waiting
else ""
),
"host_pressure_attempt_count": max(attempt_numbers)
if attempt_numbers
else 0,
"host_pressure_attempt_limit": max(attempt_limits) if attempt_limits else 0,
"latest_load5_per_core": latest_load,
"load5_per_core_threshold": latest_threshold,
"host_pressure_waiting": host_pressure_waiting,
"host_pressure_refused": host_pressure_refused,
"host_pressure_interrupted": host_pressure_interrupted,
"postgres_recovery_cpu_pressure": postgres_recovery_cpu_pressure,
"postgres_recovery_cpu_cores": latest_postgres_cores,
"postgres_recovery_cpu_threshold": latest_postgres_threshold,
"host_pressure_blocked_or_waiting": host_pressure_blocked_or_waiting,
}
def load_json_text(text: str) -> Any:
try:
return json.loads(text)
except json.JSONDecodeError:
return {"message": text.strip()}
def load_json_file(path: Path) -> Any:
return load_json_text(path.read_text(encoding="utf-8"))
def derive_jobs_api_url(actions_list_api_url: str, run_id: str) -> str:
if not run_id:
return ""
return re.sub(
r"/actions/runs(?:\?.*)?$",
f"/actions/runs/{run_id}/jobs",
actions_list_api_url,
)
def _int(value: Any) -> int:
try:
return int(value)
except (TypeError, ValueError):
return 0
def _last_named_match_group(pattern: re.Pattern[str], text: str, group: str) -> str:
matches = list(pattern.finditer(text))
return matches[-1].group(group) if matches else ""
def _last_bool_marker(name: str, text: str) -> bool | None:
pattern = re.compile(
_HARBOR_110_REMOTE_SSH_BOOL_RE_TEMPLATE.format(name=re.escape(name))
)
matches = list(pattern.finditer(text))
if not matches:
return None
return matches[-1].group("value") == "true"
def _read_text_file(path: Path) -> str:
return path.read_text(encoding="utf-8")
def _human_summary(payload: dict[str, Any]) -> str:
readback = payload["readback"]
lines = [
f"AWOOOI_PUBLIC_GITEA_ACTIONS_QUEUE_STATUS={payload['status']}",
(
"ACTIONS_LIST_WITHOUT_TOKEN_HTTP_STATUS="
f"{readback['actions_list_without_token_http_status']}"
),
f"CD_RUN_JOBS_TOTAL_COUNT={readback['cd_run_jobs_total_count']}",
(
"CD_RUN_JOBS_PAYLOAD_CLASSIFIER="
f"{readback['cd_run_jobs_payload_classifier']}"
),
(
"NO_MATCHING_ONLINE_RUNNER_VISIBLE="
f"{int(readback['no_matching_online_runner_visible'])}"
),
(
"LATEST_NO_MATCHING_RUNNER_LABEL="
f"{readback['latest_visible_no_matching_runner_label']}"
),
f"LATEST_VISIBLE_CD_RUN_ID={readback['latest_visible_cd_run_id']}",
f"LATEST_VISIBLE_CD_RUN_STATUS={readback['latest_visible_cd_run_status']}",
(
"LATEST_VISIBLE_CD_FAILURE_CLASSIFIER="
f"{readback['latest_visible_cd_failure_classifier']}"
),
(
"LATEST_VISIBLE_CD_INFLIGHT_CLASSIFIER="
f"{readback['latest_visible_cd_inflight_classifier']}"
),
(
"LATEST_VISIBLE_CD_HARBOR_LATEST_REGISTRY_V2_STATUS="
f"{readback['latest_visible_cd_harbor_latest_registry_v2_status']}"
),
(
"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']}"
),
(
"LATEST_VISIBLE_HARBOR_110_REPAIR_FAILURE_CLASSIFIER="
f"{readback['latest_visible_harbor_110_repair_failure_classifier']}"
),
(
"LATEST_VISIBLE_HARBOR_110_REPAIR_REMOTE_CONTROL_CHANNEL_UNAVAILABLE="
f"{int(readback['latest_visible_harbor_110_repair_remote_control_channel_unavailable'])}"
),
(
"LATEST_VISIBLE_HARBOR_110_REPAIR_REMOTE_SSH_REACHABLE="
f"{readback['latest_visible_harbor_110_repair_remote_ssh_reachable']}"
),
(
"LATEST_VISIBLE_HARBOR_110_REPAIR_REMOTE_SSH_PUBLICKEY_AUTH_STALLED="
f"{int(readback['latest_visible_harbor_110_repair_remote_ssh_publickey_auth_stalled'])}"
),
(
"LATEST_VISIBLE_HARBOR_110_REPAIR_REMOTE_SSH_PUBLICKEY_REPLY_TIMEOUT_SEEN="
f"{readback['latest_visible_harbor_110_repair_remote_ssh_publickey_reply_timeout_seen']}"
),
(
"HARBOR_110_REPAIR_WAITING_AFTER_CD_HARBOR_BLOCKER="
f"{int(readback['harbor_110_repair_waiting_after_cd_harbor_blocker'])}"
),
(
"HARBOR_110_REPAIR_JOBS_ALL_SUCCESS="
f"{int(readback['harbor_110_repair_jobs_all_success'])}"
),
(
"HARBOR_110_REPAIR_JOBS_STALE_OR_MISMATCHED="
f"{int(readback['harbor_110_repair_jobs_stale_or_mismatched'])}"
),
(
"HARBOR_110_REPAIR_VISIBLE_WAITING_STALE="
f"{int(readback['harbor_110_repair_visible_waiting_stale'])}"
),
"WRITE_PERFORMED=false",
"TOKEN_COLLECTED=false",
]
return "\n".join(lines) + "\n"
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(
description=(
"Read public Gitea Actions queue state without credentials, dispatch, "
"runner registration, host access, or secret reads."
)
)
parser.add_argument("--actions-url", default=DEFAULT_ACTIONS_URL)
parser.add_argument(
"--cd-workflow-actions-url",
default=DEFAULT_CD_WORKFLOW_ACTIONS_URL,
)
parser.add_argument("--actions-list-api-url", default=DEFAULT_ACTIONS_LIST_API_URL)
parser.add_argument("--cd-run-jobs-api-url", default=DEFAULT_CD_RUN_JOBS_API_URL)
parser.add_argument(
"--cd-build-job-log-url-template",
default=DEFAULT_CD_BUILD_JOB_LOG_URL_TEMPLATE,
)
parser.add_argument(
"--cd-tests-job-log-url-template",
default=DEFAULT_CD_TESTS_JOB_LOG_URL_TEMPLATE,
)
parser.add_argument(
"--harbor-110-repair-job-log-url-template",
default=DEFAULT_HARBOR_110_REPAIR_JOB_LOG_URL_TEMPLATE,
)
parser.add_argument("--timeout-seconds", type=float, default=10.0)
parser.add_argument("--actions-html-file", type=Path)
parser.add_argument("--cd-workflow-actions-html-file", type=Path)
parser.add_argument("--actions-list-json-file", type=Path)
parser.add_argument("--actions-list-http-status", type=int)
parser.add_argument("--cd-run-jobs-json-file", type=Path)
parser.add_argument("--cd-run-jobs-http-status", type=int)
parser.add_argument("--harbor-110-repair-jobs-json-file", type=Path)
parser.add_argument("--harbor-110-repair-jobs-http-status", type=int)
parser.add_argument("--cd-build-job-log-file", type=Path)
parser.add_argument("--cd-build-job-log-http-status", type=int)
parser.add_argument("--cd-tests-job-log-file", type=Path)
parser.add_argument("--cd-tests-job-log-http-status", type=int)
parser.add_argument("--harbor-110-repair-job-log-file", type=Path)
parser.add_argument("--harbor-110-repair-job-log-http-status", type=int)
parser.add_argument("--skip-cd-build-job-log-read", action="store_true")
parser.add_argument("--skip-cd-tests-job-log-read", action="store_true")
parser.add_argument("--skip-harbor-110-repair-job-log-read", action="store_true")
parser.add_argument("--json", action="store_true")
args = parser.parse_args(argv)
if args.actions_html_file:
actions_html = _read_text_file(args.actions_html_file)
else:
actions_html = fetch_public_url(args.actions_url, args.timeout_seconds).text
if args.cd_workflow_actions_html_file:
cd_workflow_actions_html = _read_text_file(args.cd_workflow_actions_html_file)
elif args.actions_html_file:
cd_workflow_actions_html = ""
elif any(run.get("workflow") == "cd.yaml" for run in parse_visible_runs(actions_html)):
cd_workflow_actions_html = ""
else:
cd_workflow_actions_html = fetch_public_url(
args.cd_workflow_actions_url,
args.timeout_seconds,
).text
actions_lookup_runs = merge_visible_runs(
parse_visible_runs(actions_html),
parse_visible_runs(cd_workflow_actions_html, workflow_hint="cd.yaml"),
)
if args.actions_list_json_file:
actions_list_http_status = args.actions_list_http_status or 0
actions_list_payload = load_json_file(args.actions_list_json_file)
else:
actions_list_read = fetch_public_url(
args.actions_list_api_url,
args.timeout_seconds,
)
actions_list_http_status = actions_list_read.http_status
actions_list_payload = load_json_text(actions_list_read.text)
if args.cd_run_jobs_json_file:
cd_jobs_http_status = args.cd_run_jobs_http_status or 0
cd_jobs_payload = load_json_file(args.cd_run_jobs_json_file)
else:
visible_runs_for_jobs = actions_lookup_runs
latest_cd_run_for_jobs = next(
(run for run in visible_runs_for_jobs if run.get("workflow") == "cd.yaml"),
{},
)
cd_run_jobs_api_url = args.cd_run_jobs_api_url or derive_jobs_api_url(
args.actions_list_api_url,
latest_cd_run_for_jobs.get("run_id", ""),
)
if cd_run_jobs_api_url:
cd_jobs_read = fetch_public_url(
cd_run_jobs_api_url,
args.timeout_seconds,
)
cd_jobs_http_status = cd_jobs_read.http_status
cd_jobs_payload = load_json_text(cd_jobs_read.text)
else:
cd_jobs_http_status = 0
cd_jobs_payload = {"jobs": [], "total_count": 0}
if args.harbor_110_repair_jobs_json_file:
harbor_110_repair_jobs_http_status = (
args.harbor_110_repair_jobs_http_status or 0
)
harbor_110_repair_jobs_payload = load_json_file(
args.harbor_110_repair_jobs_json_file
)
else:
visible_runs_for_harbor_jobs = actions_lookup_runs
latest_harbor_110_repair_run_for_jobs = next(
(
run
for run in visible_runs_for_harbor_jobs
if run.get("workflow") == "harbor-110-local-repair.yaml"
),
{},
)
harbor_110_repair_jobs_api_url = derive_jobs_api_url(
args.actions_list_api_url,
latest_harbor_110_repair_run_for_jobs.get("run_id", ""),
)
if harbor_110_repair_jobs_api_url:
harbor_110_repair_jobs_read = fetch_public_url(
harbor_110_repair_jobs_api_url,
args.timeout_seconds,
)
harbor_110_repair_jobs_http_status = (
harbor_110_repair_jobs_read.http_status
)
harbor_110_repair_jobs_payload = load_json_text(
harbor_110_repair_jobs_read.text
)
else:
harbor_110_repair_jobs_http_status = 0
harbor_110_repair_jobs_payload = {"jobs": [], "total_count": 0}
if args.cd_build_job_log_file:
cd_build_job_log_http_status = args.cd_build_job_log_http_status or 0
cd_build_job_log_text = _read_text_file(args.cd_build_job_log_file)
elif args.skip_cd_build_job_log_read:
cd_build_job_log_http_status = 0
cd_build_job_log_text = ""
else:
latest_cd_run = next(
(
run
for run in actions_lookup_runs
if run.get("workflow") == "cd.yaml"
),
{},
)
latest_cd_run_id = latest_cd_run.get("run_id", "")
if latest_cd_run_id:
log_url = args.cd_build_job_log_url_template.format(
run_id=latest_cd_run_id,
)
cd_build_job_log_read = fetch_public_url(
log_url,
args.timeout_seconds,
)
cd_build_job_log_http_status = cd_build_job_log_read.http_status
cd_build_job_log_text = cd_build_job_log_read.text
else:
cd_build_job_log_http_status = 0
cd_build_job_log_text = ""
if args.cd_tests_job_log_file:
cd_tests_job_log_http_status = args.cd_tests_job_log_http_status or 0
cd_tests_job_log_text = _read_text_file(args.cd_tests_job_log_file)
elif args.skip_cd_tests_job_log_read:
cd_tests_job_log_http_status = 0
cd_tests_job_log_text = ""
else:
latest_cd_run = next(
(
run
for run in actions_lookup_runs
if run.get("workflow") == "cd.yaml"
),
{},
)
latest_cd_run_id = latest_cd_run.get("run_id", "")
if latest_cd_run_id:
tests_log_url = args.cd_tests_job_log_url_template.format(
run_id=latest_cd_run_id,
)
cd_tests_job_log_read = fetch_public_url(
tests_log_url,
args.timeout_seconds,
)
cd_tests_job_log_http_status = cd_tests_job_log_read.http_status
cd_tests_job_log_text = cd_tests_job_log_read.text
else:
cd_tests_job_log_http_status = 0
cd_tests_job_log_text = ""
if args.harbor_110_repair_job_log_file:
harbor_110_repair_job_log_http_status = (
args.harbor_110_repair_job_log_http_status or 0
)
harbor_110_repair_job_log_text = _read_text_file(
args.harbor_110_repair_job_log_file
)
elif args.skip_harbor_110_repair_job_log_read:
harbor_110_repair_job_log_http_status = 0
harbor_110_repair_job_log_text = ""
else:
latest_harbor_110_repair_run = next(
(
run
for run in actions_lookup_runs
if run.get("workflow") == "harbor-110-local-repair.yaml"
),
{},
)
latest_harbor_110_repair_run_id = latest_harbor_110_repair_run.get(
"run_id",
"",
)
if latest_harbor_110_repair_run_id:
repair_log_url = args.harbor_110_repair_job_log_url_template.format(
run_id=latest_harbor_110_repair_run_id,
)
harbor_110_repair_job_log_read = fetch_public_url(
repair_log_url,
args.timeout_seconds,
)
harbor_110_repair_job_log_http_status = (
harbor_110_repair_job_log_read.http_status
)
harbor_110_repair_job_log_text = harbor_110_repair_job_log_read.text
else:
harbor_110_repair_job_log_http_status = 0
harbor_110_repair_job_log_text = ""
payload = build_readback(
actions_html=actions_html,
cd_workflow_actions_html=cd_workflow_actions_html,
actions_list_http_status=actions_list_http_status,
actions_list_payload=actions_list_payload,
cd_jobs_http_status=cd_jobs_http_status,
cd_jobs_payload=cd_jobs_payload,
harbor_110_repair_jobs_http_status=harbor_110_repair_jobs_http_status,
harbor_110_repair_jobs_payload=harbor_110_repair_jobs_payload,
latest_cd_build_log_http_status=cd_build_job_log_http_status,
latest_cd_build_log_text=cd_build_job_log_text,
latest_cd_tests_log_http_status=cd_tests_job_log_http_status,
latest_cd_tests_log_text=cd_tests_job_log_text,
latest_harbor_110_repair_log_http_status=(
harbor_110_repair_job_log_http_status
),
latest_harbor_110_repair_log_text=harbor_110_repair_job_log_text,
)
if args.json:
json.dump(payload, sys.stdout, ensure_ascii=False, indent=2, sort_keys=True)
sys.stdout.write("\n")
else:
sys.stdout.write(_human_summary(payload))
return 0
if __name__ == "__main__":
raise SystemExit(main())