Skip to content
Merged
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
7 changes: 6 additions & 1 deletion module/sources/common/source_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,12 @@ def map_object_interfaces_to_current_interfaces(self, device_vm_object, interfac

# grab current data
for interface in self.inventory.get_all_interfaces(device_vm_object):
int_mac = grab(interface, "data.mac_address")
# from NetBox 4.2 on 'mac_address' is a read-only leftover of the last NetBox read which sources
# don't update. Use the current primary MAC address object instead.
if version.parse(self.inventory.netbox_api_version) >= version.parse("4.2.0"):
int_mac = grab(grab(interface, "data.primary_mac_address"), "data.mac_address")
else:
int_mac = grab(interface, "data.mac_address")
int_name = grab(interface, "data.name")

if interface_exclude_filter is not None and int_name is not None and \
Expand Down
56 changes: 56 additions & 0 deletions tests/test_interface_matching_primary_mac.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# -*- 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>.

"""Interface matching by MAC must use the current primary MAC address object (NetBox >= 4.2).

The legacy interface 'mac_address' field is only what NetBox returned at read time. Once a
previous source moved the primary MAC to another address, matching on the stale value merged
a BMC port (i.e. Lenovo XCC) into the ESXi vmk0 interface on every run.
"""

from module.netbox.object_classes import NBInterface, NBMACAddress

BMC_MAC = "38:68:DD:34:33:C5"
VMK_MAC = "00:50:56:67:39:DA"


def seed_vmk0(context, legacy_mac, primary_mac):
interface = context.inventory.add_object(
NBInterface, data={"name": "vmk0", "device": context.device, "type": "virtual", "mac_address": legacy_mac},
source=context.source)
mac_object = context.inventory.add_object(
NBMACAddress, data={"mac_address": primary_mac, "assigned_object_id": interface,
"assigned_object_type": NBInterface}, source=context.source)
interface.update(data={"primary_mac_address": mac_object}, source=context.source)
return interface


def bmc_port():
return {"XCC (1:NIC:abc)": {"name": "XCC (1:NIC:abc)", "mac_address": BMC_MAC, "type": "other",
"mgmt_only": True}}


def test_bmc_port_ignores_stale_legacy_mac(check_redfish_source):

context = check_redfish_source()
seed_vmk0(context, legacy_mac=BMC_MAC, primary_mac=VMK_MAC)

data = context.source.map_object_interfaces_to_current_interfaces(context.device, bmc_port(), True)

assert data["XCC (1:NIC:abc)"] is None


def test_bmc_port_still_matches_by_primary_mac(check_redfish_source):

context = check_redfish_source()
vmk0 = seed_vmk0(context, legacy_mac=VMK_MAC, primary_mac=BMC_MAC)

data = context.source.map_object_interfaces_to_current_interfaces(context.device, bmc_port(), True)

assert data["XCC (1:NIC:abc)"] is vmk0
Loading