Skip to content

Commit ced12c5

Browse files
committed
improve ACLInterfaceAssignmentForm clean method
1 parent 1861c56 commit ced12c5

File tree

1 file changed

+119
-79
lines changed

1 file changed

+119
-79
lines changed

netbox_acls/forms/models.py

Lines changed: 119 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -182,24 +182,24 @@ def clean(self):
182182
acl_type = cleaned_data.get("type")
183183

184184
# Check if more than one host type selected.
185-
host_types = self.get_host_types()
185+
host_types = self._get_host_types()
186186

187187
# Check if no hosts selected.
188-
self.validate_host_types(host_types)
188+
self._validate_host_types(host_types)
189189

190190
host_type, host = host_types[0]
191191

192192
# Check if duplicate entry.
193-
self.validate_duplicate_entry(name, host_type, host, error_message)
193+
self._validate_duplicate_entry(name, host_type, host, error_message)
194194
# Check if Access List has no existing rules before change the Access List's type.
195-
self.validate_acl_type_change(acl_type, error_message)
195+
self._validate_acl_type_change(acl_type, error_message)
196196

197197
if error_message:
198198
raise forms.ValidationError(error_message)
199199

200200
return cleaned_data
201201

202-
def get_host_types(self):
202+
def _get_host_types(self):
203203
"""
204204
Get host type assigned to the Access List.
205205
"""
@@ -213,7 +213,7 @@ def get_host_types(self):
213213
]
214214
return [x for x in host_types if x[1]]
215215

216-
def validate_host_types(self, host_types):
216+
def _validate_host_types(self, host_types):
217217
"""
218218
Check number of host types selected.
219219
"""
@@ -227,7 +227,7 @@ def validate_host_types(self, host_types):
227227
"Access Lists must be assigned to a device, virtual chassis or virtual machine.",
228228
)
229229

230-
def validate_duplicate_entry(self, name, host_type, host, error_message):
230+
def _validate_duplicate_entry(self, name, host_type, host, error_message):
231231
"""
232232
Check if duplicate entry. (Because of GFK.)
233233
"""
@@ -246,7 +246,7 @@ def validate_duplicate_entry(self, name, host_type, host, error_message):
246246
"name": [error_same_acl_name],
247247
}
248248

249-
def validate_acl_type_change(self, acl_type, error_message):
249+
def _validate_acl_type_change(self, acl_type, error_message):
250250
"""
251251
Check if Access List has no existing rules before change the Access List's type.
252252
"""
@@ -374,6 +374,7 @@ class Meta:
374374
),
375375
}
376376

377+
377378
def clean(self):
378379
"""
379380
Validates form inputs before submitting:
@@ -384,87 +385,126 @@ def clean(self):
384385
- Check for duplicate entry. (Because of GFK)
385386
- Check that the interface does not have an existing ACL applied in the direction already.
386387
"""
388+
# Call the parent class's `clean` method
387389
cleaned_data = super().clean()
388-
error_message = {}
389-
access_list = cleaned_data.get("access_list")
390-
direction = cleaned_data.get("direction")
391-
interface = cleaned_data.get("interface")
392-
vminterface = cleaned_data.get("vminterface")
393-
394-
# Check if both interface and vminterface are set.
395-
if interface and vminterface:
396-
error_too_many_interfaces = "Access Lists must be assigned to one type of interface at a time (VM interface or physical interface)"
397-
error_message |= {
398-
"interface": [error_too_many_interfaces],
399-
"vminterface": [error_too_many_interfaces],
400-
}
401-
elif not (interface or vminterface):
402-
error_no_interface = (
403-
"An Access List assignment but specify an Interface or VM Interface."
404-
)
405-
error_message |= {
406-
"interface": [error_no_interface],
407-
"vminterface": [error_no_interface],
408-
}
409-
else:
410-
if interface:
411-
assigned_object = interface
412-
assigned_object_type = "interface"
413-
host_type = "device"
390+
391+
# Get the interface types assigned to the Access List
392+
interface_types = self._get_interface_types()
393+
394+
# Initialize an error message variable
395+
error_message = self._validate_interface_types(interface_types)
396+
397+
if not error_message:
398+
assigned_object_type, assigned_object = interface_types[0]
399+
host_type = ("device" if assigned_object_type == "interface" else "virtual_machine")
400+
401+
# Get the parent host (device or virtual machine) of the assigned interface
402+
if assigned_object_type == "interface":
414403
host = Interface.objects.get(pk=assigned_object.pk).device
415404
assigned_object_id = Interface.objects.get(pk=assigned_object.pk).pk
416405
else:
417-
assigned_object = vminterface
418-
assigned_object_type = "vminterface"
419-
host_type = "virtual_machine"
420406
host = VMInterface.objects.get(pk=assigned_object.pk).virtual_machine
421407
assigned_object_id = VMInterface.objects.get(pk=assigned_object.pk).pk
422408

