17:27
This commit is contained in:
@@ -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=<value>` 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")
|
||||
|
||||
Reference in New Issue
Block a user