diff --git a/app/routers/applications.py b/app/routers/applications.py index 750f812..22dc554 100644 --- a/app/routers/applications.py +++ b/app/routers/applications.py @@ -338,7 +338,7 @@ async def applications_assign_page(request: Request, app_id: int, db=Depends(get if not app: return RedirectResponse(url="/admin/applications?msg=notfound", status_code=303) - where = ["s.etat NOT IN ('stock','obsolete')"] + where = ["s.etat NOT IN ('Stock','Obsolète')"] params = {} if search: where.append("s.hostname ILIKE :s"); params["s"] = f"%{search}%" diff --git a/app/routers/audit.py b/app/routers/audit.py index b2c0df3..ab5e690 100644 --- a/app/routers/audit.py +++ b/app/routers/audit.py @@ -134,7 +134,7 @@ async def audit_global(request: Request, db=Depends(get_db)): parallel = int(form.get("parallel", "5")) # Construire la requete - where = ["s.os_family = 'linux'", "s.etat = 'production'"] + where = ["s.os_family = 'linux'", "s.etat = 'Production'"] params = {} if exclude_domains: where.append("d.code NOT IN :ed") diff --git a/app/routers/dashboard.py b/app/routers/dashboard.py index b4c8531..0094131 100644 --- a/app/routers/dashboard.py +++ b/app/routers/dashboard.py @@ -18,21 +18,21 @@ async def dashboard(request: Request, db=Depends(get_db)): # Stats generales stats = {} stats["total_servers"] = db.execute(text("SELECT COUNT(*) FROM servers")).scalar() - stats["patchable"] = db.execute(text("SELECT COUNT(*) FROM servers WHERE patch_os_owner='secops' AND etat='production'")).scalar() + stats["patchable"] = db.execute(text("SELECT COUNT(*) FROM servers WHERE patch_os_owner='secops' AND etat='Production'")).scalar() stats["linux"] = db.execute(text("SELECT COUNT(*) FROM servers WHERE os_family='linux'")).scalar() stats["windows"] = db.execute(text("SELECT COUNT(*) FROM servers WHERE os_family='windows'")).scalar() - stats["decom"] = db.execute(text("SELECT COUNT(*) FROM servers WHERE etat='obsolete'")).scalar() + stats["decom"] = db.execute(text("SELECT COUNT(*) FROM servers WHERE etat='Obsolète'")).scalar() stats["obsolete"] = db.execute(text("SELECT COUNT(*) FROM servers WHERE licence_support='obsolete'")).scalar() stats["qualys_assets"] = db.execute(text("SELECT COUNT(*) FROM qualys_assets")).scalar() stats["qualys_tags"] = db.execute(text("SELECT COUNT(*) FROM qualys_tags")).scalar() stats["qualys_active"] = db.execute(text("SELECT COUNT(*) FROM qualys_assets WHERE agent_status ILIKE '%active%' AND agent_status NOT ILIKE '%inactive%'")).scalar() stats["qualys_inactive"] = db.execute(text("SELECT COUNT(*) FROM qualys_assets WHERE agent_status ILIKE '%inactive%'")).scalar() - stats["qualys_no_agent"] = db.execute(text("SELECT COUNT(*) FROM servers WHERE etat='production' AND NOT EXISTS (SELECT 1 FROM qualys_assets qa WHERE LOWER(qa.hostname) = LOWER(servers.hostname))")).scalar() + stats["qualys_no_agent"] = db.execute(text("SELECT COUNT(*) FROM servers WHERE etat='Production' AND NOT EXISTS (SELECT 1 FROM qualys_assets qa WHERE LOWER(qa.hostname) = LOWER(servers.hostname))")).scalar() # Par domaine domains = db.execute(text(""" SELECT d.name, d.code, COUNT(s.id) as total, - COUNT(*) FILTER (WHERE s.etat='production') as actifs, + COUNT(*) FILTER (WHERE s.etat='Production') as actifs, COUNT(*) FILTER (WHERE s.os_family='linux') as linux, COUNT(*) FILTER (WHERE s.os_family='windows') as windows FROM servers s diff --git a/app/routers/planning.py b/app/routers/planning.py index a1cdda3..a22aa87 100644 --- a/app/routers/planning.py +++ b/app/routers/planning.py @@ -40,7 +40,7 @@ def _get_planning_data(db, year): SELECT d.code, d.name, COUNT(s.id) as srv_count FROM domains d LEFT JOIN domain_environments de ON de.domain_id = d.id - LEFT JOIN servers s ON s.domain_env_id = de.id AND s.etat = 'production' + LEFT JOIN servers s ON s.domain_env_id = de.id AND s.etat = 'Production' GROUP BY d.code, d.name, d.display_order ORDER BY d.display_order """)).fetchall() diff --git a/app/services/campaign_service.py b/app/services/campaign_service.py index 77ecbfa..12a9d8b 100644 --- a/app/services/campaign_service.py +++ b/app/services/campaign_service.py @@ -124,7 +124,7 @@ def get_servers_for_planning(db, year, week_number): or_clauses.append("z.name = 'DMZ'") where = f""" - s.etat = 'production' AND s.patch_os_owner = 'secops' + s.etat = 'Production' AND s.patch_os_owner = 'secops' AND s.licence_support IN ('active', 'els') AND s.os_family = 'linux' AND ({' OR '.join(or_clauses)}) """ diff --git a/app/services/correspondance_service.py b/app/services/correspondance_service.py index 6f8adf9..18b9557 100644 --- a/app/services/correspondance_service.py +++ b/app/services/correspondance_service.py @@ -53,7 +53,7 @@ def detect_correspondances(db, dry_run=False): # Tous les serveurs actifs (exclut stock/obsolete) rows = db.execute(text("""SELECT id, hostname FROM servers - WHERE etat NOT IN ('stock','obsolete','eol') ORDER BY hostname""")).fetchall() + WHERE etat NOT IN ('Stock','Obsolète','EOL') ORDER BY hostname""")).fetchall() by_signature = defaultdict(list) # signature -> [(server_id, env_char, hostname)] for r in rows: @@ -125,7 +125,7 @@ def detect_correspondances(db, dry_run=False): def get_servers_for_builder(db, search="", app="", domain="", env=""): """Retourne tous les serveurs matchant les filtres, avec leurs correspondances existantes. Exclut les serveurs en stock / obsolete (décommissionnés, EOL).""" - where = ["s.etat NOT IN ('stock','obsolete','eol')"] + where = ["s.etat NOT IN ('Stock','Obsolète','EOL')"] params = {} if search: where.append("s.hostname ILIKE :s"); params["s"] = f"%{search}%" @@ -181,7 +181,7 @@ def bulk_create_correspondance(db, prod_ids, nonprod_ids, env_labels, user_id): def get_correspondance_view(db, search="", app="", env=""): """Vue hiérarchique des correspondances groupées par application. Exclut les serveurs en stock/obsolete.""" - where = ["s.etat NOT IN ('stock','obsolete','eol')"] + where = ["s.etat NOT IN ('Stock','Obsolète','EOL')"] params = {} if search: where.append("s.hostname ILIKE :s"); params["s"] = f"%{search}%" @@ -330,7 +330,7 @@ def get_orphan_nonprod(db): LEFT JOIN environments e ON de.environment_id = e.id LEFT JOIN domains d ON de.domain_id = d.id WHERE e.name IS NOT NULL AND e.name NOT ILIKE '%production%' - AND s.etat NOT IN ('stock','obsolete','eol') + AND s.etat NOT IN ('Stock','Obsolète','EOL') AND NOT EXISTS (SELECT 1 FROM server_correspondance sc WHERE sc.nonprod_server_id = s.id) ORDER BY s.application_name, s.hostname LIMIT 500 diff --git a/app/services/itop_service.py b/app/services/itop_service.py index b982ba7..3c21c4d 100644 --- a/app/services/itop_service.py +++ b/app/services/itop_service.py @@ -337,10 +337,16 @@ def sync_from_itop(db, itop_url, itop_user, itop_pass): "patch_excludes,domain_ldap_name,last_patch_date," "applicationsolution_list") - # PatchCenter etat = iTop status (meme enum: production, implementation, stock, obsolete, eol) - itop_status = {"production": "production", "stock": "stock", - "implementation": "implementation", "obsolete": "obsolete", - "eol": "eol"} + # PatchCenter etat = label iTop verbatim (Production, Implémentation, Stock, Obsolète, EOL, prêt, tests, Nouveau, ...) + itop_status = { + "production": "Production", "implementation": "Implémentation", + "stock": "Stock", "obsolete": "Obsolète", "eol": "EOL", + "pret": "prêt", "tests": "tests", "nouveau": "Nouveau", + "casse": "Cassé", "cede": "Cédé", "en_panne": "En panne", + "a_recuperer": "A récupérer", "perdu": "Perdu", + "recycle": "Recyclé", "occasion": "Occasion", + "a_detruire": "A détruire", "vole": "Volé", + } for v in vms: hostname = v.get("name", "").split(".")[0].lower() @@ -404,7 +410,7 @@ def sync_from_itop(db, itop_url, itop_user, itop_pass): "os_family": "linux" if "linux" in v.get("osfamily_id_friendlyname", "").lower() else "windows", "os_version": v.get("osversion_id_friendlyname", ""), "machine_type": "vm", - "etat": itop_status.get(v.get("status", ""), "production"), + "etat": itop_status.get(v.get("status", ""), "Production"), "de_id": de_id, "zone_id": zone_id, "resp_srv": resp_srv_name, "resp_srv_email": person_email.get(resp_srv_name.lower(), ""), @@ -499,7 +505,7 @@ def sync_from_itop(db, itop_url, itop_user, itop_pass): try: db.execute(text("""INSERT INTO servers (hostname, fqdn, os_family, os_version, machine_type, etat, responsable_nom, commentaire, site, ssh_port, ssh_user, ssh_method, tier) - VALUES (:h, :f, :osf, :osv, 'physical', 'production', :resp, :desc, :site, + VALUES (:h, :f, :osf, :osv, 'physical', 'Production', :resp, :desc, :site, 22, 'root', 'ssh_key', 'tier0')"""), {"h": hostname, "f": s.get("name", hostname), "osf": osf, "osv": osv, "resp": resp, "desc": s.get("description", ""), @@ -562,8 +568,16 @@ def sync_to_itop(db, itop_url, itop_user, itop_pass): for v in client.get_all("VirtualMachine", "name"): itop_vms[v["name"].split(".")[0].lower()] = v - status_map = {"production": "production", "implementation": "implementation", - "stock": "stock", "obsolete": "obsolete", "eol": "eol"} + # DB (iTop label verbatim) -> iTop API internal code + status_map = { + "Production": "production", "Implémentation": "implementation", + "Stock": "stock", "Obsolète": "obsolete", "EOL": "eol", + "prêt": "pret", "tests": "tests", "Nouveau": "nouveau", + "Cassé": "casse", "Cédé": "cede", "En panne": "en_panne", + "A récupérer": "a_recuperer", "Perdu": "perdu", + "Recyclé": "recycle", "Occasion": "occasion", + "A détruire": "a_detruire", "Volé": "vole", + } tier_map = {"tier0": "Tier 0", "tier1": "Tier 1", "tier2": "Tier 2", "tier3": "Tier 3"} # Build OSVersion cache: name.lower() → itop_id @@ -599,7 +613,7 @@ def sync_to_itop(db, itop_url, itop_user, itop_pass): if srv.mgmt_ip: fields["managementip"] = srv.mgmt_ip.split("/")[0] if srv.etat: - fields["status"] = status_map.get(srv.etat, "production") + fields["status"] = status_map.get(srv.etat, "production") # iTop API internal code if srv.commentaire: fields["description"] = srv.commentaire if srv.patch_excludes: diff --git a/app/services/prereq_service.py b/app/services/prereq_service.py index edad0f4..c020b1b 100644 --- a/app/services/prereq_service.py +++ b/app/services/prereq_service.py @@ -146,7 +146,7 @@ def _check_server(s): result["eligible"] = False result["exclude_reason"] = "obsolete" result["exclude_detail"] = "Licence EOL" - elif s.etat != 'production': + elif s.etat != 'Production': result["eligible"] = False result["exclude_reason"] = "non_patchable" result["exclude_detail"] = f"Etat: {s.etat}" @@ -159,7 +159,7 @@ def _check_server(s): result["exclude_detail"] = "Licence EOL — serveur non supporte" return result - if s.etat != 'production': + if s.etat != 'Production': result["eligible"] = False result["exclude_reason"] = "non_patchable" result["exclude_detail"] = f"Etat: {s.etat}" @@ -256,7 +256,7 @@ def _auto_exclude(db, campaign_id): JOIN servers s ON ps.server_id = s.id WHERE ps.campaign_id = :cid AND ps.status = 'pending' AND (s.licence_support = 'obsolete' - OR s.etat != 'production' + OR s.etat != 'Production' OR ps.prereq_ssh = 'ko' OR ps.prereq_disk_ok = false) """), {"cid": campaign_id}).fetchall() @@ -265,7 +265,7 @@ def _auto_exclude(db, campaign_id): for s in non_eligible: if s.licence_support == 'obsolete': reason, detail = "obsolete", "Licence EOL — auto-exclu" - elif s.etat != 'production': + elif s.etat != 'Production': reason, detail = "non_patchable", f"Etat {s.etat} — auto-exclu" elif s.prereq_disk_ok is False: reason, detail = "creneau_inadequat", "Espace disque insuffisant — auto-exclu" diff --git a/app/services/quickwin_service.py b/app/services/quickwin_service.py index 7df42e5..8444cab 100644 --- a/app/services/quickwin_service.py +++ b/app/services/quickwin_service.py @@ -86,7 +86,7 @@ def get_eligible_servers(db): LEFT JOIN environments e ON de.environment_id = e.id LEFT JOIN quickwin_server_config qc ON qc.server_id = s.id WHERE s.os_family = 'linux' - AND s.etat = 'production' + AND s.etat = 'Production' AND s.patch_os_owner = 'secops' ORDER BY e.display_order, d.display_order, s.hostname """)).fetchall() @@ -184,7 +184,7 @@ def get_available_servers(db, run_id, search="", domains=None, envs=None, zones= LEFT JOIN environments e ON de.environment_id = e.id LEFT JOIN zones z ON s.zone_id = z.id WHERE s.os_family = 'linux' - AND s.etat = 'production' + AND s.etat = 'Production' AND s.patch_os_owner = 'secops' AND s.id NOT IN (SELECT server_id FROM quickwin_entries WHERE run_id = :rid) ORDER BY d.name, e.name, s.hostname @@ -211,7 +211,7 @@ def get_available_filters(db, run_id): LEFT JOIN environments e ON de.environment_id = e.id LEFT JOIN zones z ON s.zone_id = z.id WHERE s.os_family = 'linux' - AND s.etat = 'production' + AND s.etat = 'Production' AND s.patch_os_owner = 'secops' AND s.id NOT IN (SELECT server_id FROM quickwin_entries WHERE run_id = :rid) """), {"rid": run_id}).fetchall() diff --git a/app/templates/partials/server_detail.html b/app/templates/partials/server_detail.html index 2b5afc8..a92fd94 100644 --- a/app/templates/partials/server_detail.html +++ b/app/templates/partials/server_detail.html @@ -51,7 +51,7 @@
Environnement{{ s.environnement }}
Zone{{ s.zone or 'LAN' }}
Tier{{ s.tier }}
-
Etat{% if s.etat == 'obsolete' %}Décommissionné{% elif s.etat == 'eol' %}EOL{% else %}{{ s.etat }}{% endif %}
+
Etat{{ s.etat }}
diff --git a/app/templates/partials/server_edit.html b/app/templates/partials/server_edit.html index c014e8f..4b400f2 100644 --- a/app/templates/partials/server_edit.html +++ b/app/templates/partials/server_edit.html @@ -58,7 +58,7 @@
diff --git a/app/templates/qualys_agents.html b/app/templates/qualys_agents.html index aa10796..b526b03 100644 --- a/app/templates/qualys_agents.html +++ b/app/templates/qualys_agents.html @@ -212,7 +212,7 @@ function refreshAgents() { {{ s.domain or '-' }} {{ s.env or '-' }} {% if s.zone == 'DMZ' %}DMZ{% else %}{{ s.zone or '-' }}{% endif %} - {% if s.etat == 'obsolete' %}Décom.{% elif s.etat == 'eol' %}EOL{% elif s.etat == 'production' %}Prod{% else %}{{ (s.etat or '-')[:8] }}{% endif %} + {% if s.etat == 'Obsolète' %}Décom.{% elif s.etat == 'EOL' %}EOL{% elif s.etat == 'Production' %}Prod{% else %}{{ (s.etat or '-')[:8] }}{% endif %} {% endfor %} diff --git a/app/templates/qualys_deploy.html b/app/templates/qualys_deploy.html index e838f2e..9bf765a 100644 --- a/app/templates/qualys_deploy.html +++ b/app/templates/qualys_deploy.html @@ -127,7 +127,7 @@ {{ s.domain or '-' }} {{ s.env or '-' }} - {% if s.etat == 'production' %}Prod + {% if s.etat == 'Production' %}Prod {% else %}{{ s.etat or '-' }}{% endif %} diff --git a/app/templates/servers.html b/app/templates/servers.html index 7a3a8ea..ce2fc00 100644 --- a/app/templates/servers.html +++ b/app/templates/servers.html @@ -36,7 +36,7 @@ {% for t in ['tier0','tier1','tier2','tier3'] %}{% endfor %}