98 lines
3.3 KiB
Python
98 lines
3.3 KiB
Python
"""Lie les serveurs non-prod (r/t/d) a leur equivalent prod (p/i) par convention SANEF.
|
|
|
|
Regle : v[r|t|d]XXXX matche v[p|i]XXXX avec XXXX identique.
|
|
Ex: vrpaians1 <-> vppaians1
|
|
|
|
Ecrit dans server_correspondance (source='auto').
|
|
|
|
Usage:
|
|
python tools/link_prod_nonprod.py [--dry-run]
|
|
"""
|
|
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"
|
|
|
|
NONPROD_PREFIXES = {"r": "recette", "t": "test", "d": "dev"}
|
|
PROD_PREFIXES = ["p", "i"] # p=prod, i=integration (prod chez SANEF)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--dry-run", action="store_true")
|
|
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")
|
|
|
|
# Tous les serveurs non-prod (2eme lettre r/t/d)
|
|
rows = conn.execute(text("""
|
|
SELECT id, hostname FROM servers
|
|
WHERE LENGTH(hostname) >= 3
|
|
AND LOWER(SUBSTRING(hostname, 1, 1)) = 'v'
|
|
AND LOWER(SUBSTRING(hostname, 2, 1)) IN ('r','t','d')
|
|
ORDER BY hostname
|
|
""")).fetchall()
|
|
print(f"[INFO] {len(rows)} serveurs non-prod (v[rtd]*)")
|
|
|
|
# Cache hostname -> id pour lookup rapide
|
|
all_servers = {}
|
|
for r in conn.execute(text("SELECT id, LOWER(hostname) as h FROM servers")).fetchall():
|
|
all_servers[r.h] = r.id
|
|
|
|
stats = {"linked": 0, "already_linked": 0, "no_prod_match": 0}
|
|
no_match = []
|
|
|
|
for r in rows:
|
|
h = r.hostname.lower()
|
|
env_char = h[1] # r/t/d
|
|
rest = h[2:] # reste apres v + r/t/d
|
|
|
|
prod_id = None
|
|
prod_hostname = None
|
|
for pchar in PROD_PREFIXES:
|
|
candidate = f"v{pchar}{rest}"
|
|
if candidate in all_servers:
|
|
prod_id = all_servers[candidate]
|
|
prod_hostname = candidate
|
|
break
|
|
|
|
if not prod_id:
|
|
no_match.append(r.hostname)
|
|
stats["no_prod_match"] += 1
|
|
continue
|
|
|
|
# Existe deja ?
|
|
existing = conn.execute(text(
|
|
"SELECT id FROM server_correspondance WHERE prod_server_id=:p AND nonprod_server_id=:n"
|
|
), {"p": prod_id, "n": r.id}).fetchone()
|
|
if existing:
|
|
stats["already_linked"] += 1
|
|
continue
|
|
|
|
env_name = NONPROD_PREFIXES.get(env_char, env_char)
|
|
if args.dry_run:
|
|
print(f" DRY: {r.hostname} ({env_name}) <-> {prod_hostname} (prod)")
|
|
else:
|
|
conn.execute(text("""
|
|
INSERT INTO server_correspondance
|
|
(prod_server_id, nonprod_server_id, environment_code, source, note)
|
|
VALUES (:p, :n, :env, 'auto', 'Auto-link convention v[rtd]XXX -> v[pi]XXX')
|
|
"""), {"p": prod_id, "n": r.id, "env": env_name})
|
|
stats["linked"] += 1
|
|
|
|
conn.close()
|
|
print(f"\n[DONE] Liens: {stats['linked']} | Deja lies: {stats['already_linked']} "
|
|
f"| Sans match prod: {stats['no_prod_match']}")
|
|
if no_match and len(no_match) < 50:
|
|
print(f"\n[INFO] Non-prod sans equivalent prod ({len(no_match)}):")
|
|
for h in no_match[:30]:
|
|
print(f" {h}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|