1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Extend VLANGroup to support cluster/cluster group assignment

This commit is contained in:
Jeremy Stretch
2021-03-15 16:25:44 -04:00
parent 0115a61ab7
commit c0c4eed3a8
6 changed files with 85 additions and 14 deletions

View File

@ -552,6 +552,12 @@ class VLANGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
rack = django_filters.NumberFilter( rack = django_filters.NumberFilter(
method='filter_scope' method='filter_scope'
) )
clustergroup = django_filters.NumberFilter(
method='filter_scope'
)
cluster = django_filters.NumberFilter(
method='filter_scope'
)
class Meta: class Meta:
model = VLANGroup model = VLANGroup
@ -559,7 +565,7 @@ class VLANGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet):
def filter_scope(self, queryset, name, value): def filter_scope(self, queryset, name, value):
return queryset.filter( return queryset.filter(
scope_type=ContentType.objects.get(app_label='dcim', model=name), scope_type=ContentType.objects.get(model=name),
scope_id=value scope_id=value
) )

View File

@ -1,5 +1,4 @@
from django import forms from django import forms
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from dcim.models import Device, Interface, Location, Rack, Region, Site, SiteGroup from dcim.models import Device, Interface, Location, Rack, Region, Site, SiteGroup
@ -14,7 +13,7 @@ from utilities.forms import (
DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableIPAddressField, NumericArrayField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableIPAddressField, NumericArrayField,
ReturnURLForm, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES, ReturnURLForm, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
) )
from virtualization.models import Cluster, VirtualMachine, VMInterface from virtualization.models import Cluster, ClusterGroup, VirtualMachine, VMInterface
from .choices import * from .choices import *
from .constants import * from .constants import *
from .models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF from .models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF
@ -1153,17 +1152,28 @@ class VLANGroupForm(BootstrapMixin, CustomFieldModelForm):
'location_id': '$location', 'location_id': '$location',
} }
) )
cluster_group = DynamicModelChoiceField(
queryset=ClusterGroup.objects.all(),
required=False,
initial_params={
'clusters': '$cluster'
}
)
cluster = DynamicModelChoiceField(
queryset=Cluster.objects.all(),
required=False,
query_params={
'group_id': '$cluster_group',
}
)
slug = SlugField() slug = SlugField()
class Meta: class Meta:
model = VLANGroup model = VLANGroup
fields = [ fields = [
'name', 'slug', 'description', 'region', 'site_group', 'site', 'location', 'rack', 'name', 'slug', 'description', 'region', 'site_group', 'site', 'location', 'rack', 'cluster_group',
'cluster',
] ]
fieldsets = (
('VLAN Group', ('name', 'slug', 'description')),
('Scope', ('region', 'site_group', 'site', 'location', 'rack')),
)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
instance = kwargs.get('instance') instance = kwargs.get('instance')
@ -1180,6 +1190,10 @@ class VLANGroupForm(BootstrapMixin, CustomFieldModelForm):
initial['site_group'] = instance.scope initial['site_group'] = instance.scope
elif type(instance.scope) is Region: elif type(instance.scope) is Region:
initial['region'] = instance.scope initial['region'] = instance.scope
elif type(instance.scope) is Cluster:
initial['cluster'] = instance.scope
elif type(instance.scope) is ClusterGroup:
initial['cluster_group'] = instance.scope
kwargs['initial'] = initial kwargs['initial'] = initial
@ -1189,8 +1203,10 @@ class VLANGroupForm(BootstrapMixin, CustomFieldModelForm):
super().clean() super().clean()
# Assign scope object # Assign scope object
self.instance.scope = self.cleaned_data['rack'] or self.cleaned_data['location'] or self.cleaned_data['site'] \ self.instance.scope = self.cleaned_data['rack'] or self.cleaned_data['location'] or \
or self.cleaned_data['site_group'] or self.cleaned_data['region'] or None self.cleaned_data['site'] or self.cleaned_data['site_group'] or \
self.cleaned_data['region'] or self.cleaned_data['cluster'] or \
self.cleaned_data['cluster_group'] or None
class VLANGroupCSVForm(CustomFieldModelCSVForm): class VLANGroupCSVForm(CustomFieldModelCSVForm):

