mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-24 17:38:37 -06:00
Closes #1945: Implemented a VLAN members view
This commit is contained in:
parent
4acd8e180d
commit
38a208242b
@ -6,6 +6,7 @@ from django.contrib.contenttypes.fields import GenericRelation
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
from django.db.models.expressions import RawSQL
|
from django.db.models.expressions import RawSQL
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
@ -616,6 +617,13 @@ class VLAN(CreatedUpdatedModel, CustomFieldModel):
|
|||||||
def get_status_class(self):
|
def get_status_class(self):
|
||||||
return STATUS_CHOICE_CLASSES[self.status]
|
return STATUS_CHOICE_CLASSES[self.status]
|
||||||
|
|
||||||
|
def get_members(self):
|
||||||
|
# Return all interfaces assigned to this VLAN
|
||||||
|
return Interface.objects.filter(
|
||||||
|
Q(untagged_vlan_id=self.pk) |
|
||||||
|
Q(tagged_vlans=self.pk)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Service(CreatedUpdatedModel):
|
class Service(CreatedUpdatedModel):
|
||||||
|
@ -3,6 +3,7 @@ from __future__ import unicode_literals
|
|||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
from django_tables2.utils import Accessor
|
from django_tables2.utils import Accessor
|
||||||
|
|
||||||
|
from dcim.models import Interface
|
||||||
from tenancy.tables import COL_TENANT
|
from tenancy.tables import COL_TENANT
|
||||||
from utilities.tables import BaseTable, ToggleColumn
|
from utilities.tables import BaseTable, ToggleColumn
|
||||||
from .models import Aggregate, IPAddress, Prefix, RIR, Role, VLAN, VLANGroup, VRF
|
from .models import Aggregate, IPAddress, Prefix, RIR, Role, VLAN, VLANGroup, VRF
|
||||||
@ -138,6 +139,18 @@ VLANGROUP_ACTIONS = """
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
VLAN_MEMBER_UNTAGGED = """
|
||||||
|
{% if record.untagged_vlan_id == vlan.pk %}
|
||||||
|
<i class="glyphicon glyphicon-ok">
|
||||||
|
{% endif %}
|
||||||
|
"""
|
||||||
|
|
||||||
|
VLAN_MEMBER_ACTIONS = """
|
||||||
|
{% if perms.dcim.change_interface %}
|
||||||
|
<a href="{% if record.device %}{% url 'dcim:interface_edit' pk=record.pk %}{% else %}{% url 'virtualization:interface_edit' pk=record.pk %}{% endif %}" class="btn btn-xs btn-warning"><i class="glyphicon glyphicon-pencil"></i></a>
|
||||||
|
{% endif %}
|
||||||
|
"""
|
||||||
|
|
||||||
TENANT_LINK = """
|
TENANT_LINK = """
|
||||||
{% if record.tenant %}
|
{% if record.tenant %}
|
||||||
<a href="{% url 'tenancy:tenant' slug=record.tenant.slug %}" title="{{ record.tenant.description }}">{{ record.tenant }}</a>
|
<a href="{% url 'tenancy:tenant' slug=record.tenant.slug %}" title="{{ record.tenant.description }}">{{ record.tenant }}</a>
|
||||||
@ -361,3 +374,21 @@ class VLANDetailTable(VLANTable):
|
|||||||
|
|
||||||
class Meta(VLANTable.Meta):
|
class Meta(VLANTable.Meta):
|
||||||
fields = ('pk', 'vid', 'site', 'group', 'name', 'prefixes', 'tenant', 'status', 'role', 'description')
|
fields = ('pk', 'vid', 'site', 'group', 'name', 'prefixes', 'tenant', 'status', 'role', 'description')
|
||||||
|
|
||||||
|
|
||||||
|
class VLANMemberTable(BaseTable):
|
||||||
|
parent = tables.LinkColumn(order_by=['device', 'virtual_machine'])
|
||||||
|
name = tables.Column(verbose_name='Interface')
|
||||||
|
untagged = tables.TemplateColumn(
|
||||||
|
template_code=VLAN_MEMBER_UNTAGGED,
|
||||||
|
orderable=False
|
||||||
|
)
|
||||||
|
actions = tables.TemplateColumn(
|
||||||
|
template_code=VLAN_MEMBER_ACTIONS,
|
||||||
|
attrs={'td': {'class': 'text-right'}},
|
||||||
|
verbose_name=''
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta(BaseTable.Meta):
|
||||||
|
model = Interface
|
||||||
|
fields = ('parent', 'name', 'untagged', 'actions')
|
||||||
|
@ -80,6 +80,7 @@ urlpatterns = [
|
|||||||
url(r'^vlans/edit/$', views.VLANBulkEditView.as_view(), name='vlan_bulk_edit'),
|
url(r'^vlans/edit/$', views.VLANBulkEditView.as_view(), name='vlan_bulk_edit'),
|
||||||
url(r'^vlans/delete/$', views.VLANBulkDeleteView.as_view(), name='vlan_bulk_delete'),
|
url(r'^vlans/delete/$', views.VLANBulkDeleteView.as_view(), name='vlan_bulk_delete'),
|
||||||
url(r'^vlans/(?P<pk>\d+)/$', views.VLANView.as_view(), name='vlan'),
|
url(r'^vlans/(?P<pk>\d+)/$', views.VLANView.as_view(), name='vlan'),
|
||||||
|
url(r'^vlans/(?P<pk>\d+)/members/$', views.VLANMembersView.as_view(), name='vlan_members'),
|
||||||
url(r'^vlans/(?P<pk>\d+)/edit/$', views.VLANEditView.as_view(), name='vlan_edit'),
|
url(r'^vlans/(?P<pk>\d+)/edit/$', views.VLANEditView.as_view(), name='vlan_edit'),
|
||||||
url(r'^vlans/(?P<pk>\d+)/delete/$', views.VLANDeleteView.as_view(), name='vlan_delete'),
|
url(r'^vlans/(?P<pk>\d+)/delete/$', views.VLANDeleteView.as_view(), name='vlan_delete'),
|
||||||
|
|
||||||
|
@ -851,6 +851,38 @@ class VLANView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class VLANMembersView(View):
|
||||||
|
|
||||||
|
def get(self, request, pk):
|
||||||
|
|
||||||
|
vlan = get_object_or_404(VLAN.objects.all(), pk=pk)
|
||||||
|
members = vlan.get_members().select_related('device', 'virtual_machine')
|
||||||
|
|
||||||
|
members_table = tables.VLANMemberTable(members)
|
||||||
|
# if request.user.has_perm('dcim.change_interface'):
|
||||||
|
# members_table.columns.show('pk')
|
||||||
|
|
||||||
|
paginate = {
|
||||||
|
'klass': EnhancedPaginator,
|
||||||
|
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
|
||||||
|
}
|
||||||
|
RequestConfig(request, paginate).configure(members_table)
|
||||||
|
|
||||||
|
# Compile permissions list for rendering the object table
|
||||||
|
# permissions = {
|
||||||
|
# 'add': request.user.has_perm('ipam.add_ipaddress'),
|
||||||
|
# 'change': request.user.has_perm('ipam.change_ipaddress'),
|
||||||
|
# 'delete': request.user.has_perm('ipam.delete_ipaddress'),
|
||||||
|
# }
|
||||||
|
|
||||||
|
return render(request, 'ipam/vlan_members.html', {
|
||||||
|
'vlan': vlan,
|
||||||
|
'members_table': members_table,
|
||||||
|
# 'permissions': permissions,
|
||||||
|
# 'bulk_querystring': 'vrf_id={}&parent={}'.format(prefix.vrf.pk if prefix.vrf else '0', prefix.prefix),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
class VLANCreateView(PermissionRequiredMixin, ObjectEditView):
|
class VLANCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'ipam.add_vlan'
|
permission_required = 'ipam.add_vlan'
|
||||||
model = VLAN
|
model = VLAN
|
||||||
|
46
netbox/templates/ipam/inc/vlan_header.html
Normal file
46
netbox/templates/ipam/inc/vlan_header.html
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8 col-md-9">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="{% url 'ipam:vlan_list' %}">VLANs</a></li>
|
||||||
|
{% if vlan.site %}
|
||||||
|
<li><a href="{% url 'ipam:vlan_list' %}?site={{ vlan.site.slug }}">{{ vlan.site }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if vlan.group %}
|
||||||
|
<li><a href="{% url 'ipam:vlan_list' %}?group={{ vlan.group.slug }}">{{ vlan.group }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
<li>{{ vlan }}</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 col-md-3">
|
||||||
|
<form action="{% url 'ipam:vlan_list' %}" method="get">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" name="q" class="form-control" placeholder="Search VLANs" />
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<span class="fa fa-search" aria-hidden="true"></span>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pull-right">
|
||||||
|
{% if perms.ipam.change_vlan %}
|
||||||
|
<a href="{% url 'ipam:vlan_edit' pk=vlan.pk %}" class="btn btn-warning">
|
||||||
|
<span class="fa fa-pencil" aria-hidden="true"></span>
|
||||||
|
Edit this VLAN
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if perms.ipam.delete_vlan %}
|
||||||
|
<a href="{% url 'ipam:vlan_delete' pk=vlan.pk %}" class="btn btn-danger">
|
||||||
|
<span class="fa fa-trash" aria-hidden="true"></span>
|
||||||
|
Delete this VLAN
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<h1>{% block title %}VLAN {{ vlan.display_name }}{% endblock %}</h1>
|
||||||
|
{% include 'inc/created_updated.html' with obj=vlan %}
|
||||||
|
<ul class="nav nav-tabs" style="margin-bottom: 20px">
|
||||||
|
<li role="presentation"{% if active_tab == 'vlan' %} class="active"{% endif %}><a href="{% url 'ipam:vlan' pk=vlan.pk %}">VLAN</a></li>
|
||||||
|
<li role="presentation"{% if active_tab == 'members' %} class="active"{% endif %}><a href="{% url 'ipam:vlan_members' pk=vlan.pk %}">Members <span class="badge">{{ vlan.get_members.count }}</span></a></li>
|
||||||
|
</ul>
|
@ -1,48 +1,7 @@
|
|||||||
{% extends '_base.html' %}
|
{% extends '_base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
{% include 'ipam/inc/vlan_header.html' with active_tab='vlan' %}
|
||||||
<div class="col-sm-8 col-md-9">
|
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li><a href="{% url 'ipam:vlan_list' %}">VLANs</a></li>
|
|
||||||
{% if vlan.site %}
|
|
||||||
<li><a href="{% url 'ipam:vlan_list' %}?site={{ vlan.site.slug }}">{{ vlan.site }}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
{% if vlan.group %}
|
|
||||||
<li><a href="{% url 'ipam:vlan_list' %}?group={{ vlan.group.slug }}">{{ vlan.group }}</a></li>
|
|
||||||
{% endif %}
|
|
||||||
<li>{{ vlan }}</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-4 col-md-3">
|
|
||||||
<form action="{% url 'ipam:vlan_list' %}" method="get">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" name="q" class="form-control" placeholder="Search VLANs" />
|
|
||||||
<span class="input-group-btn">
|
|
||||||
<button type="submit" class="btn btn-primary">
|
|
||||||
<span class="fa fa-search" aria-hidden="true"></span>
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pull-right">
|
|
||||||
{% if perms.ipam.change_vlan %}
|
|
||||||
<a href="{% url 'ipam:vlan_edit' pk=vlan.pk %}" class="btn btn-warning">
|
|
||||||
<span class="fa fa-pencil" aria-hidden="true"></span>
|
|
||||||
Edit this VLAN
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if perms.ipam.delete_vlan %}
|
|
||||||
<a href="{% url 'ipam:vlan_delete' pk=vlan.pk %}" class="btn btn-danger">
|
|
||||||
<span class="fa fa-trash" aria-hidden="true"></span>
|
|
||||||
Delete this VLAN
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<h1>{% block title %}VLAN {{ vlan.display_name }}{% endblock %}</h1>
|
|
||||||
{% include 'inc/created_updated.html' with obj=vlan %}
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
|
12
netbox/templates/ipam/vlan_members.html
Normal file
12
netbox/templates/ipam/vlan_members.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{% extends '_base.html' %}
|
||||||
|
|
||||||
|
{% block title %}{{ vlan }} - Members{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include 'ipam/inc/vlan_header.html' with active_tab='members' %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
{% include 'utilities/obj_table.html' with table=members_table table_template='panel_table.html' heading='VLAN Members' parent=vlan %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user