Explorar el Código

Fixes #2777: Fix cable validation to handle duplicate connections on import

Jeremy Stretch hace 7 años
padre
commit
dd5f37391f
Se han modificado 2 ficheros con 50 adiciones y 46 borrados
  1. 1 0
      CHANGELOG.md
  2. 49 46
      netbox/dcim/models.py

+ 1 - 0
CHANGELOG.md

@@ -15,6 +15,7 @@ v2.5.3 (FUTURE)
 * [#2742](https://github.com/digitalocean/netbox/issues/2742) - Preserve cluster assignment when editing a device
 * [#2757](https://github.com/digitalocean/netbox/issues/2757) - Always treat first/last IPs within a /31 or /127 as usable
 * [#2762](https://github.com/digitalocean/netbox/issues/2762) - Add missing DCIM field values to API `_choices` endpoint
+* [#2777](https://github.com/digitalocean/netbox/issues/2777) - Fix cable validation to handle duplicate connections on import
 
 
 ---

+ 49 - 46
netbox/dcim/models.py

@@ -2558,52 +2558,55 @@ class Cable(ChangeLoggedModel):
 
     def clean(self):
 
-        # Check that termination types are compatible
-        type_a = self.termination_a_type.model
-        type_b = self.termination_b_type.model
-        if type_b not in COMPATIBLE_TERMINATION_TYPES.get(type_a):
-            raise ValidationError("Incompatible termination types: {} and {}".format(
-                self.termination_a_type, self.termination_b_type
-            ))
-
-        # A termination point cannot be connected to itself
-        if self.termination_a == self.termination_b:
-            raise ValidationError("Cannot connect {} to itself".format(self.termination_a_type))
-
-        # A front port cannot be connected to its corresponding rear port
-        if (
-            type_a in ['frontport', 'rearport'] and
-            type_b in ['frontport', 'rearport'] and
-            (
-                getattr(self.termination_a, 'rear_port', None) == self.termination_b or
-                getattr(self.termination_b, 'rear_port', None) == self.termination_a
-            )
-        ):
-            raise ValidationError("A front port cannot be connected to it corresponding rear port")
-
-        # Check for an existing Cable connected to either termination object
-        if self.termination_a.cable not in (None, self):
-            raise ValidationError("{} already has a cable attached (#{})".format(
-                self.termination_a, self.termination_a.cable_id
-            ))
-        if self.termination_b.cable not in (None, self):
-            raise ValidationError("{} already has a cable attached (#{})".format(
-                self.termination_b, self.termination_b.cable_id
-            ))
-
-        # Virtual interfaces cannot be connected
-        endpoint_a, endpoint_b, _ = self.get_path_endpoints()
-        if (
-            (
-                isinstance(endpoint_a, Interface) and
-                endpoint_a.form_factor == IFACE_FF_VIRTUAL
-            ) or
-            (
-                isinstance(endpoint_b, Interface) and
-                endpoint_b.form_factor == IFACE_FF_VIRTUAL
-            )
-        ):
-            raise ValidationError("Cannot connect to a virtual interface")
+        if self.termination_a and self.termination_b:
+
+            type_a = self.termination_a_type.model
+            type_b = self.termination_b_type.model
+
+            # Check that termination types are compatible
+            if type_b not in COMPATIBLE_TERMINATION_TYPES.get(type_a):
+                raise ValidationError("Incompatible termination types: {} and {}".format(
+                    self.termination_a_type, self.termination_b_type
+                ))
+
+            # A termination point cannot be connected to itself
+            if self.termination_a == self.termination_b:
+                raise ValidationError("Cannot connect {} to itself".format(self.termination_a_type))
+
+            # A front port cannot be connected to its corresponding rear port
+            if (
+                type_a in ['frontport', 'rearport'] and
+                type_b in ['frontport', 'rearport'] and
+                (
+                    getattr(self.termination_a, 'rear_port', None) == self.termination_b or
+                    getattr(self.termination_b, 'rear_port', None) == self.termination_a
+                )
+            ):
+                raise ValidationError("A front port cannot be connected to it corresponding rear port")
+
+            # Check for an existing Cable connected to either termination object
+            if self.termination_a.cable not in (None, self):
+                raise ValidationError("{} already has a cable attached (#{})".format(
+                    self.termination_a, self.termination_a.cable_id
+                ))
+            if self.termination_b.cable not in (None, self):
+                raise ValidationError("{} already has a cable attached (#{})".format(
+                    self.termination_b, self.termination_b.cable_id
+                ))
+
+            # Virtual interfaces cannot be connected
+            endpoint_a, endpoint_b, _ = self.get_path_endpoints()
+            if (
+                (
+                    isinstance(endpoint_a, Interface) and
+                    endpoint_a.form_factor == IFACE_FF_VIRTUAL
+                ) or
+                (
+                    isinstance(endpoint_b, Interface) and
+                    endpoint_b.form_factor == IFACE_FF_VIRTUAL
+                )
+            ):
+                raise ValidationError("Cannot connect to a virtual interface")
 
         # Validate length and length_unit
         if self.length is not None and self.length_unit is None: