From fc9871fba3af578197576a141a6830596fdc0d78 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 1 Mar 2018 11:57:04 -0500 Subject: [PATCH] Fixes #1935: Correct API validation of VLANs assigned to interfaces --- netbox/dcim/api/serializers.py | 21 +++++++++++++-------- netbox/utilities/api.py | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index edcd93ef247..ea87c409803 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -731,15 +731,20 @@ class Meta: def validate(self, 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') + # All associated VLANs be global or assigned to the parent device's site. + device = self.instance.device if self.instance else data.get('device') + untagged_vlan = data.get('untagged_vlan') + if untagged_vlan and untagged_vlan.site not in [device.site, None]: + raise serializers.ValidationError({ + 'untagged_vlan': "VLAN {} must belong to the same site as the interface's parent device, or it must be " + "global.".format(untagged_vlan) + }) 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) - ) + if vlan.site not in [device.site, None]: + raise serializers.ValidationError({ + 'tagged_vlans': "VLAN {} must belong to the same site as the interface's parent device, or it must " + "be global.".format(vlan) + }) return super(WritableInterfaceSerializer, self).validate(data) diff --git a/netbox/utilities/api.py b/netbox/utilities/api.py index 8471d0e00c7..5c78dacc4c9 100644 --- a/netbox/utilities/api.py +++ b/netbox/utilities/api.py @@ -55,7 +55,7 @@ def validate(self, data): model = self.Meta.model # Ignore ManyToManyFields for new instances (a PK is needed for validation) for field in model._meta.get_fields(): - if isinstance(field, ManyToManyField): + if isinstance(field, ManyToManyField) and field.name in attrs: attrs.pop(field.name) instance = self.Meta.model(**attrs) else: