Ensure cable paths are retraced when port mappings are changes via form
Some checks failed
CI / build (20.x, 3.12) (push) Has been cancelled
CI / build (20.x, 3.13) (push) Has been cancelled

This commit is contained in:
Jeremy Stretch
2025-12-01 13:35:14 -05:00
parent 9198a0490a
commit 619728a048
3 changed files with 26 additions and 14 deletions

View File

@@ -1,6 +1,8 @@
from django import forms from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import connection
from django.db.models.signals import post_save
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from dcim.constants import LOCATION_SCOPE_TYPES from dcim.constants import LOCATION_SCOPE_TYPES
@@ -191,3 +193,13 @@ class FrontPortFormMixin(forms.Form):
}) })
) )
self.port_mapping_model.objects.bulk_create(mappings) self.port_mapping_model.objects.bulk_create(mappings)
# Send post_save signals
for mapping in mappings:
post_save.send(
sender=PortMapping,
instance=mapping,
created=True,
raw=False,
using=connection,
update_fields=None
)

View File

@@ -31,7 +31,7 @@ __all__ = (
'CableTermination', 'CableTermination',
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(f'netbox.{__name__}')
trace_paths = Signal() trace_paths = Signal()

View File

@@ -1,5 +1,6 @@
import logging import logging
from django.db.models import Q
from django.db.models.signals import post_save, post_delete from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver from django.dispatch import receiver
@@ -7,7 +8,7 @@ from dcim.choices import CableEndChoices, LinkStatusChoices
from virtualization.models import VMInterface from virtualization.models import VMInterface
from .models import ( from .models import (
Cable, CablePath, CableTermination, ConsolePort, ConsoleServerPort, Device, DeviceBay, FrontPort, Interface, Cable, CablePath, CableTermination, ConsolePort, ConsoleServerPort, Device, DeviceBay, FrontPort, Interface,
InventoryItem, ModuleBay, PathEndpoint, PowerOutlet, PowerPanel, PowerPort, Rack, RearPort, Location, InventoryItem, ModuleBay, PathEndpoint, PortMapping, PowerOutlet, PowerPanel, PowerPort, Rack, RearPort, Location,
VirtualChassis, VirtualChassis,
) )
from .models.cables import trace_paths from .models.cables import trace_paths
@@ -135,6 +136,17 @@ def retrace_cable_paths(instance, **kwargs):
cablepath.retrace() cablepath.retrace()
@receiver((post_delete, post_save), sender=PortMapping)
def update_passthrough_port_paths(instance, **kwargs):
"""
When a PortMapping is created or deleted, retrace any CablePaths which traverse its front and/or rear ports.
"""
for cablepath in CablePath.objects.filter(
Q(_nodes__contains=instance.front_port) | Q(_nodes__contains=instance.rear_port)
):
cablepath.retrace()
@receiver(post_delete, sender=CableTermination) @receiver(post_delete, sender=CableTermination)
def nullify_connected_endpoints(instance, **kwargs): def nullify_connected_endpoints(instance, **kwargs):
""" """
@@ -150,18 +162,6 @@ def nullify_connected_endpoints(instance, **kwargs):
cablepath.retrace() cablepath.retrace()
# TODO: Adapt signal handler to act on changes to port mappings
@receiver(post_save, sender=FrontPort)
def extend_rearport_cable_paths(instance, created, raw, **kwargs):
"""
When a new FrontPort is created, add it to any CablePaths which end at its corresponding RearPort.
"""
if created and not raw:
for mapping in instance.mappings.prefetch_related('rear_port'):
for cablepath in CablePath.objects.filter(_nodes__contains=mapping.rear_port):
cablepath.retrace()
@receiver(post_save, sender=Interface) @receiver(post_save, sender=Interface)
@receiver(post_save, sender=VMInterface) @receiver(post_save, sender=VMInterface)
def update_mac_address_interface(instance, created, raw, **kwargs): def update_mac_address_interface(instance, created, raw, **kwargs):