feat(check satellite): cascade LAN+DMZ avec fallback automatique + migration servers.satellite_url + override BDD prioritaire
This commit is contained in:
parent
c74ac5ec3e
commit
0ed564a8ed
@ -625,7 +625,8 @@ async def iexec_check(request: Request, row_id: int, db=Depends(get_db)):
|
||||
|
||||
row = db.execute(text("""
|
||||
SELECT r.id, r.asset_name, r.intervenant, r.environnement, r.domaine,
|
||||
r.os, r.os_version, r.is_eligible, r.server_id, s.hostname
|
||||
r.os, r.os_version, r.is_eligible, r.server_id,
|
||||
s.hostname, s.satellite_url
|
||||
FROM patch_planning_import_rows r
|
||||
LEFT JOIN servers s ON s.id = r.server_id
|
||||
WHERE r.id = :id
|
||||
@ -656,6 +657,7 @@ async def iexec_check(request: Request, row_id: int, db=Depends(get_db)):
|
||||
"intervenant": row.intervenant,
|
||||
"environnement": row.environnement,
|
||||
"domaine": row.domaine,
|
||||
"satellite_url": getattr(row, "satellite_url", None),
|
||||
})
|
||||
return JSONResponse({"ok": True, "row_id": row_id, **result})
|
||||
|
||||
|
||||
@ -40,13 +40,21 @@ SATELLITE_LAN = "vpdsiasat2.sanef.groupe"
|
||||
SATELLITE_DMZ = "vpdsiasat1.sanef.groupe"
|
||||
|
||||
|
||||
def _pick_satellite(row: Dict[str, Any]) -> str:
|
||||
"""Renvoie le hostname du Satellite cible selon le domaine.
|
||||
Si la colonne Domaine contient 'DMZ' → vpdsiasat1, sinon vpdsiasat2 (LAN)."""
|
||||
def _pick_satellites(row: Dict[str, Any]) -> List[str]:
|
||||
"""Renvoie la liste ordonnée des Satellites à tester.
|
||||
Priorité : 1) servers.satellite_url renseigné en BDD,
|
||||
2) DMZ d'abord si la colonne Domaine contient 'DMZ',
|
||||
3) LAN d'abord par défaut.
|
||||
L'autre satellite est toujours ajouté en fallback."""
|
||||
forced = (row.get("satellite_url") or "").strip()
|
||||
domaine = str(row.get("domaine") or "").upper()
|
||||
if forced:
|
||||
# Override : on commence par celui en BDD, fallback sur l'autre
|
||||
other = SATELLITE_DMZ if forced == SATELLITE_LAN else SATELLITE_LAN
|
||||
return [forced] if forced not in (SATELLITE_LAN, SATELLITE_DMZ) else [forced, other]
|
||||
if "DMZ" in domaine:
|
||||
return SATELLITE_DMZ
|
||||
return SATELLITE_LAN
|
||||
return [SATELLITE_DMZ, SATELLITE_LAN]
|
||||
return [SATELLITE_LAN, SATELLITE_DMZ]
|
||||
|
||||
|
||||
def _exec(client, cmd: str) -> Dict[str, Any]:
|
||||
@ -193,32 +201,38 @@ def check_disk(ctx: Dict[str, Any]) -> Dict[str, Any]:
|
||||
|
||||
def check_satellite(ctx: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Vérifie :
|
||||
1. la joignabilité du Satellite cible (LAN ou DMZ selon Domaine)
|
||||
1. la joignabilité d'un Satellite (LAN d'abord, fallback DMZ — ou
|
||||
inversement si serveur DMZ)
|
||||
2. l'inscription du serveur (subscription-manager identity)
|
||||
3. l'accès aux repos (yum repolist enabled --quiet)
|
||||
Toutes les commandes utilisent sudo -n (non-interactif).
|
||||
Toutes les commandes utilisent sudo -n.
|
||||
"""
|
||||
client = ctx.get("client")
|
||||
sat = _pick_satellite(ctx.get("row") or {})
|
||||
label = f"Satellite ({sat})"
|
||||
satellites = _pick_satellites(ctx.get("row") or {})
|
||||
preferred = satellites[0]
|
||||
label = f"Satellite (préféré: {preferred})"
|
||||
if client is None:
|
||||
return {
|
||||
"name": "satellite",
|
||||
"label": label,
|
||||
"status": "ko",
|
||||
"message": "SSH KO en amont",
|
||||
"details": "",
|
||||
"name": "satellite", "label": label, "status": "ko",
|
||||
"message": "SSH KO en amont", "details": "",
|
||||
}
|
||||
|
||||
# 1) Joignabilité réseau du Satellite (HEAD https://<sat>/pub/)
|
||||
# 1) Joignabilité : on tente chaque satellite jusqu'au premier qui répond
|
||||
sat_reached = None
|
||||
sat_attempts = []
|
||||
for sat in satellites:
|
||||
r0 = _exec(client,
|
||||
f"sudo -n curl -k -s -o /dev/null -w '%{{http_code}}' "
|
||||
f"--max-time 5 https://{sat}/pub/ 2>&1")
|
||||
http_code = (r0["stdout"] or "").strip()
|
||||
sat_reachable = http_code in ("200", "301", "302", "403")
|
||||
sat_attempts.append(f"{sat} → HTTP {http_code or 'N/A'}")
|
||||
if http_code in ("200", "301", "302", "403"):
|
||||
sat_reached = sat
|
||||
break
|
||||
|
||||
# 2) subscription-manager identity
|
||||
# Locale-indépendant : on cherche un UUID dans la sortie (présent en EN comme en FR).
|
||||
sat_reachable = sat_reached is not None
|
||||
|
||||
# 2) subscription-manager identity (locale-indépendant via UUID)
|
||||
r1 = _exec(client, "sudo -n subscription-manager identity 2>&1")
|
||||
sub_ok = (r1["rc"] == 0 and bool(re.search(
|
||||
r"\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b",
|
||||
@ -229,7 +243,7 @@ def check_satellite(ctx: Dict[str, Any]) -> Dict[str, Any]:
|
||||
repolist_ok = (r2["rc"] == 0 and r2["stdout"].strip() != "")
|
||||
|
||||
details = (
|
||||
f"$ curl https://{sat}/pub/ → http_code={http_code or 'N/A'}\n"
|
||||
"$ curl tests :\n " + "\n ".join(sat_attempts) + "\n"
|
||||
f"$ sudo subscription-manager identity →\n{r1['stdout']}\n{r1['stderr']}\n"
|
||||
f"---\n"
|
||||
f"$ sudo yum repolist enabled --quiet (head -50) →\n{r2['stdout']}\n{r2['stderr']}"
|
||||
@ -240,29 +254,23 @@ def check_satellite(ctx: Dict[str, Any]) -> Dict[str, Any]:
|
||||
if ln and not ln.lower().startswith(("repo id", "loaded plugins",
|
||||
"updating subscription",
|
||||
"this system")))
|
||||
return {
|
||||
"name": "satellite",
|
||||
"label": label,
|
||||
"status": "ok",
|
||||
"message": f"{sat} joignable · système enregistré · ~{nb} repo(s) actifs",
|
||||
"details": details,
|
||||
}
|
||||
# Construit message synthétique des KO
|
||||
msg = f"{sat_reached} joignable · système enregistré · ~{nb} repo(s)"
|
||||
if sat_reached != preferred:
|
||||
msg += f" — fallback depuis {preferred}"
|
||||
return {"name": "satellite", "label": label, "status": "ok",
|
||||
"message": msg, "details": details}
|
||||
|
||||
issues = []
|
||||
if not sat_reachable:
|
||||
issues.append(f"Satellite {sat} injoignable (http={http_code or 'N/A'})")
|
||||
tried = ", ".join(s for s in satellites)
|
||||
issues.append(f"Aucun Satellite joignable (testés: {tried})")
|
||||
if not sub_ok:
|
||||
issues.append("subscription-manager identity KO")
|
||||
if not repolist_ok:
|
||||
issues.append("yum repolist vide / KO")
|
||||
status = "ko" if (not sat_reachable or not repolist_ok) else "warn"
|
||||
return {
|
||||
"name": "satellite",
|
||||
"label": label,
|
||||
"status": status,
|
||||
"message": " · ".join(issues),
|
||||
"details": details,
|
||||
}
|
||||
return {"name": "satellite", "label": label, "status": status,
|
||||
"message": " · ".join(issues), "details": details}
|
||||
|
||||
|
||||
# ────────────────────────────────────────────────────────────────────────
|
||||
|
||||
38
migrate_servers_satellite.sql
Normal file
38
migrate_servers_satellite.sql
Normal file
@ -0,0 +1,38 @@
|
||||
-- Migration : ajoute servers.satellite_url avec backfill auto
|
||||
-- - DMZ (zone "DMZ" ou domaine "DMZ") → vpdsiasat1.sanef.groupe
|
||||
-- - Tous les autres → vpdsiasat2.sanef.groupe
|
||||
-- Champ optionnel (override de la convention par défaut côté code).
|
||||
-- Idempotent.
|
||||
|
||||
ALTER TABLE public.servers
|
||||
ADD COLUMN IF NOT EXISTS satellite_url text;
|
||||
|
||||
-- Backfill DMZ (par zone = 'DMZ' ou nom de domaine contenant 'DMZ')
|
||||
UPDATE public.servers s
|
||||
SET satellite_url = 'vpdsiasat1.sanef.groupe',
|
||||
updated_at = NOW()
|
||||
FROM public.zones z, public.domain_environments de, public.domains d
|
||||
WHERE s.zone_id = z.id
|
||||
AND s.domain_env_id = de.id
|
||||
AND de.domain_id = d.id
|
||||
AND s.satellite_url IS NULL
|
||||
AND (z.is_dmz = true
|
||||
OR UPPER(z.name) = 'DMZ'
|
||||
OR UPPER(d.name) LIKE '%DMZ%'
|
||||
OR UPPER(d.code) = 'DMZ');
|
||||
|
||||
-- Backfill tout le reste (LAN par défaut)
|
||||
UPDATE public.servers
|
||||
SET satellite_url = 'vpdsiasat2.sanef.groupe',
|
||||
updated_at = NOW()
|
||||
WHERE satellite_url IS NULL;
|
||||
|
||||
-- Compteurs après backfill
|
||||
SELECT 'satellite_lan (vpdsiasat2)' AS scope, COUNT(*) AS nb
|
||||
FROM public.servers WHERE satellite_url = 'vpdsiasat2.sanef.groupe'
|
||||
UNION ALL
|
||||
SELECT 'satellite_dmz (vpdsiasat1)' AS scope, COUNT(*) AS nb
|
||||
FROM public.servers WHERE satellite_url = 'vpdsiasat1.sanef.groupe'
|
||||
UNION ALL
|
||||
SELECT 'satellite_null' AS scope, COUNT(*) AS nb
|
||||
FROM public.servers WHERE satellite_url IS NULL;
|
||||
Loading…
Reference in New Issue
Block a user