Просмотр исходного кода

Record wireless links as part of cable path

jeremystretch 4 лет назад
Родитель
Сommit
138af27bf7

+ 5 - 5
netbox/dcim/models/cables.py

@@ -379,7 +379,7 @@ class CablePath(BigIDModel):
         """
         from circuits.models import CircuitTermination
 
-        if origin is None or origin.cable is None:
+        if origin is None or origin.link is None:
             return None
 
         destination = None
@@ -389,12 +389,12 @@ class CablePath(BigIDModel):
         is_split = False
 
         node = origin
-        while node.cable is not None:
-            if node.cable.status != CableStatusChoices.STATUS_CONNECTED:
+        while node.link is not None:
+            if hasattr(node.link, 'status') and node.link.status != CableStatusChoices.STATUS_CONNECTED:
                 is_active = False
 
-            # Follow the cable to its far-end termination
-            path.append(object_to_path_node(node.cable))
+            # Follow the link to its far-end termination
+            path.append(object_to_path_node(node.link))
             peer_termination = node.get_cable_peer()
 
             # Follow a FrontPort to its corresponding RearPort

+ 11 - 0
netbox/dcim/models/device_components.py

@@ -157,6 +157,13 @@ class CableTermination(models.Model):
     def parent_object(self):
         raise NotImplementedError("CableTermination models must implement parent_object()")
 
+    @property
+    def link(self):
+        """
+        Generic wrapper for a Cable, WirelessLink, or some other relation to a connected termination.
+        """
+        return self.cable
+
 
 class PathEndpoint(models.Model):
     """
@@ -657,6 +664,10 @@ class Interface(ComponentModel, BaseInterface, CableTermination, PathEndpoint):
     def is_lag(self):
         return self.type == InterfaceTypeChoices.TYPE_LAG
 
+    @property
+    def link(self):
+        return self.cable or self.wireless_link
+
 
 #
 # Pass-through ports

+ 1 - 27
netbox/dcim/signals.py

@@ -2,37 +2,11 @@ import logging
 
 from django.contrib.contenttypes.models import ContentType
 from django.db.models.signals import post_save, post_delete, pre_delete
-from django.db import transaction
 from django.dispatch import receiver
 
 from .choices import CableStatusChoices
 from .models import Cable, CablePath, Device, PathEndpoint, PowerPanel, Rack, Location, VirtualChassis
-
-
-def create_cablepath(node):
-    """
-    Create CablePaths for all paths originating from the specified node.
-    """
-    cp = CablePath.from_origin(node)
-    if cp:
-        try:
-            cp.save()
-        except Exception as e:
-            print(node, node.pk)
-            raise e
-
-
-def rebuild_paths(obj):
-    """
-    Rebuild all CablePaths which traverse the specified node
-    """
-    cable_paths = CablePath.objects.filter(path__contains=obj)
-
-    with transaction.atomic():
-        for cp in cable_paths:
-            cp.delete()
-            if cp.origin:
-                create_cablepath(cp.origin)
+from .utils import create_cablepath, rebuild_paths
 
 
 #

+ 27 - 0
netbox/dcim/utils.py

@@ -1,4 +1,5 @@
 from django.contrib.contenttypes.models import ContentType
+from django.db import transaction
 
 
 def compile_path_node(ct_id, object_id):
@@ -26,3 +27,29 @@ def path_node_to_object(repr):
     ct_id, object_id = decompile_path_node(repr)
     ct = ContentType.objects.get_for_id(ct_id)
     return ct.model_class().objects.get(pk=object_id)
+
+
+def create_cablepath(node):
+    """
+    Create CablePaths for all paths originating from the specified node.
+    """
+    from dcim.models import CablePath
+
+    cp = CablePath.from_origin(node)
+    if cp:
+        cp.save()
+
+
+def rebuild_paths(obj):
+    """
+    Rebuild all CablePaths which traverse the specified node
+    """
+    from dcim.models import CablePath
+
+    cable_paths = CablePath.objects.filter(path__contains=obj)
+
+    with transaction.atomic():
+        for cp in cable_paths:
+            cp.delete()
+            if cp.origin:
+                create_cablepath(cp.origin)

+ 15 - 6
netbox/wireless/signals.py

@@ -3,7 +3,8 @@ import logging
 from django.db.models.signals import post_save, post_delete
 from django.dispatch import receiver
 
-from dcim.models import Interface
+from dcim.models import CablePath, Interface
+from dcim.utils import create_cablepath
 from .models import WirelessLink
 
 
@@ -12,11 +13,10 @@ from .models import WirelessLink
 #
 
 @receiver(post_save, sender=WirelessLink)
-def update_connected_interfaces(instance, raw=False, **kwargs):
+def update_connected_interfaces(instance, created, raw=False, **kwargs):
     """
     When a WirelessLink is saved, save a reference to it on each connected interface.
     """
-    print('update_connected_interfaces')
     logger = logging.getLogger('netbox.wireless.wirelesslink')
     if raw:
         logger.debug(f"Skipping endpoint updates for imported wireless link {instance}")
@@ -25,21 +25,25 @@ def update_connected_interfaces(instance, raw=False, **kwargs):
     if instance.interface_a.wireless_link != instance:
         logger.debug(f"Updating interface A for wireless link {instance}")
         instance.interface_a.wireless_link = instance
-        # instance.interface_a._cable_peer = instance.interface_b  # TODO: Rename _cable_peer field
+        instance.interface_a._cable_peer = instance.interface_b  # TODO: Rename _cable_peer field
         instance.interface_a.save()
     if instance.interface_b.cable != instance:
         logger.debug(f"Updating interface B for wireless link {instance}")
         instance.interface_b.wireless_link = instance
-        # instance.interface_b._cable_peer = instance.interface_a
+        instance.interface_b._cable_peer = instance.interface_a
         instance.interface_b.save()
 
+    # Create/update cable paths
+    if created:
+        for interface in (instance.interface_a, instance.interface_b):
+            create_cablepath(interface)
+
 
 @receiver(post_delete, sender=WirelessLink)
 def nullify_connected_interfaces(instance, **kwargs):
     """
     When a WirelessLink is deleted, update its two connected Interfaces
     """
-    print('nullify_connected_interfaces')
     logger = logging.getLogger('netbox.wireless.wirelesslink')
 
     if instance.interface_a is not None:
@@ -56,3 +60,8 @@ def nullify_connected_interfaces(instance, **kwargs):
             _cable_peer_type=None,
             _cable_peer_id=None
         )
+
+    # Delete and retrace any dependent cable paths
+    for cablepath in CablePath.objects.filter(path__contains=instance):
+        print(f'Deleting cable path {cablepath.pk}')
+        cablepath.delete()