feat: sync switch interface IP addresses
Read IPv4 and IPv6 addresses from Aruba CX, ArubaOS-Switch, and HPE Comware interfaces, display and assign them in NetBox, and add robust Aruba 6100 LLDP detail parsing with table fallback.
This commit is contained in:
@@ -23,6 +23,8 @@ Windows-Desktopanwendung zum Synchronisieren virtueller Maschinen sowie HPE-/Aru
|
|||||||
- Durchsuchbare, nach Mandant filterbare Auswahl vorhandener NetBox-Geräte
|
- Durchsuchbare, nach Mandant filterbare Auswahl vorhandener NetBox-Geräte
|
||||||
- Automatische Aktivierung von global deaktiviertem LLDP auf unterstützten Switches
|
- Automatische Aktivierung von global deaktiviertem LLDP auf unterstützten Switches
|
||||||
- Synchronisierung von Switch-Schnittstellen und optionalen LLDP-Verbindungen als NetBox-Kabel
|
- Synchronisierung von Switch-Schnittstellen und optionalen LLDP-Verbindungen als NetBox-Kabel
|
||||||
|
- Auslesen und Synchronisieren vorhandener IPv4-/IPv6-Adressen auf Switch-Schnittstellen
|
||||||
|
- Spezieller LLDP-Detailparser mit Tabellen-Fallback für Aruba-6100-Switches
|
||||||
|
|
||||||
## Verwendung
|
## Verwendung
|
||||||
|
|
||||||
|
|||||||
@@ -1095,13 +1095,17 @@ class NetBoxVMImporter:
|
|||||||
|
|
||||||
result_card = ttk.LabelFrame(main, text="Schnittstellen & LLDP-Nachbarn", style="Card.TLabelframe")
|
result_card = ttk.LabelFrame(main, text="Schnittstellen & LLDP-Nachbarn", style="Card.TLabelframe")
|
||||||
result_card.grid(row=3, column=0, sticky="nsew", pady=(0, 10))
|
result_card.grid(row=3, column=0, sticky="nsew", pady=(0, 10))
|
||||||
result_columns = ("switch", "interface", "state", "speed", "neighbor", "remote_port")
|
result_columns = ("switch", "interface", "state", "speed", "ips", "neighbor", "remote_port")
|
||||||
self.switch_result_tree = ttk.Treeview(result_card, columns=result_columns, show="headings")
|
self.switch_result_tree = ttk.Treeview(result_card, columns=result_columns, show="headings")
|
||||||
result_headings = {
|
result_headings = {
|
||||||
"switch": "Switch", "interface": "Schnittstelle", "state": "Status",
|
"switch": "Switch", "interface": "Schnittstelle", "state": "Status",
|
||||||
"speed": "Geschwindigkeit", "neighbor": "LLDP-Nachbar", "remote_port": "Nachbar-Port",
|
"speed": "Geschwindigkeit", "ips": "IP-Adressen",
|
||||||
|
"neighbor": "LLDP-Nachbar", "remote_port": "Nachbar-Port",
|
||||||
|
}
|
||||||
|
result_widths = {
|
||||||
|
"switch": 150, "interface": 140, "state": 70, "speed": 100,
|
||||||
|
"ips": 210, "neighbor": 170, "remote_port": 140,
|
||||||
}
|
}
|
||||||
result_widths = {"switch": 180, "interface": 150, "state": 80, "speed": 110, "neighbor": 210, "remote_port": 170}
|
|
||||||
for column in result_columns:
|
for column in result_columns:
|
||||||
self.switch_result_tree.heading(column, text=result_headings[column])
|
self.switch_result_tree.heading(column, text=result_headings[column])
|
||||||
self.switch_result_tree.column(column, width=result_widths[column])
|
self.switch_result_tree.column(column, width=result_widths[column])
|
||||||
@@ -1399,6 +1403,7 @@ class NetBoxVMImporter:
|
|||||||
self.switch_log(f"{switch['name']}: LLDP war deaktiviert und wurde automatisch aktiviert")
|
self.switch_log(f"{switch['name']}: LLDP war deaktiviert und wurde automatisch aktiviert")
|
||||||
self.switch_log(
|
self.switch_log(
|
||||||
f"{switch['name']}: {len(snapshot['interfaces'])} Schnittstellen, "
|
f"{switch['name']}: {len(snapshot['interfaces'])} Schnittstellen, "
|
||||||
|
f"{len(snapshot.get('ip_addresses', []))} IP-Adressen, "
|
||||||
f"{len(snapshot['neighbors'])} LLDP-Nachbarn"
|
f"{len(snapshot['neighbors'])} LLDP-Nachbarn"
|
||||||
)
|
)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
@@ -1424,6 +1429,7 @@ class NetBoxVMImporter:
|
|||||||
interface["name"],
|
interface["name"],
|
||||||
"Up" if interface.get("connected") else "Down",
|
"Up" if interface.get("connected") else "Down",
|
||||||
speed_text,
|
speed_text,
|
||||||
|
", ".join(interface.get("ip_addresses", [])),
|
||||||
neighbor.get("system_name", ""),
|
neighbor.get("system_name", ""),
|
||||||
neighbor.get("remote_port", ""),
|
neighbor.get("remote_port", ""),
|
||||||
))
|
))
|
||||||
@@ -1435,7 +1441,7 @@ class NetBoxVMImporter:
|
|||||||
if self.nb is None and not self.load_switch_devices():
|
if self.nb is None and not self.load_switch_devices():
|
||||||
return
|
return
|
||||||
switch_map = {switch["id"]: switch for switch in self.current_switches}
|
switch_map = {switch["id"]: switch for switch in self.current_switches}
|
||||||
totals = {"created": 0, "updated": 0, "cables": 0}
|
totals = {"created": 0, "updated": 0, "ip_addresses": 0, "cables": 0}
|
||||||
errors = []
|
errors = []
|
||||||
for switch_id, snapshot in self.switch_snapshots.items():
|
for switch_id, snapshot in self.switch_snapshots.items():
|
||||||
switch = switch_map.get(switch_id)
|
switch = switch_map.get(switch_id)
|
||||||
@@ -1453,7 +1459,7 @@ class NetBoxVMImporter:
|
|||||||
errors.extend(f"{switch['name']}: {error}" for error in result["errors"])
|
errors.extend(f"{switch['name']}: {error}" for error in result["errors"])
|
||||||
text = (
|
text = (
|
||||||
f"{totals['created']} Schnittstellen erstellt, {totals['updated']} aktualisiert, "
|
f"{totals['created']} Schnittstellen erstellt, {totals['updated']} aktualisiert, "
|
||||||
f"{totals['cables']} LLDP-Kabel angelegt."
|
f"{totals['ip_addresses']} IP-Adressen synchronisiert, {totals['cables']} LLDP-Kabel angelegt."
|
||||||
)
|
)
|
||||||
self.switch_log(text)
|
self.switch_log(text)
|
||||||
if errors:
|
if errors:
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
+159
-9
@@ -1,5 +1,6 @@
|
|||||||
"""SSH discovery and NetBox synchronization for HPE and Aruba switches."""
|
"""SSH discovery and NetBox synchronization for HPE and Aruba switches."""
|
||||||
|
|
||||||
|
import ipaddress
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -13,11 +14,17 @@ PLATFORMS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
COMMANDS = {
|
COMMANDS = {
|
||||||
"aruba_cx": ("no page", "show interface brief", "show lldp neighbor-info"),
|
"aruba_cx": ("no page", "show interface brief", "show lldp neighbor-info detail"),
|
||||||
"aruba_aos": ("no page", "show interfaces brief", "show lldp info remote-device"),
|
"aruba_aos": ("no page", "show interfaces brief", "show lldp info remote-device"),
|
||||||
"hpe_comware": ("screen-length disable", "display interface brief", "display lldp neighbor-information verbose"),
|
"hpe_comware": ("screen-length disable", "display interface brief", "display lldp neighbor-information verbose"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IP_COMMANDS = {
|
||||||
|
"aruba_cx": ("show ip interface brief", "show ipv6 interface brief"),
|
||||||
|
"aruba_aos": ("show ip", "show ipv6"),
|
||||||
|
"hpe_comware": ("display ip interface brief", "display ipv6 interface brief"),
|
||||||
|
}
|
||||||
|
|
||||||
LLDP_CONTROL = {
|
LLDP_CONTROL = {
|
||||||
"aruba_cx": {
|
"aruba_cx": {
|
||||||
"status": "show lldp configuration",
|
"status": "show lldp configuration",
|
||||||
@@ -110,10 +117,19 @@ def run_switch_commands(config):
|
|||||||
|
|
||||||
channel.send(interface_command + "\n")
|
channel.send(interface_command + "\n")
|
||||||
interfaces = _read_available(channel)
|
interfaces = _read_available(channel)
|
||||||
|
ip_outputs = []
|
||||||
|
for command in IP_COMMANDS[platform]:
|
||||||
|
channel.send(command + "\n")
|
||||||
|
ip_outputs.append(_read_available(channel))
|
||||||
channel.send(neighbor_command + "\n")
|
channel.send(neighbor_command + "\n")
|
||||||
neighbors = _read_available(channel)
|
neighbors = _read_available(channel)
|
||||||
|
if platform == "aruba_cx" and re.search(r"(?i)invalid input|unknown command|unrecognized", neighbors):
|
||||||
|
channel.send("show lldp neighbor-info\n")
|
||||||
|
neighbors = _read_available(channel)
|
||||||
return {
|
return {
|
||||||
"interfaces": interfaces,
|
"interfaces": interfaces,
|
||||||
|
"ipv4_interfaces": ip_outputs[0],
|
||||||
|
"ipv6_interfaces": ip_outputs[1],
|
||||||
"neighbors": neighbors,
|
"neighbors": neighbors,
|
||||||
"lldp_enabled_automatically": lldp_enabled_automatically,
|
"lldp_enabled_automatically": lldp_enabled_automatically,
|
||||||
}
|
}
|
||||||
@@ -147,7 +163,7 @@ def _interface_name(token):
|
|||||||
token = token.strip(" |:")
|
token = token.strip(" |:")
|
||||||
return bool(re.match(
|
return bool(re.match(
|
||||||
r"(?i)^(?:\d+(?:/\d+){0,3}|(?:GE|XGE|HGE|FGE|FortyGigE|Ten-GigabitEthernet|GigabitEthernet)\S+|"
|
r"(?i)^(?:\d+(?:/\d+){0,3}|(?:GE|XGE|HGE|FGE|FortyGigE|Ten-GigabitEthernet|GigabitEthernet)\S+|"
|
||||||
r"Bridge-Aggregation\d+|Trk\d+|lag\d+)$",
|
r"Bridge-Aggregation\d+|Trk\d+|lag\d+|Vlan-interface\d+|vlan\s*\d+|loopback\s*\d*|lo\d+|mgmt)$",
|
||||||
token,
|
token,
|
||||||
))
|
))
|
||||||
|
|
||||||
@@ -185,11 +201,77 @@ def parse_interfaces(output, platform):
|
|||||||
"mac_address": _normalize_mac(mac_match.group(0)) if mac_match else None,
|
"mac_address": _normalize_mac(mac_match.group(0)) if mac_match else None,
|
||||||
"description": description,
|
"description": description,
|
||||||
"neighbor": None,
|
"neighbor": None,
|
||||||
|
"ip_addresses": [],
|
||||||
|
"virtual": False,
|
||||||
})
|
})
|
||||||
seen.add(name)
|
seen.add(name)
|
||||||
return interfaces
|
return interfaces
|
||||||
|
|
||||||
|
|
||||||
|
def _address_with_mask(address, mask=None):
|
||||||
|
try:
|
||||||
|
if "/" in address:
|
||||||
|
return str(ipaddress.ip_interface(address))
|
||||||
|
if mask:
|
||||||
|
return str(ipaddress.ip_interface(f"{address}/{mask}"))
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def parse_interface_ips(ipv4_output, ipv6_output, platform):
|
||||||
|
entries = []
|
||||||
|
if platform == "aruba_aos":
|
||||||
|
for line in _clean_output(ipv4_output).splitlines():
|
||||||
|
match = re.match(
|
||||||
|
r"^\s*([^|]+?)\s*\|\s*(?:Manual|DHCP/Bootp|Disabled)\s+(\d+(?:\.\d+){3})\s+(\d+(?:\.\d+){3})",
|
||||||
|
line,
|
||||||
|
flags=re.I,
|
||||||
|
)
|
||||||
|
if match:
|
||||||
|
address = _address_with_mask(match.group(2), match.group(3))
|
||||||
|
if address and not address.startswith("0.0.0.0/"):
|
||||||
|
entries.append({"interface": match.group(1).strip(), "address": address})
|
||||||
|
current_interface = ""
|
||||||
|
for line in _clean_output(ipv6_output).splitlines():
|
||||||
|
vlan_match = re.match(r"^\s*Vlan Name\s*:\s*(.+)$", line, flags=re.I)
|
||||||
|
if vlan_match:
|
||||||
|
current_interface = vlan_match.group(1).strip()
|
||||||
|
address_match = re.search(r"([0-9a-fA-F:]+/\d{1,3})", line)
|
||||||
|
if address_match and current_interface:
|
||||||
|
address = _address_with_mask(address_match.group(1))
|
||||||
|
if address and not address.lower().startswith("fe80:"):
|
||||||
|
entries.append({"interface": current_interface, "address": address})
|
||||||
|
else:
|
||||||
|
for output, version in ((ipv4_output, 4), (ipv6_output, 6)):
|
||||||
|
for line in _clean_output(output).splitlines():
|
||||||
|
tokens = re.split(r"\s+", line.strip())
|
||||||
|
if len(tokens) < 2 or not _interface_name(tokens[0]):
|
||||||
|
continue
|
||||||
|
patterns = (
|
||||||
|
r"\b(\d+(?:\.\d+){3}/\d{1,2})\b"
|
||||||
|
if version == 4 else
|
||||||
|
r"\b([0-9a-fA-F]*:[0-9a-fA-F:]+/\d{1,3})\b"
|
||||||
|
)
|
||||||
|
match = re.search(patterns, line)
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
address = _address_with_mask(match.group(1))
|
||||||
|
if not address or address.startswith("0.0.0.0/") or address.lower().startswith("fe80:"):
|
||||||
|
continue
|
||||||
|
entries.append({"interface": tokens[0], "address": address})
|
||||||
|
unique = {}
|
||||||
|
for entry in entries:
|
||||||
|
unique[(entry["interface"].casefold(), entry["address"])] = entry
|
||||||
|
return list(unique.values())
|
||||||
|
|
||||||
|
|
||||||
|
def _interface_key(value):
|
||||||
|
value = value.casefold().replace("_", "").replace("-", "").replace(" ", "")
|
||||||
|
value = value.replace("vlaninterface", "vlan")
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
def _field(block, patterns):
|
def _field(block, patterns):
|
||||||
for pattern in patterns:
|
for pattern in patterns:
|
||||||
match = re.search(pattern, block, flags=re.I | re.M)
|
match = re.search(pattern, block, flags=re.I | re.M)
|
||||||
@@ -201,7 +283,7 @@ def _field(block, patterns):
|
|||||||
def parse_neighbors(output):
|
def parse_neighbors(output):
|
||||||
clean = _clean_output(output)
|
clean = _clean_output(output)
|
||||||
starts = list(re.finditer(
|
starts = list(re.finditer(
|
||||||
r"(?im)^(?:\s*(?:Local (?:Port|Interface|Intf)|LLDP neighbor-information of port)\s*[: ]\s*.+)$",
|
r"(?im)^(?:\s*(?:Port|Local (?:Port|Interface|Intf)|LLDP neighbor-information of port)\s*[: ]\s*.+)$",
|
||||||
clean,
|
clean,
|
||||||
))
|
))
|
||||||
if not starts:
|
if not starts:
|
||||||
@@ -211,18 +293,23 @@ def parse_neighbors(output):
|
|||||||
end = starts[index + 1].start() if index + 1 < len(starts) else len(clean)
|
end = starts[index + 1].start() if index + 1 < len(starts) else len(clean)
|
||||||
block = clean[start.start():end]
|
block = clean[start.start():end]
|
||||||
local_port = _field(block, (
|
local_port = _field(block, (
|
||||||
|
r"^\s*Port\s*:\s*(\S+)",
|
||||||
r"^\s*Local (?:Port|Interface|Intf)\s*[: ]\s*(\S+)",
|
r"^\s*Local (?:Port|Interface|Intf)\s*[: ]\s*(\S+)",
|
||||||
r"^\s*LLDP neighbor-information of port\s+(?:\d+\[)?([^\]\s:]+)\]?",
|
r"^\s*LLDP neighbor-information of port\s+(?:\d+\[)?([^\]\s:]+)\]?",
|
||||||
))
|
))
|
||||||
system_name = _field(block, (
|
system_name = _field(block, (
|
||||||
|
r"^\s*Neighbor Chassis-Name\s*:\s*(.+)$",
|
||||||
r"^\s*(?:System Name|SysName)\s*[: ]\s*(.+)$",
|
r"^\s*(?:System Name|SysName)\s*[: ]\s*(.+)$",
|
||||||
r"^\s*Neighbor name\s*[: ]\s*(.+)$",
|
r"^\s*Neighbor name\s*[: ]\s*(.+)$",
|
||||||
))
|
))
|
||||||
remote_port = _field(block, (
|
remote_port = _field(block, (
|
||||||
|
r"^\s*Neighbor Port-ID\s*:\s*(.+)$",
|
||||||
|
r"^\s*Neighbor Port-Desc\s*:\s*(.+)$",
|
||||||
r"^\s*(?:Port ID|PortId|Port ID subtype.*\n\s*Port ID)\s*[: ]\s*(.+)$",
|
r"^\s*(?:Port ID|PortId|Port ID subtype.*\n\s*Port ID)\s*[: ]\s*(.+)$",
|
||||||
r"^\s*(?:Port Description|PortDesc)\s*[: ]\s*(.+)$",
|
r"^\s*(?:Port Description|PortDesc)\s*[: ]\s*(.+)$",
|
||||||
))
|
))
|
||||||
management_ip = _field(block, (
|
management_ip = _field(block, (
|
||||||
|
r"^\s*Neighbor Management-Address\s*:\s*([0-9a-fA-F:.]+)",
|
||||||
r"^\s*(?:Management Address|Management address|Management IP)\s*[: ]\s*([0-9a-fA-F:.]+)",
|
r"^\s*(?:Management Address|Management address|Management IP)\s*[: ]\s*([0-9a-fA-F:.]+)",
|
||||||
))
|
))
|
||||||
if local_port and (system_name or remote_port):
|
if local_port and (system_name or remote_port):
|
||||||
@@ -268,21 +355,47 @@ def _parse_neighbor_table(output):
|
|||||||
def discover_switch(config):
|
def discover_switch(config):
|
||||||
outputs = run_switch_commands(config)
|
outputs = run_switch_commands(config)
|
||||||
interfaces = parse_interfaces(outputs["interfaces"], config["platform"])
|
interfaces = parse_interfaces(outputs["interfaces"], config["platform"])
|
||||||
|
interface_ips = parse_interface_ips(
|
||||||
|
outputs.get("ipv4_interfaces", ""),
|
||||||
|
outputs.get("ipv6_interfaces", ""),
|
||||||
|
config["platform"],
|
||||||
|
)
|
||||||
neighbors = parse_neighbors(outputs["neighbors"])
|
neighbors = parse_neighbors(outputs["neighbors"])
|
||||||
interface_map = {interface["name"].casefold(): interface for interface in interfaces}
|
interface_map = {_interface_key(interface["name"]): interface for interface in interfaces}
|
||||||
|
for item in interface_ips:
|
||||||
|
key = _interface_key(item["interface"])
|
||||||
|
interface = interface_map.get(key)
|
||||||
|
if not interface:
|
||||||
|
interface = {
|
||||||
|
"name": item["interface"],
|
||||||
|
"enabled": True,
|
||||||
|
"connected": True,
|
||||||
|
"speed_mbps": None,
|
||||||
|
"mac_address": None,
|
||||||
|
"description": "Logisches Layer-3-Interface",
|
||||||
|
"neighbor": None,
|
||||||
|
"ip_addresses": [],
|
||||||
|
"virtual": True,
|
||||||
|
}
|
||||||
|
interfaces.append(interface)
|
||||||
|
interface_map[key] = interface
|
||||||
|
interface["ip_addresses"].append(item["address"])
|
||||||
for neighbor in neighbors:
|
for neighbor in neighbors:
|
||||||
local = interface_map.get(neighbor["local_port"].casefold())
|
local = interface_map.get(_interface_key(neighbor["local_port"]))
|
||||||
if local:
|
if local:
|
||||||
local["neighbor"] = neighbor
|
local["neighbor"] = neighbor
|
||||||
return {
|
return {
|
||||||
"interfaces": interfaces,
|
"interfaces": interfaces,
|
||||||
|
"ip_addresses": interface_ips,
|
||||||
"neighbors": neighbors,
|
"neighbors": neighbors,
|
||||||
"raw": outputs,
|
"raw": outputs,
|
||||||
"lldp_enabled_automatically": outputs.get("lldp_enabled_automatically", False),
|
"lldp_enabled_automatically": outputs.get("lldp_enabled_automatically", False),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _netbox_interface_type(speed_mbps):
|
def _netbox_interface_type(speed_mbps, virtual=False):
|
||||||
|
if virtual:
|
||||||
|
return "virtual"
|
||||||
if not speed_mbps:
|
if not speed_mbps:
|
||||||
return "other"
|
return "other"
|
||||||
if speed_mbps >= 100_000:
|
if speed_mbps >= 100_000:
|
||||||
@@ -301,13 +414,15 @@ def _netbox_interface_type(speed_mbps):
|
|||||||
def sync_snapshot_to_netbox(nb, config, snapshot, create_cables=True):
|
def sync_snapshot_to_netbox(nb, config, snapshot, create_cables=True):
|
||||||
device_id = int(config["device_id"])
|
device_id = int(config["device_id"])
|
||||||
interface_records = {}
|
interface_records = {}
|
||||||
created = updated = cables = 0
|
created = updated = cables = ip_addresses = 0
|
||||||
errors = []
|
errors = []
|
||||||
|
device = nb.dcim.devices.get(id=device_id)
|
||||||
|
tenant_id = getattr(getattr(device, "tenant", None), "id", None) if device else None
|
||||||
for interface in snapshot["interfaces"]:
|
for interface in snapshot["interfaces"]:
|
||||||
payload = {
|
payload = {
|
||||||
"device": device_id,
|
"device": device_id,
|
||||||
"name": interface["name"],
|
"name": interface["name"],
|
||||||
"type": _netbox_interface_type(interface.get("speed_mbps")),
|
"type": _netbox_interface_type(interface.get("speed_mbps"), interface.get("virtual", False)),
|
||||||
"enabled": interface.get("enabled", True),
|
"enabled": interface.get("enabled", True),
|
||||||
}
|
}
|
||||||
if interface.get("description"):
|
if interface.get("description"):
|
||||||
@@ -326,6 +441,35 @@ def sync_snapshot_to_netbox(nb, config, snapshot, create_cables=True):
|
|||||||
except Exception as error:
|
except Exception as error:
|
||||||
errors.append(f"Interface {interface['name']}: {error}")
|
errors.append(f"Interface {interface['name']}: {error}")
|
||||||
|
|
||||||
|
for interface in snapshot["interfaces"]:
|
||||||
|
record = interface_records.get(interface["name"].casefold())
|
||||||
|
if not record:
|
||||||
|
continue
|
||||||
|
for address in interface.get("ip_addresses", []):
|
||||||
|
try:
|
||||||
|
host = str(ipaddress.ip_interface(address).ip)
|
||||||
|
candidates = [
|
||||||
|
item for item in nb.ipam.ip_addresses.filter(address=host)
|
||||||
|
if getattr(getattr(item, "vrf", None), "id", None) is None
|
||||||
|
]
|
||||||
|
if len(candidates) > 1:
|
||||||
|
raise ValueError("mehrere globale IP-Adressen mit diesem Host gefunden")
|
||||||
|
payload = {
|
||||||
|
"address": address,
|
||||||
|
"status": "active",
|
||||||
|
"assigned_object_type": "dcim.interface",
|
||||||
|
"assigned_object_id": record.id,
|
||||||
|
}
|
||||||
|
if tenant_id:
|
||||||
|
payload["tenant"] = tenant_id
|
||||||
|
if candidates:
|
||||||
|
candidates[0].update(payload)
|
||||||
|
else:
|
||||||
|
nb.ipam.ip_addresses.create(payload)
|
||||||
|
ip_addresses += 1
|
||||||
|
except Exception as error:
|
||||||
|
errors.append(f"IP-Adresse {address} auf {interface['name']}: {error}")
|
||||||
|
|
||||||
if create_cables:
|
if create_cables:
|
||||||
for neighbor in snapshot["neighbors"]:
|
for neighbor in snapshot["neighbors"]:
|
||||||
try:
|
try:
|
||||||
@@ -349,4 +493,10 @@ def sync_snapshot_to_netbox(nb, config, snapshot, create_cables=True):
|
|||||||
f"Nachbar {neighbor.get('local_port')} → {neighbor.get('system_name')} "
|
f"Nachbar {neighbor.get('local_port')} → {neighbor.get('system_name')} "
|
||||||
f"{neighbor.get('remote_port')}: {error}"
|
f"{neighbor.get('remote_port')}: {error}"
|
||||||
)
|
)
|
||||||
return {"created": created, "updated": updated, "cables": cables, "errors": errors}
|
return {
|
||||||
|
"created": created,
|
||||||
|
"updated": updated,
|
||||||
|
"ip_addresses": ip_addresses,
|
||||||
|
"cables": cables,
|
||||||
|
"errors": errors,
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user