From a0bb7b08bdf4e4ecf04c4294ef52b0a685f8cd43 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 10 Nov 2017 11:58:59 -0500 Subject: [PATCH] Closes #1512: Added a view to search for an IP address being assigned to an interface --- netbox/ipam/forms.py | 5 ++ netbox/ipam/tables.py | 18 ++++++- netbox/ipam/urls.py | 1 + netbox/ipam/views.py | 47 +++++++++++++++++- .../ipam/inc/ipadress_edit_header.html | 16 ++++++- netbox/templates/ipam/ipaddress_assign.html | 48 +++++++++++++++++++ netbox/utilities/templatetags/helpers.py | 2 +- 7 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 netbox/templates/ipam/ipaddress_assign.html diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 44316aea23f..d2bac96a60d 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -688,6 +688,11 @@ class Meta: nullable_fields = ['vrf', 'role', 'tenant', 'description'] +class IPAddressAssignForm(BootstrapMixin, forms.Form): + vrf = forms.ModelChoiceField(queryset=VRF.objects.all(), required=False, label='VRF') + address = forms.CharField(label='IP Address') + + def ipaddress_status_choices(): status_counts = {} for status in IPAddress.objects.values('status').annotate(count=Count('status')).order_by('status'): diff --git a/netbox/ipam/tables.py b/netbox/ipam/tables.py index f7253c6bfe3..ebb86731c08 100644 --- a/netbox/ipam/tables.py +++ b/netbox/ipam/tables.py @@ -76,6 +76,10 @@ {% endif %} """ +IPADDRESS_ASSIGN_LINK = """ +{{ record }} +""" + IPADDRESS_PARENT = """ {% if record.interface %} {{ record.interface.parent }} @@ -268,8 +272,8 @@ class Meta(PrefixTable.Meta): class IPAddressTable(BaseTable): pk = ToggleColumn() address = tables.TemplateColumn(IPADDRESS_LINK, verbose_name='IP Address') - status = tables.TemplateColumn(STATUS_LABEL) vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF') + status = tables.TemplateColumn(STATUS_LABEL) tenant = tables.TemplateColumn(TENANT_LINK) parent = tables.TemplateColumn(IPADDRESS_PARENT, orderable=False) interface = tables.Column(orderable=False) @@ -293,6 +297,18 @@ class Meta(IPAddressTable.Meta): ) +class IPAddressAssignTable(BaseTable): + address = tables.TemplateColumn(IPADDRESS_ASSIGN_LINK, verbose_name='IP Address') + status = tables.TemplateColumn(STATUS_LABEL) + parent = tables.TemplateColumn(IPADDRESS_PARENT, orderable=False) + interface = tables.Column(orderable=False) + + class Meta(BaseTable.Meta): + model = IPAddress + fields = ('address', 'vrf', 'status', 'role', 'tenant', 'parent', 'interface') + orderable = False + + # # VLAN groups # diff --git a/netbox/ipam/urls.py b/netbox/ipam/urls.py index c5723ef9401..a67e9e865bb 100644 --- a/netbox/ipam/urls.py +++ b/netbox/ipam/urls.py @@ -60,6 +60,7 @@ url(r'^ip-addresses/import/$', views.IPAddressBulkImportView.as_view(), name='ipaddress_import'), url(r'^ip-addresses/edit/$', views.IPAddressBulkEditView.as_view(), name='ipaddress_bulk_edit'), url(r'^ip-addresses/delete/$', views.IPAddressBulkDeleteView.as_view(), name='ipaddress_bulk_delete'), + url(r'^ip-addresses/assign/$', views.IPAddressAssignView.as_view(), name='ipaddress_assign'), url(r'^ip-addresses/(?P\d+)/$', views.IPAddressView.as_view(), name='ipaddress'), url(r'^ip-addresses/(?P\d+)/edit/$', views.IPAddressEditView.as_view(), name='ipaddress_edit'), url(r'^ip-addresses/(?P\d+)/delete/$', views.IPAddressDeleteView.as_view(), name='ipaddress_delete'), diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 4184d57b661..22335da8f47 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -4,7 +4,7 @@ from django.conf import settings from django.contrib.auth.mixins import PermissionRequiredMixin from django.db.models import Count, Q -from django.shortcuts import get_object_or_404, render +from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.views.generic import View from django_tables2 import RequestConfig @@ -686,6 +686,51 @@ class IPAddressEditView(IPAddressCreateView): permission_required = 'ipam.change_ipaddress' +class IPAddressAssignView(PermissionRequiredMixin, View): + """ + Search for IPAddresses to be assigned to an Interface. + """ + permission_required = 'ipam.change_ipaddress' + + def dispatch(self, request, *args, **kwargs): + + # Redirect user if an interface has not been provided + if 'interface' not in request.GET: + return redirect('ipam:ipaddress_add') + + return super(IPAddressAssignView, self).dispatch(request, *args, **kwargs) + + def get(self, request): + + form = forms.IPAddressAssignForm() + + return render(request, 'ipam/ipaddress_assign.html', { + 'form': form, + 'return_url': request.GET.get('return_url', ''), + }) + + def post(self, request): + + form = forms.IPAddressAssignForm(request.POST) + table = None + + if form.is_valid(): + + queryset = IPAddress.objects.select_related( + 'vrf', 'tenant', 'interface__device', 'interface__virtual_machine' + ).filter( + vrf=form.cleaned_data['vrf'], + address__net_host=form.cleaned_data['address'], + ) + table = tables.IPAddressAssignTable(queryset) + + return render(request, 'ipam/ipaddress_assign.html', { + 'form': form, + 'table': table, + 'return_url': request.GET.get('return_url', ''), + }) + + class IPAddressDeleteView(PermissionRequiredMixin, ObjectDeleteView): permission_required = 'ipam.delete_ipaddress' model = IPAddress diff --git a/netbox/templates/ipam/inc/ipadress_edit_header.html b/netbox/templates/ipam/inc/ipadress_edit_header.html index 7d590291a32..b8ec3878a1b 100644 --- a/netbox/templates/ipam/inc/ipadress_edit_header.html +++ b/netbox/templates/ipam/inc/ipadress_edit_header.html @@ -1,4 +1,16 @@ +{% load helpers %} + diff --git a/netbox/templates/ipam/ipaddress_assign.html b/netbox/templates/ipam/ipaddress_assign.html new file mode 100644 index 00000000000..a623a55f348 --- /dev/null +++ b/netbox/templates/ipam/ipaddress_assign.html @@ -0,0 +1,48 @@ +{% extends 'utilities/obj_edit.html' %} +{% load static from staticfiles %} +{% load form_helpers %} +{% load helpers %} + +{% block content %} +
+ {% csrf_token %} + {% for field in form.hidden_fields %} + {{ field }} + {% endfor %} +
+
+

Assign an IP Address

+ {% include 'ipam/inc/ipadress_edit_header.html' with active_tab='assign' %} + {% if form.non_field_errors %} +
+
Errors
+
+ {{ form.non_field_errors }} +
+
+ {% endif %} +
+
Select IP Address
+
+ {% render_field form.vrf %} + {% render_field form.address %} +
+
+
+
+
+
+ + Cancel +
+
+
+ {% if table %} +
+
+

Search Results

+ {% include 'utilities/obj_table.html' with table_template='panel_table.html' %} +
+
+ {% endif %} +{% endblock %} diff --git a/netbox/utilities/templatetags/helpers.py b/netbox/utilities/templatetags/helpers.py index ea6cd117309..2af93688555 100644 --- a/netbox/utilities/templatetags/helpers.py +++ b/netbox/utilities/templatetags/helpers.py @@ -132,7 +132,7 @@ def querystring(request, **kwargs): querydict[k] = v elif k in querydict: querydict.pop(k) - querystring = querydict.urlencode() + querystring = querydict.urlencode(safe='/') if querystring: return '?' + querystring else: