diff --git a/tools/fill_ips_by_dns.py b/tools/fill_ips_by_dns.py new file mode 100644 index 0000000..49bb8b4 --- /dev/null +++ b/tools/fill_ips_by_dns.py @@ -0,0 +1,109 @@ +"""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()