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("""
|
row = db.execute(text("""
|
||||||
SELECT r.id, r.asset_name, r.intervenant, r.environnement, r.domaine,
|
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
|
FROM patch_planning_import_rows r
|
||||||
LEFT JOIN servers s ON s.id = r.server_id
|
LEFT JOIN servers s ON s.id = r.server_id
|
||||||
WHERE r.id = :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,
|
"intervenant": row.intervenant,
|
||||||
"environnement": row.environnement,
|
"environnement": row.environnement,
|
||||||
"domaine": row.domaine,
|
"domaine": row.domaine,
|
||||||
|
"satellite_url": getattr(row, "satellite_url", None),
|
||||||
})
|
})
|
||||||
return JSONResponse({"ok": True, "row_id": row_id, **result})
|
return JSONResponse({"ok": True, "row_id": row_id, **result})
|
||||||
|
|
||||||
|
|||||||
@ -40,13 +40,21 @@ SATELLITE_LAN = "vpdsiasat2.sanef.groupe"
|
|||||||
SATELLITE_DMZ = "vpdsiasat1.sanef.groupe"
|
SATELLITE_DMZ = "vpdsiasat1.sanef.groupe"
|
||||||
|
|
||||||
|
|
||||||
def _pick_satellite(row: Dict[str, Any]) -> str:
|
def _pick_satellites(row: Dict[str, Any]) -> List[str]:
|
||||||
"""Renvoie le hostname du Satellite cible selon le domaine.
|
"""Renvoie la liste ordonnée des Satellites à tester.
|
||||||
Si la colonne Domaine contient 'DMZ' → vpdsiasat1, sinon vpdsiasat2 (LAN)."""
|
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()
|
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:
|
if "DMZ" in domaine:
|
||||||
return SATELLITE_DMZ
|
return [SATELLITE_DMZ, SATELLITE_LAN]
|
||||||
return SATELLITE_LAN
|
return [SATELLITE_LAN, SATELLITE_DMZ]
|
||||||
|
|
||||||
|
|
||||||
def _exec(client, cmd: str) -> Dict[str, Any]:
|
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]:
|
def check_satellite(ctx: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""Vérifie :
|
"""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)
|
2. l'inscription du serveur (subscription-manager identity)
|
||||||
3. l'accès aux repos (yum repolist enabled --quiet)
|
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")
|
client = ctx.get("client")
|
||||||
sat = _pick_satellite(ctx.get("row") or {})
|
satellites = _pick_satellites(ctx.get("row") or {})
|
||||||
label = f"Satellite ({sat})"
|
preferred = satellites[0]
|
||||||
|
label = f"Satellite (préféré: {preferred})"
|
||||||
if client is None:
|
if client is None:
|
||||||
return {
|
return {
|
||||||
"name": "satellite",
|
"name": "satellite", "label": label, "status": "ko",
|
||||||
"label": label,
|
"message": "SSH KO en amont", "details": "",
|
||||||
"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,
|
r0 = _exec(client,
|
||||||
f"sudo -n curl -k -s -o /dev/null -w '%{{http_code}}' "
|
f"sudo -n curl -k -s -o /dev/null -w '%{{http_code}}' "
|
||||||
f"--max-time 5 https://{sat}/pub/ 2>&1")
|
f"--max-time 5 https://{sat}/pub/ 2>&1")
|
||||||
http_code = (r0["stdout"] or "").strip()
|
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
|
sat_reachable = sat_reached is not None
|
||||||
# Locale-indépendant : on cherche un UUID dans la sortie (présent en EN comme en FR).
|
|
||||||
|
# 2) subscription-manager identity (locale-indépendant via UUID)
|
||||||
r1 = _exec(client, "sudo -n subscription-manager identity 2>&1")
|
r1 = _exec(client, "sudo -n subscription-manager identity 2>&1")
|
||||||
sub_ok = (r1["rc"] == 0 and bool(re.search(
|
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",
|
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() != "")
|
repolist_ok = (r2["rc"] == 0 and r2["stdout"].strip() != "")
|
||||||
|
|
||||||
details = (
|
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"$ sudo subscription-manager identity →\n{r1['stdout']}\n{r1['stderr']}\n"
|
||||||
f"---\n"
|
f"---\n"
|
||||||
f"$ sudo yum repolist enabled --quiet (head -50) →\n{r2['stdout']}\n{r2['stderr']}"
|
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",
|
if ln and not ln.lower().startswith(("repo id", "loaded plugins",
|
||||||
"updating subscription",
|
"updating subscription",
|
||||||
"this system")))
|
"this system")))
|
||||||
return {
|
msg = f"{sat_reached} joignable · système enregistré · ~{nb} repo(s)"
|
||||||
"name": "satellite",
|
if sat_reached != preferred:
|
||||||
"label": label,
|
msg += f" — fallback depuis {preferred}"
|
||||||
"status": "ok",
|
return {"name": "satellite", "label": label, "status": "ok",
|
||||||
"message": f"{sat} joignable · système enregistré · ~{nb} repo(s) actifs",
|
"message": msg, "details": details}
|
||||||
"details": details,
|
|
||||||
}
|
|
||||||
# Construit message synthétique des KO
|
|
||||||
issues = []
|
issues = []
|
||||||
if not sat_reachable:
|
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:
|
if not sub_ok:
|
||||||
issues.append("subscription-manager identity KO")
|
issues.append("subscription-manager identity KO")
|
||||||
if not repolist_ok:
|
if not repolist_ok:
|
||||||
issues.append("yum repolist vide / KO")
|
issues.append("yum repolist vide / KO")
|
||||||
status = "ko" if (not sat_reachable or not repolist_ok) else "warn"
|
status = "ko" if (not sat_reachable or not repolist_ok) else "warn"
|
||||||
return {
|
return {"name": "satellite", "label": label, "status": status,
|
||||||
"name": "satellite",
|
"message": " · ".join(issues), "details": details}
|
||||||
"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