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

Closes #971: Implement VLANGroup VLANs view to show available VLANs within a group

This commit is contained in:
Vas Sadvariy
2018-08-02 05:59:00 +10:00
committed by Jeremy Stretch
parent 475e0e6c1e
commit 33e45a5292
6 changed files with 118 additions and 3 deletions

View File

@ -528,7 +528,7 @@ class VLANGroup(models.Model):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
return "{}?group_id={}".format(reverse('ipam:vlan_list'), self.pk) return reverse('ipam:vlangroup_vlans', args=[self.pk])
def to_csv(self): def to_csv(self):
return ( return (

View File

@ -110,6 +110,16 @@ STATUS_LABEL = """
{% endif %} {% endif %}
""" """
VLAN_LINK = """
{% if record.pk %}
<a href="{{ record.get_absolute_url }}">{{ record.vid }}</a>
{% elif perms.ipam.add_vlan %}
<a href="{% url 'ipam:vlan_add' %}?vid={{ record.vid }}&group={{ vlan_group.pk }}{% if vlan_group.site %}&site={{ vlan_group.site.pk }}{% endif %}" class="btn btn-xs btn-success">{{ record.available }} VLAN{{ record.available|pluralize }} available</a>
{% else %}
{{ record.available }} VLAN{{ record.available|pluralize }} available
{% endif %}
"""
VLAN_PREFIXES = """ VLAN_PREFIXES = """
{% for prefix in record.prefixes.all %} {% for prefix in record.prefixes.all %}
<a href="{% url 'ipam:prefix' pk=prefix.pk %}">{{ prefix }}</a>{% if not forloop.last %}<br />{% endif %} <a href="{% url 'ipam:prefix' pk=prefix.pk %}">{{ prefix }}</a>{% if not forloop.last %}<br />{% endif %}
@ -375,9 +385,9 @@ class VLANGroupTable(BaseTable):
class VLANTable(BaseTable): class VLANTable(BaseTable):
pk = ToggleColumn() pk = ToggleColumn()
vid = tables.LinkColumn('ipam:vlan', args=[Accessor('pk')], verbose_name='ID') vid = tables.TemplateColumn(VLAN_LINK, verbose_name='ID')
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')]) site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group') group = tables.LinkColumn('ipam:vlangroup_vlans', args=[Accessor('group.pk')], verbose_name='Group')
tenant = tables.TemplateColumn(template_code=COL_TENANT) tenant = tables.TemplateColumn(template_code=COL_TENANT)
status = tables.TemplateColumn(STATUS_LABEL) status = tables.TemplateColumn(STATUS_LABEL)
role = tables.TemplateColumn(VLAN_ROLE_LINK) role = tables.TemplateColumn(VLAN_ROLE_LINK)
@ -385,6 +395,9 @@ class VLANTable(BaseTable):
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
model = VLAN model = VLAN
fields = ('pk', 'vid', 'site', 'group', 'name', 'tenant', 'status', 'role', 'description') fields = ('pk', 'vid', 'site', 'group', 'name', 'tenant', 'status', 'role', 'description')
row_attrs = {
'class': lambda record: 'success' if not isinstance(record, VLAN) else '',
}
class VLANDetailTable(VLANTable): class VLANDetailTable(VLANTable):

View File

@ -72,6 +72,7 @@ urlpatterns = [
url(r'^vlan-groups/import/$', views.VLANGroupBulkImportView.as_view(), name='vlangroup_import'), url(r'^vlan-groups/import/$', views.VLANGroupBulkImportView.as_view(), name='vlangroup_import'),
url(r'^vlan-groups/delete/$', views.VLANGroupBulkDeleteView.as_view(), name='vlangroup_bulk_delete'), url(r'^vlan-groups/delete/$', views.VLANGroupBulkDeleteView.as_view(), name='vlangroup_bulk_delete'),
url(r'^vlan-groups/(?P<pk>\d+)/edit/$', views.VLANGroupEditView.as_view(), name='vlangroup_edit'), url(r'^vlan-groups/(?P<pk>\d+)/edit/$', views.VLANGroupEditView.as_view(), name='vlangroup_edit'),
url(r'^vlan-groups/(?P<pk>\d+)/vlans/$', views.VLANGroupVLANsView.as_view(), name='vlangroup_vlans'),
# VLANs # VLANs
url(r'^vlans/$', views.VLANListView.as_view(), name='vlan_list'), url(r'^vlans/$', views.VLANListView.as_view(), name='vlan_list'),

View File

@ -84,6 +84,34 @@ def add_available_ipaddresses(prefix, ipaddress_list, is_pool=False):
return output return output
def add_available_vlans(vlan_group, vlans):
"""
Create fake records for all gaps between used VLANs
"""
MIN_VLAN = 1
MAX_VLAN = 4094
if not vlans:
return [{'vid': MIN_VLAN, 'available': MAX_VLAN - MIN_VLAN + 1}]
prev_vid = MAX_VLAN
new_vlans = []
for vlan in vlans:
if vlan.vid - prev_vid > 1:
new_vlans.append({'vid': prev_vid + 1, 'available': vlan.vid - prev_vid - 1})
prev_vid = vlan.vid
if vlans[0].vid > MIN_VLAN:
new_vlans.append({'vid': MIN_VLAN, 'available': vlans[0].vid - MIN_VLAN})
if prev_vid < MAX_VLAN:
new_vlans.append({'vid': prev_vid + 1, 'available': MAX_VLAN - prev_vid})
vlans = list(vlans) + new_vlans
vlans.sort(key=lambda v: v.vid if type(v) == VLAN else v['vid'])
return vlans
# #
# VRFs # VRFs
# #
@ -814,6 +842,41 @@ class VLANGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
default_return_url = 'ipam:vlangroup_list' default_return_url = 'ipam:vlangroup_list'
class VLANGroupVLANsView(View):
def get(self, request, pk):
vlan_group = get_object_or_404(VLANGroup.objects.all(), pk=pk)
vlans = VLAN.objects.filter(group_id=pk)
vlans = add_available_vlans(vlan_group, vlans)
vlan_table = tables.VLANDetailTable(vlans)
if request.user.has_perm('ipam.change_vlan') or request.user.has_perm('ipam.delete_vlan'):
vlan_table.columns.show('pk')
vlan_table.columns.hide('site')
vlan_table.columns.hide('group')
paginate = {
'klass': EnhancedPaginator,
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
}
RequestConfig(request, paginate).configure(vlan_table)
# Compile permissions list for rendering the object table
permissions = {
'add': request.user.has_perm('ipam.add_vlan'),
'change': request.user.has_perm('ipam.change_vlan'),
'delete': request.user.has_perm('ipam.delete_vlan'),
}
return render(request, 'ipam/vlangroup_vlans.html', {
'vlan_group': vlan_group,
'first_available_vlan': vlan_group.get_next_available_vid(),
'vlan_table': vlan_table,
'permissions': permissions,
})
# #
# VLANs # VLANs
# #

View File

@ -0,0 +1,14 @@
<div class="pull-right">
{% if perms.ipam.add_vlan and first_available_vlan %}
<a href="{% url 'ipam:vlan_add' %}?vid={{ first_available_vlan }}&group={{ vlan_group.pk }}{% if vlan_group.site %}&site={{ vlan_group.site.pk }}{% endif %}" class="btn btn-success">
<i class="fa fa-plus" aria-hidden="true"></i> Add a VLAN
</a>
{% endif %}
{% if perms.ipam.change_vlangroup %}
<a href="{% url 'ipam:vlangroup_edit' pk=vlan_group.pk %}" class="btn btn-warning">
<span class="fa fa-pencil" aria-hidden="true"></span>
Edit this VLAN Group
</a>
{% endif %}
</div>
<h1>{{ vlan_group }}</h1>

View File

@ -0,0 +1,24 @@
{% extends '_base.html' %}
{% block title %}{{ vlan_group }} - VLANs{% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-12 col-md-12">
<ol class="breadcrumb">
<li><a href="{% url 'ipam:vlangroup_list' %}">VLAN Groups</a></li>
{% if vlan_group.site %}
<li><a href="{% url 'dcim:site' slug=vlan_group.site.slug %}">{{ vlan_group.site }}</a></li>
{% endif %}
<li>{{ vlan_group }}</li>
</ol>
</div>
</div>
{% include 'ipam/inc/vlangroup_header.html' %}
<div class="row">
<div class="col-md-12">
{% include 'utilities/obj_table.html' with table=vlan_table table_template='panel_table.html' heading='VLANs' bulk_edit_url='ipam:vlan_bulk_edit' bulk_delete_url='ipam:vlan_bulk_delete' %}
</div>
</div>
{% endblock %}