Skip to content

Commit

Permalink
Closes #1512: Added a view to search for an IP address being assigned…
Browse files Browse the repository at this point in the history
… to an interface
  • Loading branch information
jeremystretch committed Nov 10, 2017
1 parent e1d655c commit a0bb7b0
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 5 deletions.
5 changes: 5 additions & 0 deletions netbox/ipam/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'):
Expand Down
18 changes: 17 additions & 1 deletion netbox/ipam/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@
{% endif %}
"""

IPADDRESS_ASSIGN_LINK = """
<a href="{% url 'ipam:ipaddress_edit' pk=record.pk %}?interface={{ request.GET.interface }}&return_url={{ request.GET.return_url }}">{{ record }}</a>
"""

IPADDRESS_PARENT = """
{% if record.interface %}
<a href="{{ record.interface.parent.get_absolute_url }}">{{ record.interface.parent }}</a>
Expand Down Expand Up @@ -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)
Expand All @@ -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
#
Expand Down
1 change: 1 addition & 0 deletions netbox/ipam/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -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<pk>\d+)/$', views.IPAddressView.as_view(), name='ipaddress'),
url(r'^ip-addresses/(?P<pk>\d+)/edit/$', views.IPAddressEditView.as_view(), name='ipaddress_edit'),
url(r'^ip-addresses/(?P<pk>\d+)/delete/$', views.IPAddressDeleteView.as_view(), name='ipaddress_delete'),
Expand Down
47 changes: 46 additions & 1 deletion netbox/ipam/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
16 changes: 14 additions & 2 deletions netbox/templates/ipam/inc/ipadress_edit_header.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
{% load helpers %}

<ul class="nav nav-tabs" style="margin-bottom: 20px">
<li role="presentation"{% if active_tab == 'add' %} class="active"{% endif %}><a href="{% url 'ipam:ipaddress_add' %}">Individual</a></li>
<li role="presentation"{% if active_tab == 'bulk_add' %} class="active"{% endif %}><a href="{% url 'ipam:ipaddress_bulk_add' %}">Bulk</a></li>
<li role="presentation"{% if active_tab == 'add' %} class="active"{% endif %}>
<a href="{% url 'ipam:ipaddress_add' %}{% querystring request %}">New IP</a>
</li>
{% if 'interface' in request.GET %}
<li role="presentation"{% if active_tab == 'assign' %} class="active"{% endif %}>
<a href="{% url 'ipam:ipaddress_assign' %}{% querystring request %}">Assign IP</a>
</li>
{% else %}
<li role="presentation"{% if active_tab == 'bulk_add' %} class="active"{% endif %}>
<a href="{% url 'ipam:ipaddress_bulk_add' %}{% querystring request %}">Bulk Create</a>
</li>
{% endif %}
</ul>
48 changes: 48 additions & 0 deletions netbox/templates/ipam/ipaddress_assign.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{% extends 'utilities/obj_edit.html' %}
{% load static from staticfiles %}
{% load form_helpers %}
{% load helpers %}

{% block content %}
<form action="{% querystring request %}" method="post" class="form form-horizontal">
{% csrf_token %}
{% for field in form.hidden_fields %}
{{ field }}
{% endfor %}
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h3>Assign an IP Address</h3>
{% include 'ipam/inc/ipadress_edit_header.html' with active_tab='assign' %}
{% if form.non_field_errors %}
<div class="panel panel-danger">
<div class="panel-heading"><strong>Errors</strong></div>
<div class="panel-body">
{{ form.non_field_errors }}
</div>
</div>
{% endif %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Select IP Address</strong></div>
<div class="panel-body">
{% render_field form.vrf %}
{% render_field form.address %}
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3 text-right">
<button type="submit" class="btn btn-primary">Search</button>
<a href="{{ return_url }}" class="btn btn-default">Cancel</a>
</div>
</div>
</form>
{% if table %}
<div class="row">
<div class="col-md-10 col-md-offset-1" style="margin-top: 20px">
<h3>Search Results</h3>
{% include 'utilities/obj_table.html' with table_template='panel_table.html' %}
</div>
</div>
{% endif %}
{% endblock %}
2 changes: 1 addition & 1 deletion netbox/utilities/templatetags/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit a0bb7b0

Please sign in to comment.