Add link_prod_nonprod: lie v[rtd]XXX <-> v[pi]XXX dans server_correspondance
This commit is contained in:
parent
52cb7b4cfc
commit
2a11a27675
97
tools/link_prod_nonprod.py
Normal file
97
tools/link_prod_nonprod.py
Normal file
@ -0,0 +1,97 @@
|
||||
"""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()
|
||||
Loading…
Reference in New Issue
Block a user