Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions module/sources/vmware/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,12 @@ def __init__(self):
description="""define if the name of the device interface discovered overwrites the
interface name in NetBox. The interface will only be matched by identical MAC address""",
default_value=True),
ConfigOption("overwrite_host_interface_type",
bool,
description="""define if the type of a host interface derived from its link speed
overwrites a physical interface type in NetBox. Set to False if a source which knows the
hardware (i.e. check_redfish) sets the type of the host interfaces""",
default_value=True),
ConfigOption("overwrite_vm_interface_name",
bool,
description="""define if the name of the VM interface discovered overwrites the
Expand Down
10 changes: 10 additions & 0 deletions module/sources/vmware/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -1894,6 +1894,16 @@ def add_device_vm_to_inventory(self, object_type, object_data, pnic_data=None, v
if object_type == NBVM and self.settings.overwrite_vm_interface_name is False:
del int_data["name"]

# vCenter derives the pNIC type from the current link speed only. Keep a physical type
# set by a source which knows the hardware (i.e. check_redfish) if configured.
if object_type == NBDevice and self.settings.overwrite_host_interface_type is False:
current_type = grab(nic_object_dict.get(int_name), "data.type")
# NetBox returns choice fields as {"value": ..., "label": ...}
if isinstance(current_type, dict):
current_type = current_type.get("value")
if current_type not in [None, "virtual", "bridge", "lag", "other"]:
int_data.pop("type", None)

# add/update interface with retrieved data
nic_object, ip_address_objects = self.add_update_interface(nic_object_dict.get(int_name), device_vm_object,
int_data, nic_ips.get(int_name, list()),
Expand Down
5 changes: 5 additions & 0 deletions settings-example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,11 @@ password = super-secret
; NetBox. The interface will only be matched by identical MAC address
;overwrite_device_interface_name = True

; define if the type of a host interface derived from its link speed overwrites a physical
; interface type in NetBox. Set to False if a source which knows the hardware (i.e.
; check_redfish) sets the type of the host interfaces
;overwrite_host_interface_type = True

; define if the name of the VM interface discovered overwrites the interface name in
; NetBox. The interface will only be matched by identical MAC address
;overwrite_vm_interface_name = True
Expand Down
94 changes: 94 additions & 0 deletions tests/test_vmware_host_nic_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020 - 2026 netbox-sync team. All rights reserved.
#
# netbox-sync.py
#
# This work is licensed under the terms of the MIT license.
# For a copy, see file LICENSE.txt included in this
# repository or visit: <https://opensource.org/licenses/MIT>.

"""
vCenter only knows the current link speed of a host pNIC, so the interface type it derives
is a guess. With 'overwrite_host_interface_type = False' a physical type already in NetBox
(i.e. an SFP+ port set by the check_redfish source, running at 1G or without link) is kept.
Otherwise both sources overwrite each other's type. By default vCenter still sets the type.
"""
import pytest

from module.netbox.object_classes import NBDevice, NBInterface
from module.sources import instantiate_sources

KEEP_TYPE = "\noverwrite_host_interface_type = False\n"


def first_sync(vcsim, inventory, load_config, settings):
load_config(settings)
first_run = instantiate_sources()[0]
inventory.resolve_relations()
first_run.apply()

interfaces = [i for i in inventory.get_all_items(NBInterface)
if i.data.get("type") not in [None, "virtual", "other"]]
if not interfaces:
pytest.skip(f"vcsim dump '{vcsim.name}' has no physical host interfaces")

# the second run finds the objects of the first one in NetBox
for nb_id, this_object in enumerate(inventory.get_all_items(NBInterface) + inventory.get_all_items(NBDevice),
start=1):
this_object.nb_id = nb_id
this_object.is_new = False
this_object.updated_items = list()
this_object.unset_items = list()

return {interface: interface.data.get("type") for interface in interfaces}


def second_sync(inventory, load_config, settings, nic_type):
for interface in inventory.get_all_items(NBInterface):
if interface.data.get("type") not in [None, "virtual"]:
# the shape NetBox hands back for a choice field
interface.data["type"] = {"value": nic_type, "label": nic_type}

inventory.source_list = []
load_config(settings)
second_run = instantiate_sources()[0]
inventory.resolve_relations()
second_run.apply()


def type_value(interface):
nic_type = interface.data.get("type")
return nic_type.get("value") if isinstance(nic_type, dict) else nic_type


def test_physical_type_is_kept(vcsim, inventory, load_config, vmware_settings):
discovered = first_sync(vcsim, inventory, load_config, vmware_settings + KEEP_TYPE)

second_sync(inventory, load_config, vmware_settings + KEEP_TYPE, "10gbase-x-sfpp")

for interface in discovered:
assert type_value(interface) == "10gbase-x-sfpp", \
f"type of '{interface.get_display_name()}' was overwritten from the link speed"


def test_type_other_is_still_updated(vcsim, inventory, load_config, vmware_settings):
discovered = first_sync(vcsim, inventory, load_config, vmware_settings + KEEP_TYPE)

second_sync(inventory, load_config, vmware_settings + KEEP_TYPE, "other")

for interface, discovered_type in discovered.items():
assert type_value(interface) == discovered_type, \
f"type 'other' of '{interface.get_display_name()}' was not updated"


def test_type_is_overwritten_by_default(vcsim, inventory, load_config, vmware_settings):
"""vCenter-only setups still get a wrong type corrected"""
discovered = first_sync(vcsim, inventory, load_config, vmware_settings)

second_sync(inventory, load_config, vmware_settings, "400gbase-x-qsfpdd")

for interface, discovered_type in discovered.items():
if discovered_type == "400gbase-x-qsfpdd":
continue
assert type_value(interface) == discovered_type, \
f"type of '{interface.get_display_name()}' was not set from the link speed"
Loading