-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtracker.py
More file actions
99 lines (83 loc) · 3.09 KB
/
tracker.py
File metadata and controls
99 lines (83 loc) · 3.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import json
import logging
import os
from datetime import date, datetime, timezone
import requests
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s")
log = logging.getLogger(__name__)
def fetch_vms(netbox_url: str, token: str) -> list[dict]:
headers = {"Authorization": f"Token {token}"}
url = f"{netbox_url}/api/virtualization/virtual-machines/?limit=100"
vms: list[dict] = []
while url:
resp = requests.get(url, headers=headers, timeout=30)
resp.raise_for_status()
payload = resp.json()
vms.extend(payload["results"])
url = payload.get("next")
return vms
def _name(obj: dict | None) -> str | None:
return obj["name"] if obj else None
def build_entry(vm: dict) -> dict:
cf = vm.get("custom_fields") or {}
return {
"name": vm["name"],
"netbox_url": vm.get("display_url"),
"status": (vm.get("status") or {}).get("value"),
"tenant": _name(vm.get("tenant")),
"cluster": _name(vm.get("cluster")),
"site": _name(vm.get("site")),
"tags": [t["slug"] for t in vm.get("tags") or []],
"description": vm.get("description") or None,
"environment": cf.get("environment"),
"project": cf.get("project"),
"expire_date": cf.get("expire_date"),
}
def main() -> None:
token = os.environ["NETBOX_TOKEN"]
netbox_url = os.environ.get("NETBOX_URL", "https://netbox.ethquokkaops.io").rstrip("/")
expiring_soon_days = int(os.environ.get("EXPIRING_SOON_DAYS", "7"))
today = datetime.now(timezone.utc).date()
try:
vms = fetch_vms(netbox_url, token)
except requests.exceptions.RequestException as e:
log.error(f"NetBox API request failed: {e}")
raise SystemExit(1)
log.info(f"Fetched {len(vms)} VMs from {netbox_url}")
expired, expiring_soon, no_expiry = [], [], []
for vm in vms:
entry = build_entry(vm)
raw = entry["expire_date"]
if not raw:
no_expiry.append(entry)
continue
try:
expire = date.fromisoformat(raw)
except ValueError:
log.warning(f"VM '{entry['name']}' has unparseable expire_date: {raw!r}")
no_expiry.append(entry)
continue
delta = (expire - today).days
entry["days_until_expiry"] = delta
if delta < 0:
expired.append(entry)
elif delta < expiring_soon_days:
expiring_soon.append(entry)
expired.sort(key=lambda e: e["days_until_expiry"])
expiring_soon.sort(key=lambda e: e["days_until_expiry"])
no_expiry.sort(key=lambda e: e["name"])
log.info(
f"Expired: {len(expired)}, "
f"expiring within {expiring_soon_days}d: {len(expiring_soon)}, "
f"no expiry set: {len(no_expiry)}"
)
print(json.dumps({
"generated_at": datetime.now(timezone.utc).isoformat(),
"netbox_url": netbox_url,
"expiring_soon_days": expiring_soon_days,
"expired": expired,
"expiring_soon": expiring_soon,
"no_expiry": no_expiry,
}, indent=2))
if __name__ == "__main__":
main()