fix(servers): bulk + edit comparaisons domain/env/zone case-insensitive (BD mixte RECETTE/Recette/recette) + fallback bulk env_code si serveur sans domain_env_id + log INFO/WARNING + retour msg=bulk_<n_updated_reel>

This commit is contained in:
Pierre & Lumière 2026-05-05 15:19:03 +02:00
parent 5d3c07885d
commit 1b82440813
2 changed files with 63 additions and 25 deletions

View File

@ -239,41 +239,65 @@ async def servers_bulk(request: Request, db=Depends(get_db),
from sqlalchemy import text as sqlt from sqlalchemy import text as sqlt
bulk_value_clean = (bulk_value or "").strip()
n_updated = 0
if bulk_field in ("tier", "etat", "patch_os_owner", "licence_support"): if bulk_field in ("tier", "etat", "patch_os_owner", "licence_support"):
db.execute(sqlt(f"UPDATE servers SET {bulk_field} = :val WHERE id = ANY(:ids)"), res = db.execute(sqlt(f"UPDATE servers SET {bulk_field} = :val WHERE id = ANY(:ids)"),
{"val": bulk_value, "ids": ids}) {"val": bulk_value_clean, "ids": ids})
n_updated = res.rowcount or 0
elif bulk_field == "domain_code": elif bulk_field == "domain_code":
# Trouver le domain_env_id correspondant (prod par defaut) # Tous les serveurs prennent le 1er domain_env de ce domaine
# (priorité Production > autres via display_order)
row = db.execute(sqlt(""" row = db.execute(sqlt("""
SELECT de.id FROM domain_environments de SELECT de.id FROM domain_environments de
JOIN domains d ON de.domain_id = d.id JOIN domains d ON de.domain_id = d.id
JOIN environments e ON de.environment_id = e.id JOIN environments e ON de.environment_id = e.id
WHERE d.code = :dc ORDER BY e.display_order LIMIT 1 WHERE LOWER(d.code) = LOWER(:dc) ORDER BY e.display_order LIMIT 1
"""), {"dc": bulk_value}).fetchone() """), {"dc": bulk_value_clean}).fetchone()
if row: if row:
db.execute(sqlt("UPDATE servers SET domain_env_id = :deid WHERE id = ANY(:ids)"), res = db.execute(sqlt("UPDATE servers SET domain_env_id = :deid WHERE id = ANY(:ids)"),
{"deid": row.id, "ids": ids}) {"deid": row.id, "ids": ids})
n_updated = res.rowcount or 0
else:
logger.warning(f"servers_bulk domain_code: aucun domain_environments pour {bulk_value_clean!r}")
elif bulk_field == "env_code": elif bulk_field == "env_code":
# Pour chaque serveur, garder son domaine mais changer l'env # Pour chaque serveur, garder son domaine actuel et changer l'env.
# Si serveur sans domain_env_id, fallback : 1er domain dispo + cet env.
for sid in ids: for sid in ids:
srv = db.execute(sqlt(""" srv = db.execute(sqlt("""
SELECT d.id as did FROM servers s SELECT s.id, s.domain_env_id, de.domain_id AS did
JOIN domain_environments de ON s.domain_env_id = de.id FROM servers s
JOIN domains d ON de.domain_id = d.id LEFT JOIN domain_environments de ON s.domain_env_id = de.id
WHERE s.id = :sid WHERE s.id = :sid
"""), {"sid": sid}).fetchone() """), {"sid": sid}).fetchone()
if srv: if not srv:
continue
did = srv.did # peut être None si serveur sans domaine
if did:
de = db.execute(sqlt(""" de = db.execute(sqlt("""
SELECT de.id FROM domain_environments de SELECT de.id FROM domain_environments de
JOIN environments e ON de.environment_id = e.id JOIN environments e ON de.environment_id = e.id
WHERE de.domain_id = :did AND e.code = :ec WHERE de.domain_id = :did AND LOWER(e.code) = LOWER(:ec)
"""), {"did": srv.did, "ec": bulk_value}).fetchone() """), {"did": did, "ec": bulk_value_clean}).fetchone()
if de: else:
db.execute(sqlt("UPDATE servers SET domain_env_id = :deid WHERE id = :sid"), # Fallback : on prend n'importe quel domain_env avec cet env
{"deid": de.id, "sid": sid}) de = db.execute(sqlt("""
SELECT de.id FROM domain_environments de
JOIN environments e ON de.environment_id = e.id
WHERE LOWER(e.code) = LOWER(:ec)
ORDER BY de.id LIMIT 1
"""), {"ec": bulk_value_clean}).fetchone()
if de:
db.execute(sqlt("UPDATE servers SET domain_env_id = :deid WHERE id = :sid"),
{"deid": de.id, "sid": sid})
n_updated += 1
else:
logger.warning(f"servers_bulk env_code: pas de domain_env pour env {bulk_value_clean!r} (sid={sid}, did={did})")
db.commit() db.commit()
return RedirectResponse(url=f"/servers?msg=bulk_{len(ids)}", status_code=303) logger.info(f"servers_bulk: field={bulk_field} value={bulk_value_clean!r} ids={len(ids)} updated={n_updated}")
return RedirectResponse(url=f"/servers?msg=bulk_{n_updated}", status_code=303)
@router.post("/servers/{server_id}/sync-qualys", response_class=HTMLResponse) @router.post("/servers/{server_id}/sync-qualys", response_class=HTMLResponse)

View File

@ -208,25 +208,39 @@ def list_servers(db, filters, page=1, per_page=50, sort="hostname", sort_dir="as
def update_server(db, server_id, data, username): def update_server(db, server_id, data, username):
"""Met a jour un serveur et log l'action""" """Met a jour un serveur et log l'action.
Comparaisons code domain/env/zone en case-insensitive (la BD mixte
'RECETTE'/'Recette'/'recette' n'a pas une casse cohérente)."""
import logging
log = logging.getLogger("patchcenter.server")
# Domain + Env -> domain_env_id # Domain + Env -> domain_env_id
if data.get("domain_code") and data.get("env_code"): dc = (data.get("domain_code") or "").strip()
ec = (data.get("env_code") or "").strip()
if dc and ec:
row = db.execute(text(""" row = db.execute(text("""
SELECT de.id FROM domain_environments de SELECT de.id FROM domain_environments de
JOIN domains d ON de.domain_id = d.id JOIN domains d ON de.domain_id = d.id
JOIN environments e ON de.environment_id = e.id JOIN environments e ON de.environment_id = e.id
WHERE d.code = :dc AND e.code = :ec WHERE LOWER(d.code) = LOWER(:dc) AND LOWER(e.code) = LOWER(:ec)
"""), {"dc": data["domain_code"], "ec": data["env_code"]}).fetchone() """), {"dc": dc, "ec": ec}).fetchone()
if row: if row:
db.execute(text("UPDATE servers SET domain_env_id = :deid WHERE id = :id"), db.execute(text("UPDATE servers SET domain_env_id = :deid WHERE id = :id"),
{"deid": row.id, "id": server_id}) {"deid": row.id, "id": server_id})
else:
log.warning(f"update_server({server_id}): pas de domain_environments pour ({dc!r}, {ec!r})")
# Zone # Zone (case-insensitive sur name)
if data.get("zone"): zn = (data.get("zone") or "").strip()
zrow = db.execute(text("SELECT id FROM zones WHERE name = :z"), {"z": data["zone"]}).fetchone() if zn:
zrow = db.execute(text(
"SELECT id FROM zones WHERE LOWER(name) = LOWER(:z)"
), {"z": zn}).fetchone()
if zrow: if zrow:
db.execute(text("UPDATE servers SET zone_id = :zid WHERE id = :id"), db.execute(text("UPDATE servers SET zone_id = :zid WHERE id = :id"),
{"zid": zrow.id, "id": server_id}) {"zid": zrow.id, "id": server_id})
else:
log.warning(f"update_server({server_id}): zone {zn!r} introuvable")
# IPs (reelle + connexion) # IPs (reelle + connexion)
update_server_ips(db, server_id, data.get("ip_reelle"), data.get("ip_connexion")) update_server_ips(db, server_id, data.get("ip_reelle"), data.get("ip_connexion"))