Skip to content

Commit add5fe8

Browse files
committed
Inventory: fix case fetching interfaces with fetch_all: False and max_uri_length: 0
When fetching interfaces of virtual-chassis child devices in a separate request to the master, the interfaces will be returned twice. Converted some lists to dicts to efficiently check if the interface ID already exists. Made same change for services and IP Addresses, in case they have similar issues.
1 parent 8888247 commit add5fe8

File tree

4 files changed

+632
-26
lines changed

4 files changed

+632
-26
lines changed

plugins/inventory/nb_inventory.py

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -397,11 +397,13 @@ def extract_platform(self, host):
397397

398398
def extract_services(self, host):
399399
try:
400-
return (
400+
services_lookup = (
401401
self.vm_services_lookup
402402
if host["is_virtual"]
403403
else self.device_services_lookup
404-
)[host["id"]]
404+
)
405+
406+
return list(services_lookup[host["id"]].values())
405407

406408
except Exception:
407409
return
@@ -485,15 +487,20 @@ def extract_tags(self, host):
485487

486488
def extract_interfaces(self, host):
487489
try:
488-
interfaces = (
490+
491+
interfaces_lookup = (
489492
self.vm_interfaces_lookup
490493
if host["is_virtual"]
491494
else self.device_interfaces_lookup
492-
)[host["id"]]
495+
)
496+
497+
interfaces = list(interfaces_lookup[host["id"]].values())
493498

494499
# Attach IP Addresses to their interface
495500
for interface in interfaces:
496-
interface["ip_addresses"] = self.ipaddresses_lookup[interface["id"]]
501+
interface["ip_addresses"] = list(
502+
self.ipaddresses_lookup[interface["id"]].values()
503+
)
497504

498505
return interfaces
499506
except Exception:
@@ -677,18 +684,23 @@ def refresh_services(self):
677684
)
678685
services = chain(device_services, vm_services)
679686

680-
# Construct a dictionary of lists, separately for devices and vms.
681-
# Allows looking up a list of services by device id or vm id
682-
self.device_services_lookup = defaultdict(list)
683-
self.vm_services_lookup = defaultdict(list)
687+
# Construct a dictionary of dictionaries, separately for devices and vms.
688+
# Allows looking up services by device id or vm id
689+
self.device_services_lookup = defaultdict(dict)
690+
self.vm_services_lookup = defaultdict(dict)
684691

685692
for service in services:
693+
service_id = service["id"]
694+
686695
if service.get("device"):
687-
self.device_services_lookup[service["device"]["id"]].append(service)
696+
self.device_services_lookup[service["device"]["id"]][
697+
service_id
698+
] = service
699+
688700
if service.get("virtual_machine"):
689-
self.vm_services_lookup[service["virtual_machine"]["id"]].append(
690-
service
691-
)
701+
self.vm_services_lookup[service["virtual_machine"]["id"]][
702+
service_id
703+
] = service
692704

693705
def refresh_interfaces(self):
694706

@@ -715,14 +727,17 @@ def refresh_interfaces(self):
715727
query_values=self.vms_lookup.keys(),
716728
)
717729

718-
# Construct a dictionary of lists, separately for devices and vms.
719-
# Allows looking up a list of interfaces by device id or vm id
720-
self.device_interfaces_lookup = defaultdict(list)
721-
self.vm_interfaces_lookup = defaultdict(list)
730+
# Construct a dictionary of dictionaries, separately for devices and vms.
731+
# For a given device id or vm id, get a lookup of interface id to interface
732+
# This is because interfaces may be returned multiple times when querying for virtual chassis parent and child in separate queries
733+
self.device_interfaces_lookup = defaultdict(dict)
734+
self.vm_interfaces_lookup = defaultdict(dict)
735+
722736
# /dcim/interfaces gives count_ipaddresses per interface. /virtualization/interfaces does not
723737
self.devices_with_ips = set()
724738

725739
for interface in device_interfaces:
740+
interface_id = interface["id"]
726741
device_id = interface["device"]["id"]
727742

728743
# Check if device_id is actually a device we've fetched, and was not filtered out by query_filters
@@ -736,16 +751,17 @@ def refresh_interfaces(self):
736751
if virtual_chassis_master is not None:
737752
device_id = virtual_chassis_master
738753

739-
self.device_interfaces_lookup[device_id].append(interface)
754+
self.device_interfaces_lookup[device_id][interface_id] = interface
740755

741756
# Keep track of what devices have interfaces with IPs, so if fetch_all is False we can avoid unnecessary queries
742757
if interface["count_ipaddresses"] > 0:
743758
self.devices_with_ips.add(device_id)
744759

745760
for interface in vm_interfaces:
746-
self.vm_interfaces_lookup[interface["virtual_machine"]["id"]].append(
747-
interface
748-
)
761+
interface_id = interface["id"]
762+
vm_id = interface["virtual_machine"]["id"]
763+
764+
self.vm_interfaces_lookup[vm_id][interface_id] = interface
749765

750766
# Note: depends on the result of refresh_interfaces for self.devices_with_ips
751767
def refresh_ipaddresses(self):
@@ -773,13 +789,17 @@ def refresh_ipaddresses(self):
773789

774790
# Construct a dictionary of lists, to allow looking up ip addresses by interface id
775791
# Note that interface ids share the same namespace for both devices and vms so this is a single dictionary
776-
self.ipaddresses_lookup = defaultdict(list)
792+
self.ipaddresses_lookup = defaultdict(dict)
793+
777794
for ipaddress in ipaddresses:
778795

779796
if not ipaddress.get("interface"):
780797
continue
781798

782-
self.ipaddresses_lookup[ipaddress["interface"]["id"]].append(ipaddress)
799+
interface_id = ipaddress["interface"]["id"]
800+
ip_id = ipaddress["id"]
801+
802+
self.ipaddresses_lookup[interface_id][ip_id] = ipaddress
783803

784804
# Remove "interface" attribute, as that's redundant when ipaddress is added to an interface
785805
del ipaddress["interface"]

0 commit comments

Comments
 (0)