From 3261be9bda3bd7416b3b73e9f321a2eefe1d520b Mon Sep 17 00:00:00 2001 From: pavel Date: Tue, 4 Nov 2025 17:27:49 +0200 Subject: [PATCH] 17:27 --- files/nb_onedevice_update.py | 40 +++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/files/nb_onedevice_update.py b/files/nb_onedevice_update.py index 3c41018..61671cd 100644 --- a/files/nb_onedevice_update.py +++ b/files/nb_onedevice_update.py @@ -4,23 +4,22 @@ nb_sync_one_device.py Update a single NetBox device from Cloud by hostname — ONLY if device is online. -Flow -1) Input: hostname (positional arg). -2) NetBox: lookup device by name -> read custom_fields.cloud_id. -3) Cloud: GET /v1/devices/{cloud_id}/liveness; if isConnected == false -> exit with "device is not online". -4) Cloud: GET /v1/devices/{cloud_id} -> read firmwareVersion, ipAddress, nodeName, sectorName, smallCellName, serialNumber. -5) NetBox updates (idempotent by default): - - custom_fields.fw_version ← firmwareVersion - - custom_fields.nodeName ← nodeName - - custom_fields.sectorName ← sectorName - - custom_fields.smallCellName ← smallCellName - - serial ← serialNumber -6) IP handling (only when online): - - If Cloud ipAddress is valid (not None/""/"0.0.0.0"): - ensure eth0, ensure/create IP, MOVE if needed, set primary_ip4, - then PRUNE all other IPs on the device (default behavior). - - If Cloud ipAddress is placeholder/invalid: skip IP changes and keep NetBox IPs as-is. -7) Single-line OK/FAIL and proper exit code. +Behavior +- Liveness gate via /v1/devices/{cloud_id}/liveness (no changes if offline). +- Updates NetBox fields from Cloud: + custom_fields.fw_version ← firmwareVersion + custom_fields.nodeName ← nodeName + custom_fields.sectorName ← sectorName + custom_fields.smallCellName ← smallCellName + serial ← serialNumber +- IP handling: + If Cloud ipAddress is valid (not None/""/"0.0.0.0"): + ensure eth0, ensure/create IP, MOVE from other device if needed, set primary_ip4, + then PRUNE all other IPs on this device (default). + If Cloud ipAddress is placeholder/invalid: + skip IP changes and do not prune. +- --chatty logs step-by-step to stderr; stdout remains one-line OK/FAIL. +- NEW: Logs custom field cf_upgrade_cmd as `NB: upgrade_cmd=` when --chatty. Exit codes: 0 = success @@ -185,12 +184,10 @@ class NetBox: # --- Helpers for pruning --- def list_device_ips(self, dev_id: int) -> List[Dict]: - # Try device_id filter (NetBox ≥3.6); otherwise fall back via interface scan r = S_NB.get(self._url("/api/ipam/ip-addresses/"), headers=self._h(), params={"device_id": dev_id, "limit": 1000}, timeout=REQ_TIMEOUT) if r.status_code == 200: return r.json().get("results") or [] - # Fallback path ips: List[Dict] = [] r2 = S_NB.get(self._url("/api/dcim/interfaces/"), headers=self._h(), params={"device_id": dev_id, "limit": 1000}, timeout=REQ_TIMEOUT) @@ -254,6 +251,11 @@ def run(hostname: str) -> None: dev_id = dev["id"] dev_full = nb.get_device(dev_id) cf = dev_full.get("custom_fields") or {} + + # NEW: log upgrade command if present + upgrade_cmd = cf.get("cf_upgrade_cmd") + log(f"NB: upgrade_cmd={upgrade_cmd}") + cloud_id = cf.get("cloud_id") if cloud_id in (None, "", "null"): die(1, f"FAIL {hostname} has no custom_fields.cloud_id in NetBox")