"""Remplit servers.ssh_method par defaut selon OS + environnement. Regles SANEF : Linux + Production -> ssh_psmp (PSMP SSH via CyberArk) Linux + autre -> ssh_key (cybsecope cle SSH) Windows + Production -> rdp_psmp (RDP via PSMP CyberArk) Windows + autre -> rdp_local (RDP user@domain password) N'applique pas de defaut si ssh_method est deja renseigne (sauf --overwrite). Usage: python tools/fill_ssh_method_by_default.py [--dry-run] [--overwrite] """ import os import argparse from sqlalchemy import create_engine, text DATABASE_URL = os.getenv("DATABASE_URL_DEMO") or os.getenv("DATABASE_URL") \ or "postgresql://patchcenter:PatchCenter2026!@localhost:5432/patchcenter_demo" def pick_method(os_family, environnement): is_prod = (environnement == "Production") os_f = (os_family or "").lower() if os_f == "linux": return "ssh_psmp" if is_prod else "ssh_key" if os_f == "windows": return "rdp_psmp" if is_prod else "rdp_local" return None def main(): parser = argparse.ArgumentParser() parser.add_argument("--dry-run", action="store_true") parser.add_argument("--overwrite", action="store_true", help="Remplace ssh_method existant (sinon ne rempli que les vides/a_definir)") args = parser.parse_args() engine = create_engine(DATABASE_URL) print(f"[INFO] DB: {DATABASE_URL.split('@')[-1]}") conn = engine.connect().execution_options(isolation_level="AUTOCOMMIT") # Etend le CHECK constraint pour accepter les nouveaux modes SANEF print("[INFO] Drop ancien CHECK ssh_method...") conn.execute(text("ALTER TABLE servers DROP CONSTRAINT IF EXISTS servers_ssh_method_check")) conn.execute(text( "ALTER TABLE servers ADD CONSTRAINT servers_ssh_method_check " "CHECK (ssh_method IN ('ssh_key', 'ssh_psmp', 'ssh_password', " "'rdp_local', 'rdp_psmp', 'winrm', 'a_definir') OR ssh_method IS NULL)" )) where = "" if not args.overwrite: where = "AND (ssh_method IS NULL OR ssh_method = '' OR ssh_method = 'a_definir' OR ssh_method = 'ssh_key')" rows = conn.execute(text(f""" SELECT id, hostname, os_family, environnement, ssh_method FROM servers WHERE os_family IS NOT NULL {where} ORDER BY hostname """)).fetchall() print(f"[INFO] {len(rows)} candidats") stats = {"updated": 0, "skipped": 0, "unchanged": 0} by_method = {} for r in rows: target = pick_method(r.os_family, r.environnement) if not target: stats["skipped"] += 1 continue if r.ssh_method == target: stats["unchanged"] += 1 continue by_method[target] = by_method.get(target, 0) + 1 if args.dry_run: print(f" DRY: {r.hostname:25s} [{r.os_family}/{r.environnement or '-'}] " f"{r.ssh_method or 'NULL'} -> {target}") else: conn.execute(text("UPDATE servers SET ssh_method=:m WHERE id=:sid"), {"m": target, "sid": r.id}) stats["updated"] += 1 conn.close() print(f"\n[DONE] Maj: {stats['updated']} | Inchanges: {stats['unchanged']} " f"| Skip: {stats['skipped']}") if by_method: print("\nRepartition :") for m, n in sorted(by_method.items(), key=lambda x: -x[1]): print(f" {m:15s} {n}") if __name__ == "__main__": main()