Add tag_obsolete_os: licence_support=obsolete pour OS EOL (RHEL 5/6/7, Win 2008/2012, Debian 8-10, etc.)
This commit is contained in:
parent
0cfdab7c61
commit
7f6ccc763b
109
tools/tag_obsolete_os.py
Normal file
109
tools/tag_obsolete_os.py
Normal file
@ -0,0 +1,109 @@
|
||||
"""Tag servers avec OS en fin de support -> licence_support='obsolete'.
|
||||
|
||||
Regles EOL (end of life) appliquees :
|
||||
- RHEL 5, 6, 7 (7.9 EOL 2024-06-30)
|
||||
- CentOS 5, 6, 7, 8
|
||||
- Oracle Linux 5, 6, 7
|
||||
- Windows Server 2003, 2008, 2012, 2012 R2
|
||||
- Debian 8, 9, 10 (Debian 10 EOL 2024-06-30)
|
||||
- Ubuntu 12.04, 14.04, 16.04, 18.04
|
||||
- SUSE < 12
|
||||
|
||||
N'affecte que licence_support (pas etat). Le patching existant exclut deja
|
||||
les serveurs avec licence_support='obsolete'.
|
||||
|
||||
Usage:
|
||||
python tools/tag_obsolete_os.py [--dry-run] [--overwrite]
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
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"
|
||||
|
||||
# Patterns regex (case-insensitive) sur os_version indiquant un OS EOL
|
||||
EOL_PATTERNS = [
|
||||
(r"red\s*hat.*(?:release\s+)?[567]\b", "RHEL 5/6/7"),
|
||||
(r"centos.*(?:release\s+)?[5678]\b", "CentOS 5/6/7/8"),
|
||||
(r"oracle.*linux.*(?:release\s+)?[567]\b", "Oracle Linux 5/6/7"),
|
||||
(r"windows.*2003", "Windows 2003"),
|
||||
(r"windows.*2008", "Windows 2008"),
|
||||
(r"windows.*2012", "Windows 2012"),
|
||||
(r"debian.*(?:gnu/linux\s+)?[89]\b", "Debian 8/9"),
|
||||
(r"debian.*(?:gnu/linux\s+)?10\b", "Debian 10"),
|
||||
(r"ubuntu.*1[2468]\.04", "Ubuntu 12.04/14.04/16.04/18.04"),
|
||||
(r"suse.*(?:enterprise.*)?(?:server.*)?(?:sp\d\s*)?1[01]\b", "SUSE 10/11"),
|
||||
]
|
||||
|
||||
|
||||
def classify(os_version):
|
||||
if not os_version:
|
||||
return None
|
||||
v = os_version.lower()
|
||||
for pattern, label in EOL_PATTERNS:
|
||||
if re.search(pattern, v):
|
||||
return label
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--dry-run", action="store_true")
|
||||
parser.add_argument("--overwrite", action="store_true",
|
||||
help="Remplace licence_support='active' par 'obsolete' (sinon skip les active)")
|
||||
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 id, hostname, os_version, licence_support
|
||||
FROM servers
|
||||
WHERE os_version IS NOT NULL AND os_version != ''
|
||||
""")).fetchall()
|
||||
print(f"[INFO] {len(rows)} serveurs avec os_version")
|
||||
|
||||
stats = {"tagged": 0, "already_obsolete": 0, "not_eol": 0, "skipped_active": 0}
|
||||
by_label = {}
|
||||
|
||||
for r in rows:
|
||||
label = classify(r.os_version)
|
||||
if not label:
|
||||
stats["not_eol"] += 1
|
||||
continue
|
||||
if r.licence_support == "obsolete":
|
||||
stats["already_obsolete"] += 1
|
||||
continue
|
||||
# Si deja 'active' ou 'els', on ne touche pas sauf --overwrite
|
||||
if r.licence_support in ("active", "els") and not args.overwrite:
|
||||
stats["skipped_active"] += 1
|
||||
if args.dry_run:
|
||||
print(f" SKIP (--overwrite pour forcer): {r.hostname:25s} "
|
||||
f"[{r.licence_support}] {label} | {r.os_version[:60]}")
|
||||
continue
|
||||
|
||||
by_label[label] = by_label.get(label, 0) + 1
|
||||
if args.dry_run:
|
||||
print(f" DRY: {r.hostname:25s} [{r.licence_support or 'NULL'}] -> obsolete "
|
||||
f"({label}) | {r.os_version[:60]}")
|
||||
else:
|
||||
conn.execute(text("UPDATE servers SET licence_support='obsolete' WHERE id=:sid"),
|
||||
{"sid": r.id})
|
||||
stats["tagged"] += 1
|
||||
|
||||
conn.close()
|
||||
print(f"\n[DONE] Tagges obsolete: {stats['tagged']} | "
|
||||
f"Deja obsolete: {stats['already_obsolete']} | "
|
||||
f"Non-EOL: {stats['not_eol']} | "
|
||||
f"Skip (active/els): {stats['skipped_active']}")
|
||||
if by_label:
|
||||
print("\nRepartition par famille EOL :")
|
||||
for label, n in sorted(by_label.items(), key=lambda x: -x[1]):
|
||||
print(f" {label:40s} {n}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user