mirror of
https://github.com/zvx-echo6/navi.git
synced 2026-08-26 17:31:37 +00:00
* Add navi-admin service (extraction #7) Net-new fleet admin aggregator on :8427 — no port from recon (recon has no /api/admin route; Phase A §3). Three @require_auth routes: GET /api/admin/fleet fan-out to all 6 navi-* /api/admin/<svc>/info + recon /api/health, merged; never 5xx (failures land in errors[]) GET /api/admin/recon/info recon /api/health wrapped in the info shape GET /api/admin/navi-admin/info self-describe Fan-out forwards the caller's X-Authentik-Username so the @require_auth upstreams accept it; per-service admin endpoints stay localhost-only (this is the single edge-exposed admin surface). Service discovery: hardcoded list in fleet.py (Option B). No secrets, no DB. Deploy artifacts (NOT applied here): navi-admin.env.example, systemd unit, nginx ^~ /api/admin snippet, and deploy/caddy notes for the @authed_api edit (first Caddy change since #2). 12 hermetic tests (fleet happy-path, per-service timeout/500 → errors[], auth-header forwarding, recon-down degraded-not-5xx, self-info no-secrets, auth-required). Full monorepo suite green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * PR #7 review fixes 1. Symmetric degraded-entry handling in fleet.build_fleet — every probed service now appears in `services` with a uniform degraded dict on failure (matches recon's existing pattern), AND in errors[]. Operators see "everything I tried + which broke" consistently. 2. Catch ValueError specifically in _get_json — non-JSON 200 responses now surface as `error: 'invalid JSON'` instead of opaque 'ValueError'. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * PR #7 review fixes (round 2) 1. Unified degraded shape: wrap_recon_health calls _degraded_entry on failure — no more runtime.status vs runtime.recon_status asymmetry. Every probed service has the same shape on failure (runtime.status == 'unreachable'). recon-specific runtime fields (recon_status/recon_uptime/pipeline) remain only on the success path. 2. DRY'd git short-SHA helper into shared/git_sha.py — was duplicated in 7 service app.py files + fleet.recon_git_sha. One implementation, one place to fix when behavior changes. Adds shared/tests (testpaths now includes "shared"). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: zvx-echo6 <mj@k7zvx.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
42 lines
1.2 KiB
Python
42 lines
1.2 KiB
Python
"""navi-traffic Flask application factory + gunicorn entry.
|
|
|
|
Gunicorn entry:
|
|
gunicorn 'services.navi_traffic.app:create_app()' --bind 127.0.0.1:8421 --workers 2
|
|
"""
|
|
import time
|
|
|
|
from flask import Flask
|
|
|
|
from shared.git_sha import git_short_sha
|
|
|
|
from . import traffic, admin
|
|
|
|
|
|
def create_app():
|
|
app = Flask(__name__)
|
|
|
|
# Version + lightweight runtime metrics, read by the admin-info endpoint.
|
|
# NOTE: with gunicorn --workers 2 these counters are per-worker (each worker
|
|
# is its own process); they are indicative, not cluster-wide totals.
|
|
app.config['VERSION'] = git_short_sha()
|
|
app.config['METRICS'] = {
|
|
'start_time': time.time(),
|
|
'request_count': 0,
|
|
'last_error_at': None,
|
|
}
|
|
|
|
@app.before_request
|
|
def _count_request():
|
|
app.config['METRICS']['request_count'] += 1
|
|
|
|
@app.after_request
|
|
def _track_errors(response):
|
|
if response.status_code >= 500:
|
|
app.config['METRICS']['last_error_at'] = time.strftime(
|
|
'%Y-%m-%dT%H:%M:%SZ', time.gmtime()
|
|
)
|
|
return response
|
|
|
|
app.register_blueprint(traffic.bp)
|
|
app.register_blueprint(admin.bp)
|
|
return app
|