cc4c3fcecb
- Backend: Customer/Satellite Models, customer_id auf Server/Job/Audit - Satellite-API: heartbeat, poll (atomares Claiming), logs, result, scan-result, health-report - Auth via X-Api-Key (SHA-256 gehasht) - Job-Queue: pending/claimed/running/success/failed + Stale-Janitor - Batch-Trigger: ein Job pro Server, Satellite arbeitet sequenziell ab - Credentials bleiben lokal: nur symbolische credential_ref zentral - Neues Paket satellite/: Pull-Loop, WinRM/SSH/CAU/Scanner, PyInstaller-tauglich - Frontend: Kunden-Switcher, Satelliten-View, Polling statt WebSocket - Entfernt: WebSocket/Socket.io, Redis, zentrale Credentials, JobRunner - Docs: README/AGENTS/PROMPT auf neue Architektur aktualisiert
5.4 KiB
5.4 KiB
Insight Updater - Agent Orientation
Project Purpose
Zentrale, mandantenfaehige Update-Orchestrierung (Hub-and-Spoke). Zentrale (Docker) + Satelliten beim Kunden (Binary, kein Docker). Satelliten pollen Jobs, fuehren sie lokal im Kundennetz aus (WinRM/SSH/CAU/Scan) und melden Ergebnisse zurueck.
Quick Start
# Zentrale lokal
cd ~/projects/insight-updater
docker compose up -d --build
# Backend only
cd backend && pip install -e . && uvicorn app.main:app --reload
# Frontend only
cd frontend && npm install && npm run dev
# Satellite (Dev, gegen lokale Zentrale)
cd satellite && pip install -e .
cp config.example.yaml config.yaml # api_key eintragen
insight-satellite
Architecture Overview
Kundennetz Zentrale
┌────────────┐ outbound HTTPS ┌──────────────────┐
│ Satellite │ ──────────────────▶ │ FastAPI Backend │
│ (pollt │ X-Api-Key Auth │ /api/satellite │
│ alle 30s) │ ◀────────────────── │ /api (Dashboard │
└────────────┘ Jobs (claimed) │ JWT) + DB │
│ WinRM/SSH/CAU lokal └──────────────────┘
▼ ▲
Server im Kundennetz Vue 3 Frontend (JWT, Kunden-Switcher)
Key Directories
| Pfad | Zweck |
|---|---|
backend/app/api/routes/satellite_api.py |
Agent-API: heartbeat, poll, logs, result, scan-result, health-report |
backend/app/api/routes/ |
Dashboard-REST: auth, customers, satellites, servers, updates, audit |
backend/app/models/ |
Customer, Satellite, Server, UpdateJob, UpdateLog, AuditLog, User |
backend/app/services/janitor.py |
Markiert stale Jobs (Satellite meldet nicht mehr) als failed |
satellite/satellite/runner.py |
Main-Loop: heartbeat, poll, execute, report |
satellite/satellite/winrm_exec.py |
Windows Update via pywinrm |
satellite/satellite/ssh_exec.py |
Linux Update via asyncssh |
satellite/satellite/cau_exec.py |
Invoke-CauRun via WinRM |
satellite/satellite/scanner.py |
Ping-Sweep + Port-Probe (5985/22) |
frontend/src/stores/ |
Pinia: auth, customers, satellites, servers, updates |
Core Models
| Model | Beschreibung |
|---|---|
Customer |
Tenant: name, slug |
Satellite |
Agent beim Kunden: api_key_hash, last_seen, version, hostname |
Server |
Inventar pro Kunde: hostname, type, credential_ref (symbolisch!) |
UpdateJob |
customer_id, server_id (null bei Scan), satellite_id, status, params (JSON) |
UpdateLog |
Log-Zeilen pro Job (Batch-Upload vom Satellite) |
AuditLog |
Wer, wann, was - mit customer_id |
User |
Dashboard-User (lokal oder LDAP-Stub) |
Job Lifecycle (Pull-Modell)
pending -> claimed (beim Poll) -> running (erster Log-Push) -> success | failed
| cancelled (nur aus pending)
- Claiming passiert atomar im Poll (
with_for_update), zwei Satelliten eines Kunden bekommen nie denselben Job - Janitor (
services/janitor.py, alle 60s): claimed/running ohne Report seitJOB_STALE_TIMEOUT(default 3600s) -> failed - Cancel nur moeglich solange pending
API Endpoints (Dashboard, JWT)
| Method | Path | Beschreibung |
|---|---|---|
| POST | /api/auth/login |
Login |
| GET/POST/PATCH/DELETE | /api/customers[/{id}] |
Kunden CRUD |
| GET/POST/DELETE | /api/satellites[/{id}] |
Satelliten CRUD |
| POST | /api/satellites/{id}/rotate-key |
Neuer API-Key |
| GET/POST/PATCH/DELETE | /api/servers[/{id}] |
Inventar (customer_id scoped) |
| POST | /api/updates/trigger |
Einzelner Job |
| POST | /api/updates/trigger-batch |
Ein Job pro Server |
| GET | /api/updates/{id}/logs |
Job-Logs |
| GET | /api/audit |
Audit (filterbar per customer_id) |
API Endpoints (Satellite, X-Api-Key)
| Method | Path | Beschreibung |
|---|---|---|
| POST | /api/satellite/heartbeat |
Lebenszeichen + Version |
| GET | /api/satellite/poll |
Pending Jobs claimen + abholen |
| POST | /api/satellite/logs |
Log-Batch + Progress |
| POST | /api/satellite/result |
Abschluss success/failed |
| POST | /api/satellite/scan-result |
Gefundene Hosts (legt Server an) |
| POST | /api/satellite/health-report |
Health-Ergebnis pro Server |
Satellite-Deployment beim Kunden
- Binary via PyInstaller:
pyinstaller --onefile satellite/runner.py config.yaml: central_url, api_key, poll_intervalcredentials.yaml: WinRM/SSH Zugangsdaten (bleiben lokal!)- Start: Scheduled Task (Windows) oder systemd (Linux), siehe
satellite/README.md - 1-2 Stueck pro Kunde reichen - steuern das ganze Netz
Conventions
- Sprache: Deutsch fuer User-facing Text, Englisch fuer Code/Kommentare
- Keine Umlaute in .ps1/Python-Dateien (ae, oe, ue, ss)
- Keine Credentials zentral - nur
credential_refStrings - Async: Backend vollstaendig async; Satellite async mit to_thread fuer pywinrm
- Types: Strict mypy, Pydantic v2, SQLAlchemy 2.0
Deployment
Target Zentrale: monitoring (10.0.2.105)
Reverse Proxy: Traefik (Docker labels)
Git Remote: ssh://git@gitea.insight-it.de:2222/b0rbor4d/insight-updater.git
Wichtig: Zentrale muss von Kundenstandorten aus per HTTPS (443) erreichbar sein.