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
This commit is contained in:
Martin Hauser 2026-07-20 19:46:26 +02:00 committed by GitHub
parent 15d2cc35e0
commit d857c145c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 71 additions and 4 deletions

View File

@ -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):

View File

@ -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,