diff --git a/netbox_acls/forms/models.py b/netbox_acls/forms/models.py
index db01f4d..c02640f 100644
--- a/netbox_acls/forms/models.py
+++ b/netbox_acls/forms/models.py
@@ -14,7 +14,13 @@ from utilities.forms import (
DynamicModelChoiceField,
DynamicModelMultipleChoiceField,
)
-from virtualization.models import VirtualMachine, VMInterface
+from virtualization.models import (
+ Cluster,
+ ClusterGroup,
+ ClusterType,
+ VirtualMachine,
+ VMInterface,
+)
from ..choices import ACLTypeChoices
from ..models import (
@@ -60,6 +66,7 @@ class AccessListForm(NetBoxModelForm):
Requires a device, a name, a type, and a default_action.
"""
+ # Device selector
region = DynamicModelChoiceField(
queryset=Region.objects.all(),
required=False,
@@ -86,16 +93,48 @@ class AccessListForm(NetBoxModelForm):
"site_id": "$site",
},
)
+
+ # Virtual Chassis selector
virtual_chassis = DynamicModelChoiceField(
queryset=VirtualChassis.objects.all(),
required=False,
label="Virtual Chassis",
)
+
+ # Virtual Machine selector
+ cluster_type = DynamicModelChoiceField(
+ queryset=ClusterType.objects.all(),
+ required=False,
+ )
+
+ cluster_group = DynamicModelChoiceField(
+ queryset=ClusterGroup.objects.all(),
+ required=False,
+ query_params={
+ "type_id": "$cluster_type",
+ },
+ )
+
+ cluster = DynamicModelChoiceField(
+ queryset=Cluster.objects.all(),
+ required=False,
+ query_params={
+ "type_id": "$cluster_type",
+ "group_id": "$cluster_group",
+ },
+ )
+
virtual_machine = DynamicModelChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
label="Virtual Machine",
+ query_params={
+ "cluster_type_id": "$cluster_type",
+ "cluster_group_id": "$cluster_group",
+ "cluster_id": "$cluster",
+ },
)
+
comments = CommentField()
class Meta:
diff --git a/netbox_acls/migrations/0002_alter_accesslist_options_and_more.py b/netbox_acls/migrations/0002_alter_accesslist_options_and_more.py
new file mode 100644
index 0000000..da0d912
--- /dev/null
+++ b/netbox_acls/migrations/0002_alter_accesslist_options_and_more.py
@@ -0,0 +1,94 @@
+# Generated by Django 4.0.8 on 2023-01-21 09:00
+
+import django.core.validators
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('contenttypes', '0002_remove_content_type_name'),
+ ('netbox_acls', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='accesslist',
+ options={'ordering': ['assigned_object_type', 'assigned_object_id', 'name'], 'verbose_name': 'Access List', 'verbose_name_plural': 'Access Lists'},
+ ),
+ migrations.AlterModelOptions(
+ name='aclextendedrule',
+ options={'ordering': ['access_list', 'index'], 'verbose_name': 'ACL Extended Rule', 'verbose_name_plural': 'ACL Extended Rules'},
+ ),
+ migrations.AlterModelOptions(
+ name='aclinterfaceassignment',
+ options={'ordering': ['assigned_object_type', 'assigned_object_id', 'access_list', 'direction'], 'verbose_name': 'ACL Interface Assignment', 'verbose_name_plural': 'ACL Interface Assignments'},
+ ),
+ migrations.AlterModelOptions(
+ name='aclstandardrule',
+ options={'ordering': ['access_list', 'index'], 'verbose_name': 'ACL Standard Rule', 'verbose_name_plural': 'ACL Standard Rules'},
+ ),
+ migrations.AlterField(
+ model_name='accesslist',
+ name='assigned_object_id',
+ field=models.PositiveBigIntegerField(),
+ ),
+ migrations.AlterField(
+ model_name='accesslist',
+ name='assigned_object_type',
+ field=models.ForeignKey(limit_choices_to=models.Q(models.Q(models.Q(('app_label', 'dcim'), ('model', 'device')), models.Q(('app_label', 'dcim'), ('model', 'virtualchassis')), models.Q(('app_label', 'virtualization'), ('model', 'virtualmachine')), _connector='OR')), on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'),
+ ),
+ migrations.AlterField(
+ model_name='accesslist',
+ name='name',
+ field=models.CharField(max_length=500, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z,-,_]*$', 'Only alphanumeric, hyphens, and underscores characters are allowed.')]),
+ ),
+ migrations.AlterField(
+ model_name='accesslist',
+ name='type',
+ field=models.CharField(max_length=30),
+ ),
+ migrations.AlterField(
+ model_name='aclextendedrule',
+ name='access_list',
+ field=models.ForeignKey(limit_choices_to={'type': 'extended'}, on_delete=django.db.models.deletion.CASCADE, related_name='aclextendedrules', to='netbox_acls.accesslist'),
+ ),
+ migrations.AlterField(
+ model_name='aclextendedrule',
+ name='remark',
+ field=models.CharField(blank=True, default='', max_length=500),
+ preserve_default=False,
+ ),
+ migrations.AlterField(
+ model_name='aclinterfaceassignment',
+ name='access_list',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='netbox_acls.accesslist'),
+ ),
+ migrations.AlterField(
+ model_name='aclinterfaceassignment',
+ name='assigned_object_id',
+ field=models.PositiveBigIntegerField(),
+ ),
+ migrations.AlterField(
+ model_name='aclinterfaceassignment',
+ name='assigned_object_type',
+ field=models.ForeignKey(limit_choices_to=models.Q(models.Q(models.Q(('app_label', 'dcim'), ('model', 'interface')), models.Q(('app_label', 'virtualization'), ('model', 'vminterface')), _connector='OR')), on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'),
+ ),
+ migrations.AlterField(
+ model_name='aclinterfaceassignment',
+ name='direction',
+ field=models.CharField(max_length=30),
+ ),
+ migrations.AlterField(
+ model_name='aclstandardrule',
+ name='access_list',
+ field=models.ForeignKey(limit_choices_to={'type': 'standard'}, on_delete=django.db.models.deletion.CASCADE, related_name='aclstandardrules', to='netbox_acls.accesslist'),
+ ),
+ migrations.AlterField(
+ model_name='aclstandardrule',
+ name='remark',
+ field=models.CharField(blank=True, default='', max_length=500),
+ preserve_default=False,
+ ),
+ ]
diff --git a/netbox_acls/models/access_list_rules.py b/netbox_acls/models/access_list_rules.py
index 8b21dde..5656720 100644
--- a/netbox_acls/models/access_list_rules.py
+++ b/netbox_acls/models/access_list_rules.py
@@ -52,6 +52,8 @@ class ACLRule(NetBoxModel):
verbose_name="Source Prefix",
)
+ clone_fields = ("access_list", "action", "source_prefix")
+
def __str__(self):
return f"{self.access_list}: Rule {self.index}"
diff --git a/netbox_acls/models/access_lists.py b/netbox_acls/models/access_lists.py
index 729e024..1feb635 100644
--- a/netbox_acls/models/access_lists.py
+++ b/netbox_acls/models/access_lists.py
@@ -59,6 +59,11 @@ class AccessList(NetBoxModel):
blank=True,
)
+ clone_fields = (
+ "type",
+ "default_action",
+ )
+
class Meta:
unique_together = ["assigned_object_type", "assigned_object_id", "name"]
ordering = ["assigned_object_type", "assigned_object_id", "name"]
@@ -113,6 +118,8 @@ class ACLInterfaceAssignment(NetBoxModel):
blank=True,
)
+ clone_fields = ("access_list", "direction")
+
class Meta:
unique_together = [
"assigned_object_type",
diff --git a/netbox_acls/templates/netbox_acls/accesslist.html b/netbox_acls/templates/netbox_acls/accesslist.html
index b2e11c1..5821402 100644
--- a/netbox_acls/templates/netbox_acls/accesslist.html
+++ b/netbox_acls/templates/netbox_acls/accesslist.html
@@ -1,90 +1,63 @@
{% extends 'generic/object.html' %}
{% load render_table from django_tables2 %}
-{% block breadcrumbs %}
-
Access Lists
-{% endblock %}
-{% block controls %}
-
-{% endblock controls %}
-{% block tabs %}
-
-{% endblock tabs %}
+{% endblock extra_controls %}
{% block content %}
-
-
-
-
-
-
-
- | Type |
- {{ object.get_type_display }} |
-
-
- | Default Action |
- {% badge object.get_default_action_display bg_color=object.get_default_action_color %} |
-
-
- | Rules |
- {% if object.type == 'standard' %}
- {{ object.aclstandardrules.count|placeholder }} |
- {% elif object.type == 'extended' %}
- {{ object.aclextendedrules.count|placeholder }} |
- {% endif %}
-
-
- | Assigned Host |
- {{ object.assigned_object|linkify }} |
-
-
+
+
+
+
+
+
+
+ | Type |
+ {{ object.get_type_display }} |
+
+
+ | Default Action |
+ {% badge object.get_default_action_display bg_color=object.get_default_action_color %} |
+
+
+ | Rules |
+ {% if object.type == 'standard' %}
+ {{ object.aclstandardrules.count|placeholder }} |
+ {% elif object.type == 'extended' %}
+ {{ object.aclextendedrules.count|placeholder }} |
+ {% endif %}
+
+
+ | Assigned Host |
+ {{ object.assigned_object|linkify }} |
+
+
+
+
+ {% include 'inc/panels/custom_fields.html' %}
-
- {% include 'inc/panels/custom_fields.html' %}
-
-
- {% include 'inc/panels/tags.html' %}
- {% include 'inc/panels/comments.html' %}
-
-
-
-
-
-
-
- {% render_table rules_table %}
+
+ {% include 'inc/panels/tags.html' %}
+ {% include 'inc/panels/comments.html' %}
+
+
+
+
+
+
+
+ {% render_table rules_table %}
+
+
-
-
{% endblock content %}
diff --git a/netbox_acls/templates/netbox_acls/accesslist_edit.html b/netbox_acls/templates/netbox_acls/accesslist_edit.html
index 64b46cb..a197daa 100644
--- a/netbox_acls/templates/netbox_acls/accesslist_edit.html
+++ b/netbox_acls/templates/netbox_acls/accesslist_edit.html
@@ -67,6 +67,9 @@
{% render_field form.virtual_chassis %}
+ {% render_field form.cluster_type %}
+ {% render_field form.cluster_group %}
+ {% render_field form.cluster %}
{% render_field form.virtual_machine %}
diff --git a/netbox_acls/templates/netbox_acls/aclinterfaceassignment.html b/netbox_acls/templates/netbox_acls/aclinterfaceassignment.html
index b46a26a..4cabeb0 100644
--- a/netbox_acls/templates/netbox_acls/aclinterfaceassignment.html
+++ b/netbox_acls/templates/netbox_acls/aclinterfaceassignment.html
@@ -1,38 +1,6 @@
{% extends 'generic/object.html' %}
{% load render_table from django_tables2 %}
-{% block breadcrumbs %}
-
ACL Interface Assignments
-{% endblock %}
-{% block controls %}
-
- {% if perms.netbox_acls.change_policy %}
-
- Edit
-
- {% endif %}
- {% if perms.netbox_acls.delete_policy %}
-
- Delete
-
- {% endif %}
-
-{% endblock controls %}
-{% block tabs %}
-
-{% endblock tabs %}
-
{% block content %}