423-
assigned_object_type_id = ContentType.objects.get_for_model(
424-
assigned_object,
425-
).pk
426-
access_list_host = AccessList.objects.get(pk=access_list.pk).assigned_object
427-
428-
# Check that an interface's parent device/virtual_machine is assigned to the Access List.
429-
if access_list_host != host:
430-
error_acl_not_assigned_to_host = (
431-
"Access List not present on selected host."
432-
)
433-
error_message |= {
434-
"access_list": [error_acl_not_assigned_to_host],
435-
assigned_object_type: [error_acl_not_assigned_to_host],
436-
host_type: [error_acl_not_assigned_to_host],
437-
}
438-
# Check for duplicate entry.
439-
if ACLInterfaceAssignment.objects.filter(
440-
access_list=access_list,
441-
assigned_object_id=assigned_object_id,
442-
assigned_object_type=assigned_object_type_id,
443-
direction=direction,
444-
).exists():
445-
error_duplicate_entry = "An ACL with this name is already associated to this interface & direction."
446-
error_message |= {
447-
"access_list": [error_duplicate_entry],
448-
"direction": [error_duplicate_entry],
449-
assigned_object_type: [error_duplicate_entry],
450-
}
451-
# Check that the interface does not have an existing ACL applied in the direction already.
452-
if ACLInterfaceAssignment.objects.filter(
453-
assigned_object_id=assigned_object_id,
454-
assigned_object_type=assigned_object_type_id,
455-
direction=direction,
456-
).exists():
457-
error_interface_already_assigned = (
458-
"Interfaces can only have 1 Access List assigned in each direction."
459-
)
460-
error_message |= {
461-
"direction": [error_interface_already_assigned],
462-
assigned_object_type: [error_interface_already_assigned],
463-
}
409+
# Get the ContentType id for the assigned object
410+
assigned_object_type_id = ContentType.objects.get_for_model(assigned_object).pk
411+
412+
if not error_message:
413+
# Check if the parent host is assigned to the Access List
414+
error_message |= self._check_if_interface_parent_is_assigned_to_access_list(cleaned_data.get("access_list"), assigned_object_type, host_type, host)
415+
416+
if not error_message:
417+
# Check for duplicate entries in the Access List
418+
error_message |= self._check_for_duplicate_entry(cleaned_data.get("access_list"), assigned_object_id, assigned_object_type_id, cleaned_data.get("direction"),)
419+
420+
if not error_message:
421+
# Check if the interface already has an ACL applied in the specified direction
422+
error_message |= self._check_if_interface_already_has_acl_in_direction(assigned_object_id, assigned_object_type_id, cleaned_data.get("direction"))
464423

465424
if error_message:
466425
raise forms.ValidationError(error_message)
467-
return cleaned_data
426+
else:
427+
return cleaned_data
428+
429+
430+
def _get_interface_types(self):
431+
"""
432+
Get interface type/model assigned to the Access List.
433+
"""
434+
interface = self.cleaned_data.get("interface")
435+
vminterface = self.cleaned_data.get("vminterface")
436+
interface_types = [
437+
("interface", interface),
438+
("vminterface", vminterface),
439+
]
440+
return [x for x in interface_types if x[1]]
441+
442+
def _validate_interface_types(self, interface_types):
443+
"""
444+
Check if number of interface type selected is 1.
445+
"""
446+
# Check if more than 1 hosts selected.
447+
if len(interface_types) > 1:
448+
return "Assignment can only be to one interface at a time (either a interface or vm_interface)."
449+
# Check if no hosts selected.
450+
elif not interface_types:
451+
return "No interface or vm_interface selected."
452+
else:
453+
return {}
454+
455+
def _check_if_interface_parent_is_assigned_to_access_list(self, access_list, assigned_object_type, host_type, host):
456+
"""
457+
Check that an interface's parent device/virtual_machine is assigned to the Access List.
458+
"""
459+
460+
access_list_host = AccessList.objects.get(pk=access_list.pk).assigned_object
461+
462+
if access_list_host != host:
463+
ERROR_ACL_NOT_ASSIGNED_TO_HOST = (
464+
"Access List not present on selected host."
465+
)
466+
return {
467+
"access_list": [ERROR_ACL_NOT_ASSIGNED_TO_HOST],
468+
assigned_object_type: [ERROR_ACL_NOT_ASSIGNED_TO_HOST],
469+
host_type: [ERROR_ACL_NOT_ASSIGNED_TO_HOST],
470+
}
471+
else:
472+
return {}
473+
474+
def _check_for_duplicate_entry(self, access_list, assigned_object_id, assigned_object_type_id, direction):
475+
"""
476+
Check for duplicate entry. (Because of GFK)
477+
"""
478+
479+
if ACLInterfaceAssignment.objects.filter(
480+
access_list=access_list,
481+
assigned_object_id=assigned_object_id,
482+
assigned_object_type=assigned_object_type_id,
483+
direction=direction,
484+
).exists():
485+
return {"access_list": ["Duplicate entry."]}
486+
else:
487+
return {}
488+
489+
def _check_if_interface_already_has_acl_in_direction(self, assigned_object_id, assigned_object_type_id, direction):
490+
"""
491+
Check that the interface does not have an existing ACL applied in the direction already.
492+
"""
493+
if ACLInterfaceAssignment.objects.filter(
494+
assigned_object_id=assigned_object_id,
495+
assigned_object_type=assigned_object_type_id,
496+
direction=direction,
497+
).exists():
498+
error_interface_already_assigned = (
499+
"Interfaces can only have 1 Access List assigned in each direction."
500+
)
501+
return {
502+
"direction": [error_interface_already_assigned],
503+
assigned_object_type: [error_interface_already_assigned],
504+
}
505+
else:
506+
return {}
507+
468508

469509
def save(self, *args, **kwargs):
470510
"""

0 commit comments

Comments
 (0)