"""Fallback IP via DNS pour les serveurs sans IP en base. Pour chaque server sans entry server_ips : - Essaie resolve(hostname.domain_ltd) si domain_ltd renseigne - Sinon teste les suffixes SANEF (sanef.groupe, sanef-rec.fr, recette.adds, sanef-int.adds, serveur.est.sanef.fr, serveur.ouest.sanef.fr, sanef.fr) - Insere l'IP resolue (ip_type='primary', description='DNS lookup') Usage: python tools/fill_ips_by_dns.py [--dry-run] [--timeout 1] """ import os import socket import threading 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" SUFFIXES = [ "sanef.groupe", "sanef-rec.fr", "recette.adds", "sanef-int.adds", "serveur.est.sanef.fr", "serveur.ouest.sanef.fr", "sanef.fr", "sanef-int.fr", ] def resolve(fqdn, timeout): result = [None] def _do(): try: result[0] = socket.gethostbyname(fqdn) except Exception: pass t = threading.Thread(target=_do, daemon=True) t.start() t.join(timeout) return result[0] def main(): parser = argparse.ArgumentParser() parser.add_argument("--dry-run", action="store_true") parser.add_argument("--timeout", type=float, default=1.0) 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") rows = conn.execute(text(""" SELECT s.id, s.hostname, s.domain_ltd FROM servers s WHERE NOT EXISTS (SELECT 1 FROM server_ips si WHERE si.server_id=s.id) AND s.hostname IS NOT NULL ORDER BY s.hostname """)).fetchall() print(f"[INFO] {len(rows)} serveurs sans IP") inserted = skipped = 0 for i, r in enumerate(rows, 1): h = r.hostname print(f" [{i}/{len(rows)}] {h}...", flush=True) # Essaie suffixes dans l'ordre: domain_ltd prioritaire, puis les autres order = [] if r.domain_ltd: order.append(r.domain_ltd) for s in SUFFIXES: if s not in order: order.append(s) ip = None used_suffix = None for suffix in order: ip = resolve(f"{h}.{suffix}", args.timeout) if ip: used_suffix = suffix break if not ip: skipped += 1 continue if args.dry_run: print(f" DRY: {h} <- {ip} (via {used_suffix})") inserted += 1 continue try: conn.execute(text(""" INSERT INTO server_ips (server_id, ip_address, ip_type, description) VALUES (:sid, CAST(:ip AS inet), 'primary', :d) """), {"sid": r.id, "ip": ip, "d": f"DNS {used_suffix}"}) inserted += 1 print(f" OK: {h} <- {ip} (via {used_suffix})", flush=True) except Exception as e: print(f" [ERR] {h} {ip}: {str(e)[:100]}") skipped += 1 conn.close() print(f"\n[DONE] Inserts: {inserted} | Sans DNS: {skipped}") if __name__ == "__main__": main()