Merge remote-tracking branch 'origin/dev' into housekeeping/cleanup

# Conflicts:
#	netbox_acls/templates/netbox_acls/accesslist.html
This commit is contained in:
Abhimanyu Saharan 2023-01-21 18:14:11 +05:30
commit d2a91f619a
7 changed files with 197 additions and 111 deletions

View File

@ -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:

View File

@ -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,
),
]

View File

@ -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}"

View File

@ -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",

View File

@ -1,90 +1,63 @@
{% extends 'generic/object.html' %}
{% load render_table from django_tables2 %}
{% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'plugins:netbox_acls:accesslist_list' %}">Access Lists</a></li>
{% endblock %}
{% block controls %}
<div class="pull-right noprint">
{% block extra_controls %}
{% if perms.netbox_acls.change_policy %}
{% if object.type == 'extended' %}
<a href="{% url 'plugins:netbox_acls:aclextendedrule_add' %}?access_list={{ object.pk }}" class="btn btn-success">
{% elif object.type == 'standard' %}
<a href="{% url 'plugins:netbox_acls:aclstandardrule_add' %}?access_list={{ object.pk }}" class="btn btn-success">
{% endif %}
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Rule
</a>
<a href="{% url 'plugins:netbox_acls:accesslist_edit' pk=object.pk %}" class="btn btn-warning">
<span class="mdi mdi-pencil" aria-hidden="true"></span> Edit
{% if object.type == 'extended' %}
<a href="{% url 'plugins:netbox_acls:aclextendedrule_add' %}?access_list={{ object.pk }}" class="btn btn-sm btn-primary">
{% elif object.type == 'standard' %}
<a href="{% url 'plugins:netbox_acls:aclstandardrule_add' %}?access_list={{ object.pk }}" class="btn btn-sm btn-primary">
{% endif %}
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Rule
</a>
{% endif %}
{% if perms.netbox_acls.delete_policy %}
<a href="{% url 'plugins:netbox_acls:accesslist_delete' pk=object.pk %}" class="btn btn-danger">
<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> Delete
</a>
{% endif %}
</div>
{% endblock controls %}
{% block tabs %}
<ul class="nav nav-tabs px-3">
{% block tab_items %}
<li class="nav-item" role="presentation">
<a class="nav-link{% if not active_tab %} active{% endif %}" href="{{ object.get_absolute_url }}">{{ object|meta:"verbose_name"|bettertitle }}</a>
</li>
{% endblock tab_items %}
{% if perms.extras.view_objectchange %}
<li role="presentation" class="nav-item">
<a href="{% url 'plugins:netbox_acls:accesslist_changelog' pk=object.pk %}" class="nav-link{% if active_tab == 'changelog'%} active{% endif %}">Change Log</a>
</li>
{% endif %}
</ul>
{% endblock tabs %}
{% endblock extra_controls %}
{% block content %}
<div class="row mb-3">
<div class="col col-md-6">
<div class="card">
<h5 class="card-header">Access List</h5>
<div class="card-body">
<table class="table table-hover attr-table">
<tr>
<th scope="row">Type</th>
<td>{{ object.get_type_display }}</td>
</tr>
<tr>
<th scope="row">Default Action</th>
<td>{% badge object.get_default_action_display bg_color=object.get_default_action_color %}</td>
</tr>
<tr>
<th scope="row">Rules</th>
{% if object.type == 'standard' %}
<td>{{ object.aclstandardrules.count|placeholder }}</td>
{% elif object.type == 'extended' %}
<td>{{ object.aclextendedrules.count|placeholder }}</td>
{% endif %}
</tr>
<tr>
<th scope="row">Assigned Host</th>
<td>{{ object.assigned_object|linkify }}</td>
</tr>
</table>
<div class="row mb-3">
<div class="col col-md-6">
<div class="card">
<h5 class="card-header">Access List</h5>
<div class="card-body">
<table class="table table-hover attr-table">
<tr>
<th scope="row">Type</th>
<td>{{ object.get_type_display }}</td>
</tr>
<tr>
<th scope="row">Default Action</th>
<td>{% badge object.get_default_action_display bg_color=object.get_default_action_color %}</td>
</tr>
<tr>
<th scope="row">Rules</th>
{% if object.type == 'standard' %}
<td>{{ object.aclstandardrules.count|placeholder }}</td>
{% elif object.type == 'extended' %}
<td>{{ object.aclextendedrules.count|placeholder }}</td>
{% endif %}
</tr>
<tr>
<th scope="row">Assigned Host</th>
<td>{{ object.assigned_object|linkify }}</td>
</tr>
</table>
</div>
</div>
{% include 'inc/panels/custom_fields.html' %}
</div>
</div>
{% include 'inc/panels/custom_fields.html' %}
</div>
<div class="col col-md-6">
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/comments.html' %}
</div>
</div>
<div class="row">
<div class="col col-md-12">
<div class="card">
<h5 class="card-header">{{ object.get_type_display }} Rules</h5>
<div class="card-body table-responsive">
{% render_table rules_table %}
<div class="col col-md-6">
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/comments.html' %}
</div>
</div>
<div class="row">
<div class="col col-md-12">
<div class="card">
<h5 class="card-header">{{ object.get_type_display }} Rules</h5>
<div class="card-body table-responsive">
{% render_table rules_table %}
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@ -67,6 +67,9 @@
{% render_field form.virtual_chassis %}
</div>
<div class="tab-pane{% if form.initial.virtual_machine %} active{% endif %}" id="virtualmachine">
{% render_field form.cluster_type %}
{% render_field form.cluster_group %}
{% render_field form.cluster %}
{% render_field form.virtual_machine %}
</div>
</div>

View File

@ -1,38 +1,6 @@
{% extends 'generic/object.html' %}
{% load render_table from django_tables2 %}
{% block breadcrumbs %}
<li class="breadcrumb-item"><a href="{% url 'plugins:netbox_acls:aclinterfaceassignment_list' %}">ACL Interface Assignments</a></li>
{% endblock %}
{% block controls %}
<div class="pull-right noprint">
{% if perms.netbox_acls.change_policy %}
<a href="{% url 'plugins:netbox_acls:aclinterfaceassignment_edit' pk=object.pk %}" class="btn btn-warning">
<span class="mdi mdi-pencil" aria-hidden="true"></span> Edit
</a>
{% endif %}
{% if perms.netbox_acls.delete_policy %}
<a href="{% url 'plugins:netbox_acls:aclinterfaceassignment_delete' pk=object.pk %}" class="btn btn-danger">
<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> Delete
</a>
{% endif %}
</div>
{% endblock controls %}
{% block tabs %}
<ul class="nav nav-tabs px-3">
{% block tab_items %}
<li class="nav-item" role="presentation">
<a class="nav-link{% if not active_tab %} active{% endif %}" href="{{ object.get_absolute_url }}">{{ object|meta:"verbose_name"|bettertitle }}</a>
</li>
{% endblock tab_items %}
{% if perms.extras.view_objectchange %}
<li role="presentation" class="nav-item">
<a href="{% url 'plugins:netbox_acls:aclinterfaceassignment_changelog' pk=object.pk %}" class="nav-link{% if active_tab == 'changelog'%} active{% endif %}">Change Log</a>
</li>
{% endif %}
</ul>
{% endblock tabs %}
{% block content %}
<div class="row mb-3">
<div class="col col-md-6">