Explorar o código

Fixes #2721: Detect loops when tracing front/rear ports

Jeremy Stretch %!s(int64=7) %!d(string=hai) anos
pai
achega
a3097d254e
Modificáronse 3 ficheiros con 20 adicións e 2 borrados
  1. 1 0
      CHANGELOG.md
  2. 5 0
      netbox/dcim/exceptions.py
  3. 14 2
      netbox/dcim/models.py

+ 1 - 0
CHANGELOG.md

@@ -14,6 +14,7 @@ v2.5.2 (FUTURE)
 * [#2707](https://github.com/digitalocean/netbox/issues/2707) - Correct permission evaluation for circuit termination cabling
 * [#2707](https://github.com/digitalocean/netbox/issues/2707) - Correct permission evaluation for circuit termination cabling
 * [#2712](https://github.com/digitalocean/netbox/issues/2712) - Preserve list filtering after editing objects in bulk
 * [#2712](https://github.com/digitalocean/netbox/issues/2712) - Preserve list filtering after editing objects in bulk
 * [#2717](https://github.com/digitalocean/netbox/issues/2717) - Fix bulk deletion of tags
 * [#2717](https://github.com/digitalocean/netbox/issues/2717) - Fix bulk deletion of tags
+* [#2721](https://github.com/digitalocean/netbox/issues/2721) - Detect loops when tracing front/rear ports
 * [#2723](https://github.com/digitalocean/netbox/issues/2723) - Correct permission evaluation when bulk deleting tags
 * [#2723](https://github.com/digitalocean/netbox/issues/2723) - Correct permission evaluation when bulk deleting tags
 
 
 ---
 ---

+ 5 - 0
netbox/dcim/exceptions.py

@@ -0,0 +1,5 @@
+class LoopDetected(Exception):
+    """
+    A loop has been detected while tracing a cable path.
+    """
+    pass

+ 14 - 2
netbox/dcim/models.py

@@ -21,6 +21,7 @@ from utilities.managers import NaturalOrderingManager
 from utilities.models import ChangeLoggedModel
 from utilities.models import ChangeLoggedModel
 from utilities.utils import serialize_object, to_meters
 from utilities.utils import serialize_object, to_meters
 from .constants import *
 from .constants import *
+from .exceptions import LoopDetected
 from .fields import ASNField, MACAddressField
 from .fields import ASNField, MACAddressField
 from .managers import DeviceComponentManager, InterfaceManager
 from .managers import DeviceComponentManager, InterfaceManager
 
 
@@ -88,7 +89,7 @@ class CableTermination(models.Model):
     class Meta:
     class Meta:
         abstract = True
         abstract = True
 
 
-    def trace(self, position=1, follow_circuits=False):
+    def trace(self, position=1, follow_circuits=False, cable_history=None):
         """
         """
         Return a list representing a complete cable path, with each individual segment represented as a three-tuple:
         Return a list representing a complete cable path, with each individual segment represented as a three-tuple:
             [
             [
@@ -133,6 +134,13 @@ class CableTermination(models.Model):
         if not self.cable:
         if not self.cable:
             return [(self, None, None)]
             return [(self, None, None)]
 
 
+        # Record cable history to detect loops
+        if cable_history is None:
+            cable_history = []
+        elif self.cable in cable_history:
+            raise LoopDetected()
+        cable_history.append(self.cable)
+
         far_end = self.cable.termination_b if self.cable.termination_a == self else self.cable.termination_a
         far_end = self.cable.termination_b if self.cable.termination_a == self else self.cable.termination_a
         path = [(self, self.cable, far_end)]
         path = [(self, self.cable, far_end)]
 
 
@@ -140,7 +148,11 @@ class CableTermination(models.Model):
         if peer_port is None:
         if peer_port is None:
             return path
             return path
 
 
-        next_segment = peer_port.trace(position, follow_circuits)
+        try:
+            next_segment = peer_port.trace(position, follow_circuits, cable_history)
+        except LoopDetected:
+            return path
+
         if next_segment is None:
         if next_segment is None:
             return path + [(peer_port, None, None)]
             return path + [(peer_port, None, None)]