Procházet zdrojové kódy

fix(dcim): Resolve VC position when replicating relationships (#22710)

Pass the device context to resolve_name() when creating port mappings
and assigning interface bridges. This ensures that component template
names containing {vc_position} resolve consistently with the names of
the instantiated device components.

Fixes #22707
Martin Hauser před 1 týdnem
rodič
revize
d857c145c0
2 změnil soubory, kde provedl 71 přidání a 4 odebrání
  1. 64 0
      netbox/dcim/tests/test_models.py
  2. 7 4
      netbox/dcim/utils.py

+ 64 - 0
netbox/dcim/tests/test_models.py

@@ -2570,6 +2570,70 @@ class VCPositionTokenTestCase(TestCase):
         interface = device.interfaces.get(name='ge-2/1/0')
         self.assertEqual(interface.label, 'Member 2 / Slot 1')
 
+    @tag('regression')  # Ref: #22707
+    def test_vc_position_token_interface_bridge_device_type_template(self):
+        site = Site.objects.first()
+        device_type = DeviceType.objects.first()
+        device_role = DeviceRole.objects.first()
+
+        bridge_template = InterfaceTemplate.objects.create(
+            device_type=device_type,
+            name='br-{vc_position}',
+            type='bridge',
+        )
+        InterfaceTemplate.objects.create(
+            device_type=device_type,
+            name='ge-{vc_position}/0/1',
+            type='1000base-t',
+            bridge=bridge_template,
+        )
+        vc = VirtualChassis.objects.create(name='Test VC 5')
+        device = Device.objects.create(
+            name='Device VC 5', device_type=device_type, role=device_role,
+            site=site, virtual_chassis=vc, vc_position=5,
+        )
+
+        interface = device.interfaces.get(name='ge-5/0/1')
+        self.assertEqual(interface.bridge, device.interfaces.get(name='br-5'))
+
+    @tag('regression')  # Ref: #22707
+    def test_vc_position_token_port_mapping_device_type_template(self):
+        site = Site.objects.first()
+        device_type = DeviceType.objects.first()
+        device_role = DeviceRole.objects.first()
+
+        rear_port_template = RearPortTemplate.objects.create(
+            device_type=device_type,
+            name='rp-{vc_position}/1',
+            type=PortTypeChoices.TYPE_LC,
+            positions=1,
+        )
+        front_port_template = FrontPortTemplate.objects.create(
+            device_type=device_type,
+            name='fp-{vc_position}/1',
+            type=PortTypeChoices.TYPE_LC,
+            positions=1,
+        )
+        PortTemplateMapping.objects.create(
+            device_type=device_type,
+            front_port=front_port_template,
+            front_port_position=1,
+            rear_port=rear_port_template,
+            rear_port_position=1,
+        )
+        vc = VirtualChassis.objects.create(name='Test VC 6')
+        device = Device.objects.create(
+            name='Device VC 6', device_type=device_type, role=device_role,
+            site=site, virtual_chassis=vc, vc_position=6,
+        )
+
+        front_port = FrontPort.objects.get(device=device, name='fp-6/1')
+        rear_port = RearPort.objects.get(device=device, name='rp-6/1')
+        mapping = PortMapping.objects.get(device=device, front_port=front_port)
+        self.assertEqual(mapping.rear_port, rear_port)
+        self.assertEqual(mapping.front_port_position, 1)
+        self.assertEqual(mapping.rear_port_position, 1)
+
 
 class SiteSignalTestCase(TestCase):
 

+ 7 - 4
netbox/dcim/utils.py

@@ -127,12 +127,15 @@ def update_interface_bridges(device, interface_templates, module=None):
     Interface = apps.get_model('dcim', 'Interface')
 
     for interface_template in interface_templates.exclude(bridge=None):
-        interface = Interface.objects.get(device=device, name=interface_template.resolve_name(module=module))
+        interface = Interface.objects.get(
+            device=device,
+            name=interface_template.resolve_name(module=module, device=device)
+        )
 
         if interface_template.bridge:
             interface.bridge = Interface.objects.get(
                 device=device,
-                name=interface_template.bridge.resolve_name(module=module)
+                name=interface_template.bridge.resolve_name(module=module, device=device)
             )
             interface.full_clean()
             interface.save()
@@ -157,8 +160,8 @@ def create_port_mappings(device, device_or_module_type, module=None):
     # Replicate PortMappings
     mappings = []
     for template in templates:
-        front_port = front_ports.get(template.front_port.resolve_name(module=module))
-        rear_port = rear_ports.get(template.rear_port.resolve_name(module=module))
+        front_port = front_ports.get(template.front_port.resolve_name(module=module, device=device))
+        rear_port = rear_ports.get(template.rear_port.resolve_name(module=module, device=device))
         mappings.append(
             PortMapping(
                 device_id=front_port.device_id,