From 15fa8ff4a284b6a3eb9aa15cf2862c65409fc3e5 Mon Sep 17 00:00:00 2001 From: ryanmerolle Date: Mon, 6 Feb 2023 22:31:17 +0000 Subject: [PATCH] draft host logic model --- netbox_acls/models/access_lists.py | 20 ++++++++++++++++++++ netbox_acls/tests/test_models.py | 27 +++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/netbox_acls/models/access_lists.py b/netbox_acls/models/access_lists.py index e65f765..b26a04a 100644 --- a/netbox_acls/models/access_lists.py +++ b/netbox_acls/models/access_lists.py @@ -5,6 +5,7 @@ from dcim.models import Device, Interface, VirtualChassis from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import ValidationError from django.core.validators import RegexValidator from django.db import models from django.urls import reverse @@ -146,6 +147,25 @@ def get_absolute_url(self): args=[self.pk], ) + def clean(self): + super().clean() + + # A list of the possible host objects that an interface can be assigned to. + gfk_host_data = [self.assigned_object.device, self.assigned_object.virtual_machine] + + # Check to see if interface is assigned to a device or virtual machine. + interface_host = next( + (host_data for host_data in gfk_host_data if host_data is not None), + None, + ) + # Check if the assigned interface's host is the same as the host assigned to the access list. + if interface_host != self.access_list.assigned_object: + raise ValidationError( + { + "assigned_object": "The assigned object must be the same as the device assigned to it." + } + ) + @classmethod def get_prerequisite_models(cls): return [AccessList] diff --git a/netbox_acls/tests/test_models.py b/netbox_acls/tests/test_models.py index 76fd701..1bf3455 100644 --- a/netbox_acls/tests/test_models.py +++ b/netbox_acls/tests/test_models.py @@ -190,7 +190,7 @@ def test_valid_acl_choices(self): ) for default_action, acl_type in valid_acl_choices: - valid_acl_choice = AccessList( + invalid_acl_choice = AccessList( name=f"TestACL_Valid_Choice_{default_action}_{acl_type}", comments=f"VALID ACL CHOICES USED: {default_action=} {acl_type=}", type=acl_type, @@ -198,7 +198,9 @@ def test_valid_acl_choices(self): assigned_object_type=ContentType.objects.get_for_model(Device), assigned_object_id=1, # TODO - replace with Device.objects.first() ) - valid_acl_choice.full_clean() + + with self.assertRaises(ValidationError): + invalid_acl_choice.full_clean() def test_invalid_acl_choices(self): """ @@ -284,6 +286,27 @@ def test_acl_interface_assignment_success(self): ) acl_device_interface.full_clean() + def test_aclinterface_assignment_fail(self): + """ + Test that ACLInterfaceAssignment passes validation if the ACL is assigned to the host and not already assigned to the vminterface and direction. + """ + device_acl = AccessList( + name="STANDARD_ACL", + comments="STANDARD_ACL", + type="standard", + default_action="permit", + assigned_object_id=1, + assigned_object_type=ContentType.objects.get_for_model(Device), + ) + vm_acl.save() + acl_vm_interface = ACLInterfaceAssignment( + access_list=device_acl, + direction="ingress", + assigned_object_id=1, + assigned_object_type=ContentType.objects.get_for_model(VMInterface), + ) + acl_vm_interface.full_clean() + def test_acl_vminterface_assignment_success(self): """ Test that ACLInterfaceAssignment passes validation if the ACL is assigned to the host and not already assigned to the vminterface and direction.