Browse Source

Record wireless links as part of cable path

jeremystretch 4 years ago
parent
commit
138af27bf7

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

@@ -379,7 +379,7 @@ class CablePath(BigIDModel):
         """
         """
         from circuits.models import CircuitTermination
         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
             return None
 
 
         destination = None
         destination = None
@@ -389,12 +389,12 @@ class CablePath(BigIDModel):
         is_split = False
         is_split = False
 
 
         node = origin
         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
                 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()
             peer_termination = node.get_cable_peer()
 
 
             # Follow a FrontPort to its corresponding RearPort
             # 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):
     def parent_object(self):
         raise NotImplementedError("CableTermination models must implement parent_object()")
         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):
 class PathEndpoint(models.Model):
     """
     """
@@ -657,6 +664,10 @@ class Interface(ComponentModel, BaseInterface, CableTermination, PathEndpoint):
     def is_lag(self):
     def is_lag(self):
         return self.type == InterfaceTypeChoices.TYPE_LAG
         return self.type == InterfaceTypeChoices.TYPE_LAG
 
 
+    @property
+    def link(self):
+        return self.cable or self.wireless_link
+
 
 
 #
 #
 # Pass-through ports
 # Pass-through ports

+ 1 - 27
netbox/dcim/signals.py

@@ -2,37 +2,11 @@ import logging
 
 
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 from django.db.models.signals import post_save, post_delete, pre_delete
 from django.db.models.signals import post_save, post_delete, pre_delete
-from django.db import transaction
 from django.dispatch import receiver
 from django.dispatch import receiver
 
 
 from .choices import CableStatusChoices
 from .choices import CableStatusChoices
 from .models import Cable, CablePath, Device, PathEndpoint, PowerPanel, Rack, Location, VirtualChassis
 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.contrib.contenttypes.models import ContentType
+from django.db import transaction
 
 
 
 
 def compile_path_node(ct_id, object_id):
 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_id, object_id = decompile_path_node(repr)
     ct = ContentType.objects.get_for_id(ct_id)
     ct = ContentType.objects.get_for_id(ct_id)
     return ct.model_class().objects.get(pk=object_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.db.models.signals import post_save, post_delete
 from django.dispatch import receiver
 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
 from .models import WirelessLink
 
 
 
 
@@ -12,11 +13,10 @@ from .models import WirelessLink
 #
 #
 
 
 @receiver(post_save, sender=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.
     When a WirelessLink is saved, save a reference to it on each connected interface.
     """
     """
-    print('update_connected_interfaces')
     logger = logging.getLogger('netbox.wireless.wirelesslink')
     logger = logging.getLogger('netbox.wireless.wirelesslink')
     if raw:
     if raw:
         logger.debug(f"Skipping endpoint updates for imported wireless link {instance}")
         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:
     if instance.interface_a.wireless_link != instance:
         logger.debug(f"Updating interface A for wireless link {instance}")
         logger.debug(f"Updating interface A for wireless link {instance}")
         instance.interface_a.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()
         instance.interface_a.save()
     if instance.interface_b.cable != instance:
     if instance.interface_b.cable != instance:
         logger.debug(f"Updating interface B for wireless link {instance}")
         logger.debug(f"Updating interface B for wireless link {instance}")
         instance.interface_b.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()
         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)
 @receiver(post_delete, sender=WirelessLink)
 def nullify_connected_interfaces(instance, **kwargs):
 def nullify_connected_interfaces(instance, **kwargs):
     """
     """
     When a WirelessLink is deleted, update its two connected Interfaces
     When a WirelessLink is deleted, update its two connected Interfaces
     """
     """
-    print('nullify_connected_interfaces')
     logger = logging.getLogger('netbox.wireless.wirelesslink')
     logger = logging.getLogger('netbox.wireless.wirelesslink')
 
 
     if instance.interface_a is not None:
     if instance.interface_a is not None:
@@ -56,3 +60,8 @@ def nullify_connected_interfaces(instance, **kwargs):
             _cable_peer_type=None,
             _cable_peer_type=None,
             _cable_peer_id=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()