callback container integrated fully

This commit is contained in:
root
2026-08-09 13:17:44 +02:00
parent 639c2b68c8
commit 5594431749
12 changed files with 196 additions and 65 deletions
+59 -28
View File
@@ -7778,15 +7778,24 @@ def settings_software_page(request: Request):
_require_admin(request)
settings = _software_settings()
callback_base = str(settings.get("callback_base_url", "") or "").strip().rstrip("/")
callback_internal_base = str(os.getenv("CALLBACK_INTERNAL_BASE_URL", "http://callback:8001") or "http://callback:8001").strip().rstrip("/")
return templates.TemplateResponse(
"settings_software.html",
{
"request": request,
"software_settings": settings,
"callback_health_url": f"{callback_base}/api/software-callback/health" if callback_base else "",
"callback_internal_health_url": f"{callback_internal_base}/api/software-callback/health",
"callback_test_result": request.query_params.get("callback_test_result", ""),
"callback_test_kind": request.query_params.get("callback_test_kind", ""),
"callback_test_status": request.query_params.get("callback_test_status", ""),
"callback_test_ms": request.query_params.get("callback_test_ms", ""),
"callback_test_url": request.query_params.get("callback_test_url", ""),
"callback_test_message": request.query_params.get("callback_test_message", ""),
"debug_log": _software_debug_tail(),
"debug_log_path": str(SOFTWARE_CALLBACK_DEBUG_LOG),
"callback_dedicated_port": str(os.getenv("CALLBACK_PORT", "8090") or "8090"),
"callback_bind_ip": str(os.getenv("CALLBACK_BIND_IP", "127.0.0.1") or "127.0.0.1"),
},
)
@@ -7852,25 +7861,16 @@ def settings_software_save(
)
@app.post("/settings/software/test-callback")
def settings_software_test_callback(request: Request):
_require_admin(request)
settings = _software_settings()
callback_base = str(settings.get("callback_base_url", "") or "").strip().rstrip("/")
if not callback_base:
callback_base = str(request.base_url).rstrip("/")
health_url = f"{callback_base}/api/software-callback/health"
timeout = max(2, min(int(settings.get("callback_test_timeout_seconds", 10) or 10), 60))
verify_tls = bool(settings.get("callback_test_verify_tls", True))
def _run_callback_health_test(health_url: str, timeout: int, verify_tls: bool, test_kind: str) -> dict[str, str]:
parsed = urllib.parse.urlsplit(health_url)
_software_debug_log("=" * 72, force=True)
_software_debug_log("CALLBACK TEST started", force=True)
_software_debug_log(f"Base URL: {callback_base}", force=True)
_software_debug_log(f"CALLBACK HEALTH TEST started | kind={test_kind}", force=True)
_software_debug_log(f"Health URL: {health_url}", force=True)
_software_debug_log(f"Scheme: {parsed.scheme} | Host: {parsed.hostname} | Port: {parsed.port or ('443' if parsed.scheme == 'https' else '80')}", force=True)
_software_debug_log(f"Timeout: {timeout}s | Verify TLS: {verify_tls}", force=True)
if parsed.scheme not in {"http", "https"} or not parsed.hostname:
return {"ok": "0", "status": "-", "ms": "-", "url": health_url, "message": "Invalid health URL."}
try:
dns_started = time.monotonic()
addresses = sorted({item[4][0] for item in socket.getaddrinfo(parsed.hostname, parsed.port or (443 if parsed.scheme == "https" else 80), type=socket.SOCK_STREAM)})
@@ -7886,37 +7886,68 @@ def settings_software_test_callback(request: Request):
try:
req = urllib.request.Request(
health_url,
headers={"User-Agent": f"AssetManager/{application_version()} CallbackTest"},
headers={"User-Agent": f"AssetManager/{application_version()} CallbackHealthTest"},
method="GET",
)
with urllib.request.urlopen(req, timeout=timeout, context=context) as response:
body = response.read(65536).decode("utf-8", errors="replace")
elapsed = (time.monotonic() - request_started) * 1000
status = str(response.status)
_software_debug_log(f"HTTP STATUS: {response.status} {response.reason} ({elapsed:.1f} ms)", force=True)
_software_debug_log(f"Content-Type: {response.headers.get('Content-Type', '-')}", force=True)
_software_debug_log(f"Response body: {body}", force=True)
payload = json.loads(body)
if response.status == 200 and payload.get("ok") is True:
_software_debug_log("RESULT: Callback health endpoint is reachable.", force=True)
return RedirectResponse(
"/settings/software?toast_success=" + quote(_translate_request(request, "software.settings.test_success", "Callback endpoint is reachable.")),
status_code=303,
)
raise ValueError("Health response did not contain ok=true")
return {"ok": "1", "status": status, "ms": f"{elapsed:.1f}", "url": health_url, "message": "OK"}
return {"ok": "0", "status": status, "ms": f"{elapsed:.1f}", "url": health_url, "message": "Health response did not contain ok=true."}
except urllib.error.HTTPError as exc:
elapsed = (time.monotonic() - request_started) * 1000
body = exc.read(65536).decode("utf-8", errors="replace")
_software_debug_log(f"HTTP ERROR: {exc.code} {exc.reason}", force=True)
_software_debug_log(f"Response body: {body}", force=True)
message = f"HTTP {exc.code}: {exc.reason}"
return {"ok": "0", "status": str(exc.code), "ms": f"{elapsed:.1f}", "url": health_url, "message": f"HTTP {exc.code}: {exc.reason}"}
except Exception as exc:
elapsed = (time.monotonic() - request_started) * 1000
_software_debug_log(f"REQUEST ERROR: {type(exc).__name__}: {exc}", force=True)
message = f"{type(exc).__name__}: {exc}"
return {"ok": "0", "status": "-", "ms": f"{elapsed:.1f}", "url": health_url, "message": f"{type(exc).__name__}: {exc}"}
_software_debug_log("RESULT: Callback health endpoint is not reachable.", force=True)
return RedirectResponse(
"/settings/software?toast_error=" + quote(_translate_request(request, "software.settings.test_failed", "Callback test failed: {error}", error=message)),
status_code=303,
)
def _callback_test_redirect(request: Request, result: dict[str, str], test_kind: str) -> RedirectResponse:
params = urllib.parse.urlencode({
"callback_test_result": result.get("ok", "0"),
"callback_test_kind": test_kind,
"callback_test_status": result.get("status", "-"),
"callback_test_ms": result.get("ms", "-"),
"callback_test_url": result.get("url", ""),
"callback_test_message": result.get("message", ""),
})
return RedirectResponse(f"/settings/software?{params}", status_code=303)
@app.post("/settings/software/test-callback")
@app.post("/settings/software/test-callback-external")
def settings_software_test_callback_external(request: Request):
_require_admin(request)
settings = _software_settings()
callback_base = str(settings.get("callback_base_url", "") or "").strip().rstrip("/")
if not callback_base:
callback_base = str(request.base_url).rstrip("/")
health_url = f"{callback_base}/api/software-callback/health"
timeout = max(2, min(int(settings.get("callback_test_timeout_seconds", 10) or 10), 60))
verify_tls = bool(settings.get("callback_test_verify_tls", True))
result = _run_callback_health_test(health_url, timeout, verify_tls, "external")
return _callback_test_redirect(request, result, "external")
@app.post("/settings/software/test-callback-internal")
def settings_software_test_callback_internal(request: Request):
_require_admin(request)
settings = _software_settings()
internal_base = str(os.getenv("CALLBACK_INTERNAL_BASE_URL", "http://callback:8001") or "http://callback:8001").strip().rstrip("/")
health_url = f"{internal_base}/api/software-callback/health"
timeout = max(2, min(int(settings.get("callback_test_timeout_seconds", 10) or 10), 60))
result = _run_callback_health_test(health_url, timeout, True, "internal")
return _callback_test_redirect(request, result, "internal")
@app.get("/settings/software/debug-log")