Fixes #15924: Fix API interface patch tagged all mode (#18759)

* Fixes: #15924 - Prevent API payload from allowing tagged_vlans while interface mode is set to taged-all

* Prevent cleanup of tagged_vlans when no tagged_vlans set on interface

* Fix test errors

* Remove accidental debug statements

* Update validation to model clean method instead of serializer

* Remove clearing of tagged vlans from `save()`

* Make changes to validation to account for M2M not being available under model in addition to not being able to check incoming vlans under same model.

* Optimize untagged vlan check

* Re-ordering statements in validators

* Forgot to call super().clean()

* Adjust logic for form and serializer.  Add tests

* Fix test failure

* Fix ruff errors

* Fix test by removing now invalid test

* Update serializer, form and tests

* Optimize API test for vlan fields

* Optimize API serializer logic

---------

Co-authored-by: Daniel Sheppard <dans@dansheps.com>
This commit is contained in:
Jeremy Stretch
2025-02-28 11:01:48 -05:00
committed by GitHub
parent 09d867adc3
commit 63a167f130
5 changed files with 292 additions and 15 deletions

View File

@@ -43,20 +43,14 @@ class InterfaceCommonForm(forms.Form):
super().clean()
parent_field = 'device' if 'device' in self.cleaned_data else 'virtual_machine'
tagged_vlans = self.cleaned_data.get('tagged_vlans')
# Untagged interfaces cannot be assigned tagged VLANs
if self.cleaned_data['mode'] == InterfaceModeChoices.MODE_ACCESS and tagged_vlans:
raise forms.ValidationError({
'mode': _("An access interface cannot have tagged VLANs assigned.")
})
# Remove all tagged VLAN assignments from "tagged all" interfaces
elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED_ALL:
self.cleaned_data['tagged_vlans'] = []
if 'tagged_vlans' in self.fields.keys():
tagged_vlans = self.cleaned_data.get('tagged_vlans') if self.is_bound else \
self.get_initial_for_field(self.fields['tagged_vlans'], 'tagged_vlans')
else:
tagged_vlans = []
# Validate tagged VLANs; must be a global VLAN or in the same site
elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED and tagged_vlans:
if self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED and tagged_vlans:
valid_sites = [None, self.cleaned_data[parent_field].site]
invalid_vlans = [str(v) for v in tagged_vlans if v.site not in valid_sites]