View File

@ -23,7 +23,7 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='vlangroup', model_name='vlangroup',
name='scope_type', name='scope_type',
field=models.ForeignKey(blank=True, limit_choices_to=models.Q(('app_label', 'dcim'), ('model__in', ['region', 'sitegroup', 'site', 'location', 'rack'])), null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'), field=models.ForeignKey(blank=True, limit_choices_to=models.Q(model__in=['region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster']), null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'),
), ),
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='vlangroup', name='vlangroup',

View File

@ -35,8 +35,7 @@ class VLANGroup(OrganizationalModel):
to=ContentType, to=ContentType,
on_delete=models.CASCADE, on_delete=models.CASCADE,
limit_choices_to=Q( limit_choices_to=Q(
app_label='dcim', model__in=['region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster']
model__in=['region', 'sitegroup', 'site', 'location', 'rack']
), ),
blank=True, blank=True,
null=True null=True

View File

@ -642,6 +642,7 @@ class VLANGroupListView(generic.ObjectListView):
class VLANGroupEditView(generic.ObjectEditView): class VLANGroupEditView(generic.ObjectEditView):
queryset = VLANGroup.objects.all() queryset = VLANGroup.objects.all()
model_form = forms.VLANGroupForm model_form = forms.VLANGroupForm
template_name = 'ipam/vlangroup_edit.html'
class VLANGroupDeleteView(generic.ObjectDeleteView): class VLANGroupDeleteView(generic.ObjectDeleteView):
@ -655,7 +656,7 @@ class VLANGroupBulkImportView(generic.BulkImportView):
class VLANGroupBulkDeleteView(generic.BulkDeleteView): class VLANGroupBulkDeleteView(generic.BulkDeleteView):
queryset = VLANGroup.objects.prefetch_related('site').annotate( queryset = VLANGroup.objects.annotate(
vlan_count=count_related(VLAN, 'group') vlan_count=count_related(VLAN, 'group')
) )
filterset = filters.VLANGroupFilterSet filterset = filters.VLANGroupFilterSet

View File

@ -0,0 +1,49 @@
{% extends 'generic/object_edit.html' %}
{% load form_helpers %}
{% load helpers %}
{% block form %}
<div class="panel panel-default">
<div class="panel-heading"><strong>VLAN Group</strong></div>
<div class="panel-body">
{% render_field form.name %}
{% render_field form.slug %}
{% render_field form.description %}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<strong>Scope</strong>
</div>
<div class="panel-body">
{% with virtual_tab_active=form.initial.cluster %}
<ul class="nav nav-tabs" role="tablist">
<li role="presentation"{% if not virtual_tab_active %} class="active"{% endif %}><a href="#physical" role="tab" data-toggle="tab">Physical</a></li>
<li role="presentation"{% if virtual_tab_active %} class="active"{% endif %}><a href="#virtual" role="tab" data-toggle="tab">Virtual</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane{% if not virtual_tab_active %} active{% endif %}" id="physical">
{% render_field form.region %}
{% render_field form.site_group %}
{% render_field form.site %}
{% render_field form.location %}
{% render_field form.rack %}
</div>
<div class="tab-pane{% if virtual_tab_active %} active{% endif %}" id="virtual">
{% render_field form.cluster_group %}
{% render_field form.cluster %}
</div>
</div>
<span class="help-block">The VLAN group will be limited in scope to the most-specific object selected above.</span>
{% endwith %}
</div>
</div>
{% if form.custom_fields %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Custom Fields</strong></div>
<div class="panel-body">
{% render_custom_fields form %}
</div>
</div>
{% endif %}
{% endblock %}