Browse Source

Fixed up validation of Interface VLAN assignments

Jeremy Stretch 7 years ago
parent
commit
04ba57cb38
3 changed files with 18 additions and 31 deletions
  1. 11 26
      netbox/dcim/api/serializers.py
  2. 7 0
      netbox/dcim/models.py
  3. 0 5
      netbox/utilities/api.py

+ 11 - 26
netbox/dcim/api/serializers.py

@@ -699,35 +699,20 @@ class WritableInterfaceSerializer(ValidatedModelSerializer):
             'id', 'device', 'name', 'form_factor', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only', 'description',
             'mode', 'untagged_vlan', 'tagged_vlans',
         ]
-        ignore_validation_fields = [
-            'tagged_vlans'
-        ]
 
     def validate(self, data):
 
-        # Get the device for later use
-        if self.instance:
-            device = self.instance.device
-        else:
-            device = data.get('device')
-
-        # Validate VLANs belong to the device's site or global
-        # We have to do this here decause of the ManyToMany relationship
-        native_vlan = data.get('native_vlan')
-        if native_vlan:
-            if native_vlan.site != device.site and native_vlan.site is not None:
-                raise serializers.ValidationError("Native VLAN is invalid for the interface's device.")
-
-        tagged_vlan_members = data.get('tagged_vlan_members')
-        if tagged_vlan_members:
-            for vlan in tagged_vlan_members:
-                if vlan.site != device.site and vlan.site is not None:
-                    raise serializers.ValidationError("Tagged VLAN {} is invalid for the interface's device.".format(vlan))
-
-        # Enforce model validation
-        super(WritableInterfaceSerializer, self).validate(data)
-
-        return data
+        # Validate that all untagged VLANs either belong to the same site as the Interface's parent Deivce or
+        # VirtualMachine, or are global.
+        parent = self.instance.parent if self.instance else data.get('device') or data.get('virtual_machine')
+        for vlan in data.get('tagged_vlans', []):
+            if vlan.site not in [parent, None]:
+                raise serializers.ValidationError(
+                    "Tagged VLAN {} must belong to the same site as the interface's parent device/VM, or it must be "
+                    "global".format(vlan)
+                )
+
+        return super(WritableInterfaceSerializer, self).validate(data)
 
 
 #

+ 7 - 0
netbox/dcim/models.py

@@ -1318,6 +1318,13 @@ class Interface(models.Model):
                 )
             })
 
+        # Validate untagged VLAN
+        if self.untagged_vlan and self.untagged_vlan.site not in [self.parent.site, None]:
+            raise ValidationError({
+                'untagged_vlan': "The untagged VLAN ({}) must belong to the same site as the interface's parent "
+                                 "device/VM, or it must be global".format(self.untagged_vlan)
+            })
+
     @property
     def parent(self):
         return self.device or self.virtual_machine

+ 0 - 5
netbox/utilities/api.py

@@ -48,11 +48,6 @@ class ValidatedModelSerializer(ModelSerializer):
         attrs = data.copy()
         attrs.pop('custom_fields', None)
 
-        # remove any fields marked for no validation
-        ignore_validation_fields = getattr(self.Meta, 'ignore_validation_fields', [])
-        for field in ignore_validation_fields:
-            attrs.pop(field)
-
         # Run clean() on an instance of the model
         if self.instance is None:
             instance = self.Meta.model(**attrs)