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

Fixes #3269: Raise validation error when specifying non-existent cable terminationss

Jeremy Stretch 6 лет назад
Родитель
Сommit
3fdb655a92
2 измененных файлов с 64 добавлено и 49 удалено
  1. 1 0
      CHANGELOG.md
  2. 63 49
      netbox/dcim/models.py

+ 1 - 0
CHANGELOG.md

@@ -8,6 +8,7 @@ v2.6.1 (FUTURE)
 ## Bug Fixes
 
 * [#3229](https://github.com/digitalocean/netbox/issues/3229) - Limit rack group selection by parent site on racks list
+* [#3269](https://github.com/digitalocean/netbox/issues/3269) - Raise validation error when specifying non-existent cable terminations
 * [#3275](https://github.com/digitalocean/netbox/issues/3275) - Fix error when adding power outlets to a device type
 * [#3279](https://github.com/digitalocean/netbox/issues/3279) - Reset the PostgreSQL sequence for Tag and TaggedItem IDs
 * [#3283](https://github.com/digitalocean/netbox/issues/3283) - Fix rack group assignment on PowerFeed CSV import

+ 63 - 49
netbox/dcim/models.py

@@ -2747,55 +2747,69 @@ class Cable(ChangeLoggedModel):
 
     def clean(self):
 
-        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.type == IFACE_TYPE_VIRTUAL
-                ) or
-                (
-                    isinstance(endpoint_b, Interface) and
-                    endpoint_b.type == IFACE_TYPE_VIRTUAL
-                )
-            ):
-                raise ValidationError("Cannot connect to a virtual interface")
+        # Validate that termination A exists
+        try:
+            self.termination_a_type.model_class().objects.get(pk=self.termination_a_id)
+        except ObjectDoesNotExist:
+            raise ValidationError({
+                'termination_a': 'Invalid ID for type {}'.format(self.termination_a_type)
+            })
+
+        # Validate that termination B exists
+        try:
+            self.termination_b_type.model_class().objects.get(pk=self.termination_b_id)
+        except ObjectDoesNotExist:
+            raise ValidationError({
+                'termination_b': 'Invalid ID for type {}'.format(self.termination_b_type)
+            })
+
+        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.type == IFACE_TYPE_VIRTUAL
+            ) or
+            (
+                isinstance(endpoint_b, Interface) and
+                endpoint_b.type == IFACE_TYPE_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: