feat: add ops center and node onboarding flow

This commit is contained in:
Your Name
2026-04-18 23:52:51 +08:00
parent 246838ae4c
commit b9c29481b5
142 changed files with 89727 additions and 186 deletions

View File

@@ -4,23 +4,44 @@ set -euo pipefail
DB_NAME="${DB_NAME:-domain}"
DB_USER="${DB_USER:-postgres}"
PSQL_BIN="${PSQL_BIN:-/www/server/pgsql/bin/psql}"
API_BASE_URL="${1:-${API_BASE_URL:-http://127.0.0.1:8100}}"
CURL_CONNECT_TIMEOUT="${CURL_CONNECT_TIMEOUT:-3}"
CURL_MAX_TIME="${CURL_MAX_TIME:-10}"
echo "[1/3] cluster nodes"
curl_json() {
curl -fsS \
--connect-timeout "${CURL_CONNECT_TIMEOUT}" \
--max-time "${CURL_MAX_TIME}" \
"$1"
}
RUNTIME_STATUS_JSON="$(curl_json "${API_BASE_URL}/api/v1/runtime/status")"
echo "[1/4] cluster nodes"
"${PSQL_BIN}" -U "${DB_USER}" -d "${DB_NAME}" -Atc "
select
node_code || '|' ||
role || '|' ||
status || '|' ||
coalesce(current_load, 0) || '|' ||
coalesce(metadata_json->>'job_items_claimed', '0') || '|' ||
coalesce(metadata_json->>'job_items_running', '0') || '|' ||
coalesce(metadata_json->>'job_items_completed', '0') || '|' ||
to_char(last_heartbeat_at, 'YYYY-MM-DD HH24:MI:SS') || '|' ||
coalesce(metadata_json->>'worker_online', '') || '|' ||
coalesce(metadata_json->>'detect_participating', '')
(
case
when coalesce(current_load, 0) > 0 then 'true'
when coalesce(metadata_json->>'detect_participating', '') in ('true', 'false') then metadata_json->>'detect_participating'
else ''
end
)
from detect_worker_nodes
order by node_code;
"
echo
echo "[2/3] active job distribution"
echo "[2/4] active job distribution"
"${PSQL_BIN}" -U "${DB_USER}" -d "${DB_NAME}" -Atc "
select
coalesce(claimed_by, '') || '|' ||
@@ -39,59 +60,43 @@ order by claimed_by, status;
"
echo
echo "[3/3] condensed summary"
"${PSQL_BIN}" -U "${DB_USER}" -d "${DB_NAME}" -At <<'SQL'
with latest_job as (
select id, job_code, status
from detect_jobs
where status in ('pending','running')
order by id desc
limit 1
),
node_stats as (
select
node_code,
role,
status,
coalesce(metadata_json->>'worker_online', '') as worker_online,
coalesce(metadata_json->>'detect_participating', '') as detect_participating
from detect_worker_nodes
),
item_stats as (
select
coalesce(claimed_by, '') as claimed_by,
status,
count(*) as cnt
from detect_job_items
where job_id = (select id from latest_job)
group by claimed_by, status
)
select json_build_object(
'job', (
select json_build_object(
'job_code', coalesce(job_code, ''),
'status', coalesce(status, '')
)
from latest_job
),
'online_nodes', (
select coalesce(json_agg(json_build_object(
'node_code', node_code,
'role', role,
'status', status,
'worker_online', worker_online,
'detect_participating', detect_participating
) order by node_code), '[]'::json)
from node_stats
where status in ('online', 'busy')
),
'claimed_distribution', (
select coalesce(json_agg(json_build_object(
'claimed_by', claimed_by,
'status', status,
'count', cnt
) order by claimed_by, status), '[]'::json)
from item_stats
)
);
SQL
echo "[3/4] runtime participation snapshot"
printf "%s" "${RUNTIME_STATUS_JSON}" | python3 -c '
import json, sys
payload = json.load(sys.stdin).get("data", {})
detect = payload.get("detect", {})
print(json.dumps({
"node": payload.get("node", {}),
"participation_summary": detect.get("participation_summary", {}),
"participating_nodes": detect.get("participating_nodes", []),
"non_participating_nodes": detect.get("non_participating_nodes", detect.get("standby_nodes", [])),
"log_sync": detect.get("log_sync", {}),
}, ensure_ascii=False, indent=2))
'
echo
echo "[4/4] condensed summary"
printf "%s" "${RUNTIME_STATUS_JSON}" | python3 -c '
import json, sys
payload = json.load(sys.stdin).get("data", {})
detect = payload.get("detect", {})
summary = detect.get("participation_summary", {}) or {}
print(json.dumps({
"node": payload.get("node", {}),
"active_job": {
"job_code": (detect.get("active_job") or {}).get("job_code", ""),
"status": (detect.get("active_job") or {}).get("status", ""),
},
"participation_summary": summary,
"dispatch_active_nodes": summary.get("dispatch_active_node_codes", []),
"recent_only_nodes": summary.get("recent_only_node_codes", []),
"non_participating_nodes": summary.get("non_participating_node_codes", []),
"log_sync": {
"enabled": bool((detect.get("log_sync") or {}).get("enabled", False)),
"mode": (detect.get("log_sync") or {}).get("mode", ""),
"line_count": (detect.get("log_sync") or {}).get("line_count", 0),
"source_nodes": (detect.get("log_sync") or {}).get("source_nodes", []),
"last_at": (detect.get("log_sync") or {}).get("last_at", ""),
},
}, ensure_ascii=False, indent=2))
'