1445 lines
50 KiB
Python
1445 lines
50 KiB
Python
import re
|
|
|
|
from django.conf import settings
|
|
from django.contrib import messages
|
|
from django.contrib.auth.decorators import permission_required
|
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
|
from django.core.urlresolvers import reverse
|
|
from django.db.models import Count, ProtectedError
|
|
from django.http import HttpResponseRedirect
|
|
from django.shortcuts import get_object_or_404, redirect, render
|
|
from django.utils.http import urlencode
|
|
|
|
from django_tables2 import RequestConfig
|
|
from extras.models import ExportTemplate
|
|
from utilities.error_handlers import handle_protectederror
|
|
from utilities.forms import ConfirmationForm
|
|
from utilities.paginator import EnhancedPaginator
|
|
from utilities.views import ObjectListView, BulkImportView, BulkEditView, BulkDeleteView
|
|
from ipam.models import Prefix, IPAddress, VLAN
|
|
from circuits.models import Circuit
|
|
|
|
from .filters import RackFilter, DeviceFilter, ConsoleConnectionFilter, PowerConnectionFilter, InterfaceConnectionFilter
|
|
from .forms import SiteForm, SiteImportForm, RackForm, RackImportForm, RackBulkEditForm, RackBulkDeleteForm, \
|
|
RackFilterForm, DeviceForm, DeviceImportForm, DeviceBulkEditForm, DeviceBulkDeleteForm, DeviceFilterForm, \
|
|
ConsolePortForm, ConsolePortCreateForm, ConsolePortConnectionForm, ConsoleConnectionImportForm, \
|
|
ConsoleServerPortForm, ConsoleServerPortCreateForm, ConsoleServerPortConnectionForm, PowerPortForm, \
|
|
PowerPortCreateForm, PowerPortConnectionForm, PowerConnectionImportForm, PowerOutletForm, PowerOutletCreateForm, \
|
|
PowerOutletConnectionForm, InterfaceForm, InterfaceCreateForm, InterfaceBulkCreateForm, InterfaceConnectionForm, \
|
|
InterfaceConnectionDeletionForm, InterfaceConnectionImportForm, ConsoleConnectionFilterForm, \
|
|
PowerConnectionFilterForm, InterfaceConnectionFilterForm, IPAddressForm
|
|
from .models import Site, Rack, Device, ConsolePort, ConsoleServerPort, PowerPort, \
|
|
PowerOutlet, Interface, InterfaceConnection, Module, CONNECTION_STATUS_CONNECTED
|
|
from .tables import SiteTable, RackTable, RackBulkEditTable, DeviceTable, DeviceBulkEditTable, DeviceImportTable, \
|
|
ConsoleConnectionTable, PowerConnectionTable, InterfaceConnectionTable
|
|
|
|
|
|
EXPANSION_PATTERN = '\[(\d+-\d+)\]'
|
|
|
|
|
|
def xstr(s):
|
|
"""
|
|
Replace None with an empty string (for CSV export)
|
|
"""
|
|
return '' if s is None else str(s)
|
|
|
|
|
|
def expand_pattern(string):
|
|
"""
|
|
Expand a numeric pattern into a list of strings. Examples:
|
|
'ge-0/0/[0-3]' => ['ge-0/0/0', 'ge-0/0/1', 'ge-0/0/2', 'ge-0/0/3']
|
|
'xe-0/[0-3]/[0-7]' => ['xe-0/0/0', 'xe-0/0/1', 'xe-0/0/2', ... 'xe-0/3/5', 'xe-0/3/6', 'xe-0/3/7']
|
|
"""
|
|
lead, pattern, remnant = re.split(EXPANSION_PATTERN, string, maxsplit=1)
|
|
x, y = pattern.split('-')
|
|
for i in range(int(x), int(y) + 1):
|
|
if remnant:
|
|
for string in expand_pattern(remnant):
|
|
yield "{0}{1}{2}".format(lead, i, string)
|
|
else:
|
|
yield "{0}{1}".format(lead, i)
|
|
|
|
|
|
#
|
|
# Sites
|
|
#
|
|
|
|
def site_list(request):
|
|
|
|
queryset = Site.objects.all()
|
|
|
|
# Export
|
|
if 'export' in request.GET:
|
|
et = get_object_or_404(ExportTemplate, content_type__model='site', name=request.GET.get('export'))
|
|
response = et.to_response(context_dict={'queryset': queryset}, filename='netbox_sites')
|
|
return response
|
|
|
|
site_table = SiteTable(queryset)
|
|
RequestConfig(request, paginate={'per_page': settings.PAGINATE_COUNT, 'klass': EnhancedPaginator}).configure(site_table)
|
|
|
|
export_templates = ExportTemplate.objects.filter(content_type__model='site')
|
|
|
|
return render(request, 'dcim/site_list.html', {
|
|
'site_table': site_table,
|
|
'export_templates': export_templates,
|
|
})
|
|
|
|
|
|
def site(request, slug):
|
|
|
|
site = get_object_or_404(Site, slug=slug)
|
|
stats = {
|
|
'rack_count': Rack.objects.filter(site=site).count(),
|
|
'device_count': Device.objects.filter(rack__site=site).count(),
|
|
'prefix_count': Prefix.objects.filter(site=site).count(),
|
|
'vlan_count': VLAN.objects.filter(site=site).count(),
|
|
'circuit_count': Circuit.objects.filter(site=site).count(),
|
|
}
|
|
|
|
return render(request, 'dcim/site.html', {
|
|
'site': site,
|
|
'stats': stats,
|
|
})
|
|
|
|
|
|
@permission_required('dcim.add_site')
|
|
def site_add(request):
|
|
|
|
if request.method == 'POST':
|
|
form = SiteForm(request.POST)
|
|
if form.is_valid():
|
|
site = form.save()
|
|
messages.success(request, "Added new site: {0}".format(site.name))
|
|
if '_addanother' in request.POST:
|
|
return redirect('dcim:site_add')
|
|
else:
|
|
return redirect('dcim:site', slug=site.slug)
|
|
|
|
else:
|
|
form = SiteForm()
|
|
|
|
return render(request, 'dcim/site_edit.html', {
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:site_list'),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_site')
|
|
def site_edit(request, slug):
|
|
|
|
site = get_object_or_404(Site, slug=slug)
|
|
|
|
if request.method == 'POST':
|
|
form = SiteForm(request.POST, instance=site)
|
|
if form.is_valid():
|
|
site = form.save()
|
|
messages.success(request, "Modified site {0}".format(site.name))
|
|
return redirect('dcim:site', slug=site.slug)
|
|
|
|
else:
|
|
form = SiteForm(instance=site)
|
|
|
|
return render(request, 'dcim/site_edit.html', {
|
|
'site': site,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:site', kwargs={'slug': site.slug}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.delete_site')
|
|
def site_delete(request, slug):
|
|
|
|
site = get_object_or_404(Site, slug=slug)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
try:
|
|
site.delete()
|
|
messages.success(request, "Site {0} has been deleted".format(site))
|
|
return redirect('dcim:site_list')
|
|
except ProtectedError, e:
|
|
handle_protectederror(site, request, e)
|
|
return redirect('dcim:site', slug=site.slug)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/site_delete.html', {
|
|
'site': site,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:site', kwargs={'slug': site.slug}),
|
|
})
|
|
|
|
|
|
class SiteBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|
permission_required = 'dcim.add_site'
|
|
form = SiteImportForm
|
|
table = SiteTable
|
|
template_name = 'dcim/site_import.html'
|
|
obj_list_url = 'dcim:site_list'
|
|
|
|
|
|
#
|
|
# Racks
|
|
#
|
|
|
|
def rack_list(request):
|
|
|
|
queryset = Rack.objects.select_related('site').annotate(device_count=Count('devices', distinct=True))
|
|
queryset = RackFilter(request.GET, queryset).qs
|
|
|
|
# Export
|
|
if 'export' in request.GET:
|
|
et = get_object_or_404(ExportTemplate, content_type__model='rack', name=request.GET.get('export'))
|
|
response = et.to_response(context_dict={'queryset': queryset}, filename='netbox_racks')
|
|
return response
|
|
|
|
# Hot-wire direct to rack view if only one rack was returned
|
|
if queryset.count() == 1:
|
|
return redirect('dcim:rack', pk=queryset[0].pk)
|
|
|
|
if request.user.has_perm('dcim.change_rack') or request.user.has_perm('dcim.delete_rack'):
|
|
rack_table = RackBulkEditTable(queryset)
|
|
else:
|
|
rack_table = RackTable(queryset)
|
|
RequestConfig(request, paginate={'per_page': settings.PAGINATE_COUNT, 'klass': EnhancedPaginator}).configure(rack_table)
|
|
|
|
export_templates = ExportTemplate.objects.filter(content_type__model='rack')
|
|
|
|
return render(request, 'dcim/rack_list.html', {
|
|
'rack_table': rack_table,
|
|
'export_templates': export_templates,
|
|
'filter_form': RackFilterForm(request.GET, label_suffix=''),
|
|
})
|
|
|
|
|
|
def rack(request, pk):
|
|
|
|
rack = get_object_or_404(Rack, pk=pk)
|
|
|
|
nonracked_devices = Device.objects.filter(rack=rack, position__isnull=True)
|
|
try:
|
|
next_rack = Rack.objects.filter(site=rack.site, name__gt=rack.name).order_by('name')[0]
|
|
except IndexError:
|
|
next_rack = None
|
|
try:
|
|
prev_rack = Rack.objects.filter(site=rack.site, name__lt=rack.name).order_by('-name')[0]
|
|
except IndexError:
|
|
prev_rack = None
|
|
|
|
return render(request, 'dcim/rack.html', {
|
|
'rack': rack,
|
|
'nonracked_devices': nonracked_devices,
|
|
'next_rack': next_rack,
|
|
'prev_rack': prev_rack,
|
|
'front_elevation': rack.get_front_elevation(),
|
|
'rear_elevation': rack.get_rear_elevation(),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.add_rack')
|
|
def rack_add(request):
|
|
|
|
if request.method == 'POST':
|
|
form = RackForm(request.POST)
|
|
if form.is_valid():
|
|
rack = form.save()
|
|
messages.success(request, "Added new rack to {}: {}".format(rack.site.name, rack))
|
|
if '_addanother' in request.POST:
|
|
base_url = reverse('dcim:rack_add')
|
|
params = urlencode({
|
|
'site': rack.site.pk,
|
|
})
|
|
return HttpResponseRedirect('{}?{}'.format(base_url, params))
|
|
else:
|
|
return redirect('dcim:rack', pk=rack.pk)
|
|
|
|
else:
|
|
form = RackForm()
|
|
|
|
return render(request, 'dcim/rack_edit.html', {
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:rack_list'),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_rack')
|
|
def rack_edit(request, pk):
|
|
|
|
rack = get_object_or_404(Rack, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = RackForm(request.POST, instance=rack)
|
|
if form.is_valid():
|
|
rack = form.save()
|
|
messages.success(request, "Modified rack {0}".format(rack.name))
|
|
return redirect('dcim:rack', pk=rack.pk)
|
|
|
|
else:
|
|
form = RackForm(instance=rack)
|
|
|
|
return render(request, 'dcim/rack_edit.html', {
|
|
'rack': rack,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:rack', kwargs={'pk': rack.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.delete_rack')
|
|
def rack_delete(request, pk):
|
|
|
|
rack = get_object_or_404(Rack, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
try:
|
|
rack.delete()
|
|
messages.success(request, "Rack {0} has been deleted".format(rack))
|
|
return redirect('dcim:rack_list')
|
|
except ProtectedError, e:
|
|
handle_protectederror(rack, request, e)
|
|
return redirect('dcim:rack', pk=rack.pk)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/rack_delete.html', {
|
|
'rack': rack,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:rack', kwargs={'pk': rack.pk}),
|
|
})
|
|
|
|
|
|
class RackBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|
permission_required = 'dcim.add_rack'
|
|
form = RackImportForm
|
|
table = RackTable
|
|
template_name = 'dcim/rack_import.html'
|
|
obj_list_url = 'dcim:rack_list'
|
|
|
|
|
|
class RackBulkEditView(PermissionRequiredMixin, BulkEditView):
|
|
permission_required = 'dcim.change_rack'
|
|
cls = Rack
|
|
form = RackBulkEditForm
|
|
template_name = 'dcim/rack_bulk_edit.html'
|
|
redirect_url = 'dcim:rack_list'
|
|
|
|
def update_objects(self, pk_list, form):
|
|
|
|
fields_to_update = {}
|
|
for field in ['site', 'group', 'u_height', 'comments']:
|
|
if form.cleaned_data[field]:
|
|
fields_to_update[field] = form.cleaned_data[field]
|
|
|
|
updated_count = self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
|
messages.success(self.request, "Updated {} racks".format(updated_count))
|
|
|
|
|
|
class RackBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|
permission_required = 'dcim.delete_rack'
|
|
cls = Rack
|
|
form = RackBulkDeleteForm
|
|
template_name = 'dcim/rack_bulk_delete.html'
|
|
redirect_url = 'dcim:rack_list'
|
|
|
|
|
|
#
|
|
# Devices
|
|
#
|
|
|
|
def device_list(request):
|
|
|
|
queryset = Device.objects.select_related('device_type', 'device_type__manufacturer', 'device_role', 'rack', 'rack__site', 'primary_ip')
|
|
queryset = DeviceFilter(request.GET, queryset).qs
|
|
|
|
# Export
|
|
if 'export' in request.GET:
|
|
et = get_object_or_404(ExportTemplate, content_type__model='device', name=request.GET.get('export'))
|
|
response = et.to_response(context_dict={'queryset': queryset}, filename='netbox_devices')
|
|
return response
|
|
|
|
# Hot-wire direct to device view if only one device was returned
|
|
if queryset.count() == 1:
|
|
return redirect('dcim:device', pk=queryset[0].pk)
|
|
|
|
if request.user.has_perm('dcim.change_device') or request.user.has_perm('dcim.delete_device'):
|
|
device_table = DeviceBulkEditTable(queryset)
|
|
else:
|
|
device_table = DeviceTable(queryset)
|
|
RequestConfig(request, paginate={'per_page': settings.PAGINATE_COUNT, 'klass': EnhancedPaginator}).configure(device_table)
|
|
|
|
export_templates = ExportTemplate.objects.filter(content_type__model='device')
|
|
|
|
return render(request, 'dcim/device_list.html', {
|
|
'device_table': device_table,
|
|
'export_templates': export_templates,
|
|
'filter_form': DeviceFilterForm(request.GET, label_suffix=''),
|
|
})
|
|
|
|
|
|
def device(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
console_ports = ConsolePort.objects.filter(device=device).select_related('cs_port__device')
|
|
cs_ports = ConsoleServerPort.objects.filter(device=device).select_related('connected_console')
|
|
power_ports = PowerPort.objects.filter(device=device).select_related('power_outlet__device')
|
|
power_outlets = PowerOutlet.objects.filter(device=device).select_related('connected_port')
|
|
interfaces = Interface.objects.filter(device=device, mgmt_only=False).select_related('connected_as_a', 'connected_as_b', 'circuit')
|
|
mgmt_interfaces = Interface.objects.filter(device=device, mgmt_only=True).select_related('connected_as_a', 'connected_as_b', 'circuit')
|
|
|
|
# Gather any secrets which belong to this device
|
|
secrets = device.secrets.all()
|
|
|
|
# Find all IP addresses assigned to this device
|
|
ip_addresses = IPAddress.objects.filter(interface__device=device).select_related('interface').order_by('interface')
|
|
|
|
# Find any related devices for convenient linking in the UI
|
|
related_devices = []
|
|
if device.name:
|
|
if re.match('.+[0-9]+$', device.name):
|
|
# Strip 1 or more trailing digits (e.g. core-switch1)
|
|
base_name = re.match('(.*?)[0-9]+$', device.name).group(1)
|
|
elif re.match('.+\d[a-z]+$', device.name.lower()):
|
|
# Strip a trailing letter if preceded by a digit (e.g. dist-switch3a -> dist-switch3)
|
|
base_name = re.match('(.*\d+)[a-z]$', device.name.lower()).group(1)
|
|
else:
|
|
base_name = None
|
|
if base_name:
|
|
related_devices = Device.objects.filter(name__istartswith=base_name).exclude(pk=device.pk).select_related('rack', 'device_type__manufacturer')[:10]
|
|
|
|
return render(request, 'dcim/device.html', {
|
|
'device': device,
|
|
'console_ports': console_ports,
|
|
'cs_ports': cs_ports,
|
|
'power_ports': power_ports,
|
|
'power_outlets': power_outlets,
|
|
'interfaces': interfaces,
|
|
'mgmt_interfaces': mgmt_interfaces,
|
|
'ip_addresses': ip_addresses,
|
|
'secrets': secrets,
|
|
'related_devices': related_devices,
|
|
})
|
|
|
|
|
|
@permission_required('dcim.add_device')
|
|
def device_add(request):
|
|
|
|
if request.method == 'POST':
|
|
form = DeviceForm(request.POST)
|
|
if form.is_valid():
|
|
device = form.save()
|
|
messages.success(request, "Added new device: {0} ({1})".format(device.name, device.device_type))
|
|
if '_addanother' in request.POST:
|
|
base_url = reverse('dcim:device_add')
|
|
params = urlencode({
|
|
'site': device.rack.site.pk,
|
|
'rack': device.rack.pk,
|
|
})
|
|
return HttpResponseRedirect('{}?{}'.format(base_url, params))
|
|
else:
|
|
return redirect('dcim:device', pk=device.pk)
|
|
|
|
else:
|
|
initial_data = {}
|
|
if request.GET.get('rack', None):
|
|
try:
|
|
rack = Rack.objects.get(pk=request.GET.get('rack', None))
|
|
initial_data['rack'] = rack.pk
|
|
initial_data['site'] = rack.site.pk
|
|
initial_data['position'] = request.GET.get('position')
|
|
initial_data['face'] = request.GET.get('face')
|
|
except Rack.DoesNotExist:
|
|
pass
|
|
form = DeviceForm(initial=initial_data)
|
|
|
|
return render(request, 'dcim/device_edit.html', {
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device_list'),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_device')
|
|
def device_edit(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = DeviceForm(request.POST, instance=device)
|
|
if form.is_valid():
|
|
device = form.save()
|
|
messages.success(request, "Modified device {0}".format(device.name))
|
|
return redirect('dcim:device', pk=device.pk)
|
|
|
|
else:
|
|
form = DeviceForm(instance=device)
|
|
|
|
return render(request, 'dcim/device_edit.html', {
|
|
'device': device,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.delete_device')
|
|
def device_delete(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
try:
|
|
device.delete()
|
|
messages.success(request, "Device {0} has been deleted".format(device))
|
|
return redirect('dcim:device_list')
|
|
except ProtectedError, e:
|
|
handle_protectederror(device, request, e)
|
|
return redirect('dcim:device', pk=device.pk)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/device_delete.html', {
|
|
'device': device,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': device.pk}),
|
|
})
|
|
|
|
|
|
class DeviceBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|
permission_required = 'dcim.add_device'
|
|
form = DeviceImportForm
|
|
table = DeviceImportTable
|
|
template_name = 'dcim/device_import.html'
|
|
obj_list_url = 'dcim:device_list'
|
|
|
|
|
|
class DeviceBulkEditView(PermissionRequiredMixin, BulkEditView):
|
|
permission_required = 'dcim.change_device'
|
|
cls = Device
|
|
form = DeviceBulkEditForm
|
|
template_name = 'dcim/device_bulk_edit.html'
|
|
redirect_url = 'dcim:device_list'
|
|
|
|
def update_objects(self, pk_list, form):
|
|
|
|
fields_to_update = {}
|
|
if form.cleaned_data['platform']:
|
|
fields_to_update['platform'] = form.cleaned_data['platform']
|
|
elif form.cleaned_data['platform_delete']:
|
|
fields_to_update['platform'] = None
|
|
if form.cleaned_data['status']:
|
|
status = form.cleaned_data['status']
|
|
fields_to_update['status'] = True if status == 'True' else False
|
|
for field in ['device_type', 'device_role', 'serial', 'ro_snmp']:
|
|
if form.cleaned_data[field]:
|
|
fields_to_update[field] = form.cleaned_data[field]
|
|
|
|
updated_count = self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
|
messages.success(self.request, "Updated {} devices".format(updated_count))
|
|
|
|
|
|
class DeviceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|
permission_required = 'dcim.delete_device'
|
|
cls = Device
|
|
form = DeviceBulkDeleteForm
|
|
template_name = 'dcim/device_bulk_delete.html'
|
|
redirect_url = 'dcim:device_list'
|
|
|
|
|
|
def device_inventory(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
modules = Module.objects.filter(device=device)
|
|
|
|
return render(request, 'dcim/device_inventory.html', {
|
|
'device': device,
|
|
'modules': modules,
|
|
})
|
|
|
|
|
|
def device_lldp_neighbors(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
interfaces = Interface.objects.filter(device=device).select_related('connected_as_a', 'connected_as_b')
|
|
|
|
return render(request, 'dcim/device_lldp_neighbors.html', {
|
|
'device': device,
|
|
'interfaces': interfaces,
|
|
})
|
|
|
|
|
|
#
|
|
# Console ports
|
|
#
|
|
|
|
@permission_required('dcim.add_consoleport')
|
|
def consoleport_add(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConsolePortCreateForm(request.POST)
|
|
if form.is_valid():
|
|
|
|
console_ports = []
|
|
for name in form.cleaned_data['name_pattern']:
|
|
cp_form = ConsolePortForm({
|
|
'device': device.pk,
|
|
'name': name,
|
|
})
|
|
if cp_form.is_valid():
|
|
console_ports.append(cp_form.save(commit=False))
|
|
else:
|
|
form.add_error('name_pattern', "Duplicate console port name for this device: {}".format(name))
|
|
|
|
if not form.errors:
|
|
ConsolePort.objects.bulk_create(console_ports)
|
|
messages.success(request, "Added {} console port(s) to {}".format(len(console_ports), device))
|
|
if '_addanother' in request.POST:
|
|
return redirect('dcim:consoleport_add', pk=device.pk)
|
|
else:
|
|
return redirect('dcim:device', pk=device.pk)
|
|
|
|
else:
|
|
form = ConsolePortCreateForm()
|
|
|
|
return render(request, 'dcim/consoleport_edit.html', {
|
|
'device': device,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_consoleport')
|
|
def consoleport_connect(request, pk):
|
|
|
|
consoleport = get_object_or_404(ConsolePort, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConsolePortConnectionForm(request.POST, instance=consoleport)
|
|
if form.is_valid():
|
|
consoleport = form.save()
|
|
messages.success(request, "Connected {0} {1} to {2} {3}".format(
|
|
consoleport.device,
|
|
consoleport.name,
|
|
consoleport.cs_port.device,
|
|
consoleport.cs_port.name,
|
|
))
|
|
return redirect('dcim:device', pk=consoleport.device.pk)
|
|
|
|
else:
|
|
form = ConsolePortConnectionForm(instance=consoleport, initial={
|
|
'rack': consoleport.device.rack,
|
|
'connection_status': CONNECTION_STATUS_CONNECTED,
|
|
})
|
|
|
|
return render(request, 'dcim/consoleport_connect.html', {
|
|
'consoleport': consoleport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': consoleport.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_consoleport')
|
|
def consoleport_disconnect(request, pk):
|
|
|
|
consoleport = get_object_or_404(ConsolePort, pk=pk)
|
|
|
|
if not consoleport.cs_port:
|
|
messages.warning(request, "Cannot disconnect console port {0}: It is not connected to anything".format(consoleport))
|
|
return redirect('dcim:device', pk=consoleport.device.pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
consoleport.cs_port = None
|
|
consoleport.connection_status = None
|
|
consoleport.save()
|
|
messages.success(request, "Console port {0} has been disconnected".format(consoleport))
|
|
return redirect('dcim:device', pk=consoleport.device.pk)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/consoleport_disconnect.html', {
|
|
'consoleport': consoleport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': consoleport.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_consoleport')
|
|
def consoleport_edit(request, pk):
|
|
|
|
consoleport = get_object_or_404(ConsolePort, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConsolePortForm(request.POST, instance=consoleport)
|
|
if form.is_valid():
|
|
consoleport = form.save()
|
|
messages.success(request, "Modified {0} {1}".format(consoleport.device.name, consoleport.name))
|
|
return redirect('dcim:device', pk=consoleport.device.pk)
|
|
|
|
else:
|
|
form = ConsolePortForm(instance=consoleport)
|
|
|
|
return render(request, 'dcim/consoleport_edit.html', {
|
|
'consoleport': consoleport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': consoleport.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.delete_consoleport')
|
|
def consoleport_delete(request, pk):
|
|
|
|
consoleport = get_object_or_404(ConsolePort, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
consoleport.delete()
|
|
messages.success(request, "Console port {0} has been deleted from {1}".format(consoleport, consoleport.device))
|
|
return redirect('dcim:device', pk=consoleport.device.pk)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/consoleport_delete.html', {
|
|
'consoleport': consoleport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': consoleport.device.pk}),
|
|
})
|
|
|
|
|
|
class ConsoleConnectionsBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|
permission_required = 'dcim.change_consoleport'
|
|
form = ConsoleConnectionImportForm
|
|
table = ConsoleConnectionTable
|
|
template_name = 'dcim/console_connections_import.html'
|
|
|
|
|
|
#
|
|
# Console server ports
|
|
#
|
|
|
|
@permission_required('dcim.add_consoleserverport')
|
|
def consoleserverport_add(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConsoleServerPortCreateForm(request.POST)
|
|
if form.is_valid():
|
|
|
|
cs_ports = []
|
|
for name in form.cleaned_data['name_pattern']:
|
|
csp_form = ConsoleServerPortForm({
|
|
'device': device.pk,
|
|
'name': name,
|
|
})
|
|
if csp_form.is_valid():
|
|
cs_ports.append(csp_form.save(commit=False))
|
|
else:
|
|
form.add_error('name_pattern', "Duplicate console server port name for this device: {}"
|
|
.format(name))
|
|
|
|
if not form.errors:
|
|
ConsoleServerPort.objects.bulk_create(cs_ports)
|
|
messages.success(request, "Added {} console server port(s) to {}".format(len(cs_ports), device))
|
|
if '_addanother' in request.POST:
|
|
return redirect('dcim:consoleserverport_add', pk=device.pk)
|
|
else:
|
|
return redirect('dcim:device', pk=device.pk)
|
|
|
|
else:
|
|
form = ConsoleServerPortCreateForm()
|
|
|
|
return render(request, 'dcim/consoleserverport_edit.html', {
|
|
'device': device,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_consoleserverport')
|
|
def consoleserverport_connect(request, pk):
|
|
|
|
consoleserverport = get_object_or_404(ConsoleServerPort, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConsoleServerPortConnectionForm(consoleserverport, request.POST)
|
|
if form.is_valid():
|
|
consoleport = form.cleaned_data['port']
|
|
consoleport.cs_port = consoleserverport
|
|
consoleport.connection_status = form.cleaned_data['connection_status']
|
|
consoleport.save()
|
|
messages.success(request, "Connected {0} {1} to {2} {3}".format(
|
|
consoleport.device,
|
|
consoleport.name,
|
|
consoleserverport.device,
|
|
consoleserverport.name,
|
|
))
|
|
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
|
|
|
else:
|
|
form = ConsoleServerPortConnectionForm(consoleserverport, initial={'rack': consoleserverport.device.rack})
|
|
|
|
return render(request, 'dcim/consoleserverport_connect.html', {
|
|
'consoleserverport': consoleserverport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': consoleserverport.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_consoleserverport')
|
|
def consoleserverport_disconnect(request, pk):
|
|
|
|
consoleserverport = get_object_or_404(ConsoleServerPort, pk=pk)
|
|
|
|
if not hasattr(consoleserverport, 'connected_console'):
|
|
messages.warning(request, "Cannot disconnect console server port {0}: Nothing is connected to it".format(consoleserverport))
|
|
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
consoleport = consoleserverport.connected_console
|
|
consoleport.cs_port = None
|
|
consoleport.connection_status = None
|
|
consoleport.save()
|
|
messages.success(request, "Console server port {0} has been disconnected".format(consoleserverport))
|
|
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/consoleserverport_disconnect.html', {
|
|
'consoleserverport': consoleserverport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': consoleserverport.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_consoleserverport')
|
|
def consoleserverport_edit(request, pk):
|
|
|
|
consoleserverport = get_object_or_404(ConsoleServerPort, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConsoleServerPortForm(request.POST, instance=consoleserverport)
|
|
if form.is_valid():
|
|
consoleserverport = form.save()
|
|
messages.success(request, "Modified {0} {1}".format(consoleserverport.device.name, consoleserverport.name))
|
|
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
|
|
|
else:
|
|
form = ConsoleServerPortForm(instance=consoleserverport)
|
|
|
|
return render(request, 'dcim/consoleserverport_edit.html', {
|
|
'consoleserverport': consoleserverport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': consoleserverport.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.delete_consoleserverport')
|
|
def consoleserverport_delete(request, pk):
|
|
|
|
consoleserverport = get_object_or_404(ConsoleServerPort, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
consoleserverport.delete()
|
|
messages.success(request, "Console server port {0} has been deleted from {1}".format(consoleserverport, consoleserverport.device))
|
|
return redirect('dcim:device', pk=consoleserverport.device.pk)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/consoleserverport_delete.html', {
|
|
'consoleserverport': consoleserverport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': consoleserverport.device.pk}),
|
|
})
|
|
|
|
|
|
#
|
|
# Power ports
|
|
#
|
|
|
|
@permission_required('dcim.add_powerport')
|
|
def powerport_add(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = PowerPortCreateForm(request.POST)
|
|
if form.is_valid():
|
|
|
|
power_ports = []
|
|
for name in form.cleaned_data['name_pattern']:
|
|
pp_form = PowerPortForm({
|
|
'device': device.pk,
|
|
'name': name,
|
|
})
|
|
if pp_form.is_valid():
|
|
power_ports.append(pp_form.save(commit=False))
|
|
else:
|
|
form.add_error('name_pattern', "Duplicate power port name for this device: {}".format(name))
|
|
|
|
if not form.errors:
|
|
PowerPort.objects.bulk_create(power_ports)
|
|
messages.success(request, "Added {} power port(s) to {}".format(len(power_ports), device))
|
|
if '_addanother' in request.POST:
|
|
return redirect('dcim:powerport_add', pk=device.pk)
|
|
else:
|
|
return redirect('dcim:device', pk=device.pk)
|
|
|
|
else:
|
|
form = PowerPortCreateForm()
|
|
|
|
return render(request, 'dcim/powerport_edit.html', {
|
|
'device': device,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_powerport')
|
|
def powerport_connect(request, pk):
|
|
|
|
powerport = get_object_or_404(PowerPort, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = PowerPortConnectionForm(request.POST, instance=powerport)
|
|
if form.is_valid():
|
|
powerport = form.save()
|
|
messages.success(request, "Connected {0} {1} to {2} {3}".format(
|
|
powerport.device,
|
|
powerport.name,
|
|
powerport.power_outlet.device,
|
|
powerport.power_outlet.name,
|
|
))
|
|
return redirect('dcim:device', pk=powerport.device.pk)
|
|
|
|
else:
|
|
form = PowerPortConnectionForm(instance=powerport, initial={
|
|
'rack': powerport.device.rack,
|
|
'connection_status': CONNECTION_STATUS_CONNECTED,
|
|
})
|
|
|
|
return render(request, 'dcim/powerport_connect.html', {
|
|
'powerport': powerport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': powerport.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_powerport')
|
|
def powerport_disconnect(request, pk):
|
|
|
|
powerport = get_object_or_404(PowerPort, pk=pk)
|
|
|
|
if not powerport.power_outlet:
|
|
messages.warning(request, "Cannot disconnect power port {0}: It is not connected to an outlet".format(powerport))
|
|
return redirect('dcim:device', pk=powerport.device.pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
powerport.power_outlet = None
|
|
powerport.connection_status = None
|
|
powerport.save()
|
|
messages.success(request, "Power port {0} has been disconnected".format(powerport))
|
|
return redirect('dcim:device', pk=powerport.device.pk)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/powerport_disconnect.html', {
|
|
'powerport': powerport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': powerport.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_powerport')
|
|
def powerport_edit(request, pk):
|
|
|
|
powerport = get_object_or_404(PowerPort, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = PowerPortForm(request.POST, instance=powerport)
|
|
if form.is_valid():
|
|
powerport = form.save()
|
|
messages.success(request, "Modified {0} power port {1}".format(powerport.device.name, powerport.name))
|
|
return redirect('dcim:device', pk=powerport.device.pk)
|
|
|
|
else:
|
|
form = PowerPortForm(instance=powerport)
|
|
|
|
return render(request, 'dcim/powerport_edit.html', {
|
|
'powerport': powerport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': powerport.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.delete_powerport')
|
|
def powerport_delete(request, pk):
|
|
|
|
powerport = get_object_or_404(PowerPort, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
powerport.delete()
|
|
messages.success(request, "Power port {0} has been deleted from {1}".format(powerport, powerport.device))
|
|
return redirect('dcim:device', pk=powerport.device.pk)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/powerport_delete.html', {
|
|
'powerport': powerport,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': powerport.device.pk}),
|
|
})
|
|
|
|
|
|
class PowerConnectionsBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|
permission_required = 'dcim.change_powerport'
|
|
form = PowerConnectionImportForm
|
|
table = PowerConnectionTable
|
|
template_name = 'dcim/power_connections_import.html'
|
|
|
|
|
|
#
|
|
# Power outlets
|
|
#
|
|
|
|
@permission_required('dcim.add_poweroutlet')
|
|
def poweroutlet_add(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = PowerOutletCreateForm(request.POST)
|
|
if form.is_valid():
|
|
|
|
power_outlets = []
|
|
for name in form.cleaned_data['name_pattern']:
|
|
po_form = PowerOutletForm({
|
|
'device': device.pk,
|
|
'name': name,
|
|
})
|
|
if po_form.is_valid():
|
|
power_outlets.append(po_form.save(commit=False))
|
|
else:
|
|
form.add_error('name_pattern', "Duplicate power outlet name for this device: {}".format(name))
|
|
|
|
if not form.errors:
|
|
PowerOutlet.objects.bulk_create(power_outlets)
|
|
messages.success(request, "Added {} power outlet(s) to {}".format(len(power_outlets), device))
|
|
if '_addanother' in request.POST:
|
|
return redirect('dcim:poweroutlet_add', pk=device.pk)
|
|
else:
|
|
return redirect('dcim:device', pk=device.pk)
|
|
|
|
else:
|
|
form = PowerOutletCreateForm()
|
|
|
|
return render(request, 'dcim/poweroutlet_edit.html', {
|
|
'device': device,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_poweroutlet')
|
|
def poweroutlet_connect(request, pk):
|
|
|
|
poweroutlet = get_object_or_404(PowerOutlet, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = PowerOutletConnectionForm(poweroutlet, request.POST)
|
|
if form.is_valid():
|
|
powerport = form.cleaned_data['port']
|
|
powerport.power_outlet = poweroutlet
|
|
powerport.connection_status = form.cleaned_data['connection_status']
|
|
powerport.save()
|
|
messages.success(request, "Connected {0} {1} to {2} {3}".format(
|
|
powerport.device,
|
|
powerport.name,
|
|
poweroutlet.device,
|
|
poweroutlet.name,
|
|
))
|
|
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
|
|
|
else:
|
|
form = PowerOutletConnectionForm(poweroutlet, initial={'rack': poweroutlet.device.rack})
|
|
|
|
return render(request, 'dcim/poweroutlet_connect.html', {
|
|
'poweroutlet': poweroutlet,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': poweroutlet.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_poweroutlet')
|
|
def poweroutlet_disconnect(request, pk):
|
|
|
|
poweroutlet = get_object_or_404(PowerOutlet, pk=pk)
|
|
|
|
if not hasattr(poweroutlet, 'connected_port'):
|
|
messages.warning(request, "Cannot disconnectpower outlet {0}: Nothing is connected to it".format(poweroutlet))
|
|
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
powerport = poweroutlet.connected_port
|
|
powerport.power_outlet = None
|
|
powerport.connection_status = None
|
|
powerport.save()
|
|
messages.success(request, "Power outlet {0} has been disconnected".format(poweroutlet))
|
|
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/poweroutlet_disconnect.html', {
|
|
'poweroutlet': poweroutlet,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': poweroutlet.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_poweroutlet')
|
|
def poweroutlet_edit(request, pk):
|
|
|
|
poweroutlet = get_object_or_404(PowerOutlet, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = PowerOutletForm(request.POST, instance=poweroutlet)
|
|
if form.is_valid():
|
|
poweroutlet = form.save()
|
|
messages.success(request, "Modified {0} power outlet {1}".format(poweroutlet.device.name, poweroutlet.name))
|
|
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
|
|
|
else:
|
|
form = PowerOutletForm(instance=poweroutlet)
|
|
|
|
return render(request, 'dcim/poweroutlet_edit.html', {
|
|
'poweroutlet': poweroutlet,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': poweroutlet.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.delete_poweroutlet')
|
|
def poweroutlet_delete(request, pk):
|
|
|
|
poweroutlet = get_object_or_404(PowerOutlet, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
poweroutlet.delete()
|
|
messages.success(request, "Power outlet {0} has been deleted from {1}".format(poweroutlet, poweroutlet.device))
|
|
return redirect('dcim:device', pk=poweroutlet.device.pk)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/poweroutlet_delete.html', {
|
|
'poweroutlet': poweroutlet,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': poweroutlet.device.pk}),
|
|
})
|
|
|
|
|
|
#
|
|
# Interfaces
|
|
#
|
|
|
|
@permission_required('dcim.add_interface')
|
|
def interface_add(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = InterfaceCreateForm(request.POST)
|
|
if form.is_valid():
|
|
|
|
interfaces = []
|
|
for name in form.cleaned_data['name_pattern']:
|
|
iface_form = InterfaceForm({
|
|
'device': device.pk,
|
|
'name': name,
|
|
'form_factor': form.cleaned_data['form_factor'],
|
|
'mgmt_only': form.cleaned_data['mgmt_only'],
|
|
'description': form.cleaned_data['description'],
|
|
})
|
|
if iface_form.is_valid():
|
|
interfaces.append(iface_form.save(commit=False))
|
|
else:
|
|
form.add_error('name_pattern', "Duplicate interface name for this device: {}".format(name))
|
|
|
|
if not form.errors:
|
|
Interface.objects.bulk_create(interfaces)
|
|
messages.success(request, "Added {} interface(s) to {}".format(len(interfaces), device))
|
|
if '_addanother' in request.POST:
|
|
return redirect('dcim:interface_add', pk=device.pk)
|
|
else:
|
|
return redirect('dcim:device', pk=device.pk)
|
|
|
|
else:
|
|
form = InterfaceCreateForm()
|
|
|
|
return render(request, 'dcim/interface_edit.html', {
|
|
'device': device,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.change_interface')
|
|
def interface_edit(request, pk):
|
|
|
|
interface = get_object_or_404(Interface, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = InterfaceForm(request.POST, instance=interface)
|
|
if form.is_valid():
|
|
interface = form.save()
|
|
messages.success(request, "Modified {0} interface {1}".format(interface.device.name, interface.name))
|
|
return redirect('dcim:device', pk=interface.device.pk)
|
|
|
|
else:
|
|
form = InterfaceForm(instance=interface)
|
|
|
|
return render(request, 'dcim/interface_edit.html', {
|
|
'interface': interface,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': interface.device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.delete_interface')
|
|
def interface_delete(request, pk):
|
|
|
|
interface = get_object_or_404(Interface, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = ConfirmationForm(request.POST)
|
|
if form.is_valid():
|
|
interface.delete()
|
|
messages.success(request, "Interface {0} has been deleted from {1}".format(interface, interface.device))
|
|
return redirect('dcim:device', pk=interface.device.pk)
|
|
|
|
else:
|
|
form = ConfirmationForm()
|
|
|
|
return render(request, 'dcim/interface_delete.html', {
|
|
'interface': interface,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': interface.device.pk}),
|
|
})
|
|
|
|
|
|
class InterfaceBulkAddView(PermissionRequiredMixin, BulkEditView):
|
|
permission_required = 'dcim.add_interface'
|
|
cls = Device
|
|
form = InterfaceBulkCreateForm
|
|
template_name = 'dcim/interface_bulk_add.html'
|
|
redirect_url = 'dcim:device_list'
|
|
|
|
def update_objects(self, pk_list, form):
|
|
|
|
selected_devices = Device.objects.filter(pk__in=pk_list)
|
|
interfaces = []
|
|
|
|
for device in selected_devices:
|
|
for name in form.cleaned_data['name_pattern']:
|
|
iface_form = InterfaceForm({
|
|
'device': device.pk,
|
|
'name': name,
|
|
'form_factor': form.cleaned_data['form_factor'],
|
|
'mgmt_only': form.cleaned_data['mgmt_only'],
|
|
'description': form.cleaned_data['description'],
|
|
})
|
|
if iface_form.is_valid():
|
|
interfaces.append(iface_form.save(commit=False))
|
|
else:
|
|
form.add_error(None, "Duplicate interface {} found for device {}".format(name, device))
|
|
|
|
if not form.errors:
|
|
Interface.objects.bulk_create(interfaces)
|
|
messages.success(self.request, "Added {} interfaces to {} devices".format(len(interfaces),
|
|
len(selected_devices)))
|
|
|
|
|
|
#
|
|
# Interface connections
|
|
#
|
|
|
|
@permission_required('dcim.add_interfaceconnection')
|
|
def interfaceconnection_add(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = InterfaceConnectionForm(device, request.POST)
|
|
if form.is_valid():
|
|
interfaceconnection = form.save()
|
|
messages.success(request, "Connected {0} {1} to {2} {3}".format(
|
|
interfaceconnection.interface_a.device,
|
|
interfaceconnection.interface_a,
|
|
interfaceconnection.interface_b.device,
|
|
interfaceconnection.interface_b,
|
|
))
|
|
if '_addanother' in request.POST:
|
|
base_url = reverse('dcim:interfaceconnection_add', kwargs={'pk': device.pk})
|
|
params = urlencode({
|
|
'rack_b': interfaceconnection.interface_b.device.rack.pk,
|
|
'device_b': interfaceconnection.interface_b.device.pk,
|
|
})
|
|
return HttpResponseRedirect('{}?{}'.format(base_url, params))
|
|
else:
|
|
return redirect('dcim:device', pk=device.pk)
|
|
|
|
else:
|
|
form = InterfaceConnectionForm(device, initial={
|
|
'interface_a': request.GET.get('interface', None),
|
|
'rack_b': request.GET.get('rack_b', None),
|
|
'device_b': request.GET.get('device_b', None),
|
|
})
|
|
|
|
return render(request, 'dcim/interfaceconnection_edit.html', {
|
|
'device': device,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': device.pk}),
|
|
})
|
|
|
|
|
|
@permission_required('dcim.delete_interfaceconnection')
|
|
def interfaceconnection_delete(request, pk):
|
|
|
|
interfaceconnection = get_object_or_404(InterfaceConnection, pk=pk)
|
|
device_id = request.GET.get('device', None)
|
|
|
|
if request.method == 'POST':
|
|
form = InterfaceConnectionDeletionForm(request.POST)
|
|
if form.is_valid():
|
|
interfaceconnection.delete()
|
|
messages.success(request, "Deleted the connection between {0} {1} and {2} {3}".format(
|
|
interfaceconnection.interface_a.device,
|
|
interfaceconnection.interface_a,
|
|
interfaceconnection.interface_b.device,
|
|
interfaceconnection.interface_b,
|
|
))
|
|
if form.cleaned_data['device']:
|
|
return redirect('dcim:device', pk=form.cleaned_data['device'].pk)
|
|
else:
|
|
return redirect('dcim:device_list')
|
|
|
|
else:
|
|
form = InterfaceConnectionDeletionForm(initial={
|
|
'device': device_id,
|
|
})
|
|
|
|
# Determine where to direct user upon cancellation
|
|
if device_id:
|
|
cancel_url = reverse('dcim:device', kwargs={'pk': device_id})
|
|
else:
|
|
cancel_url = reverse('dcim:device_list')
|
|
|
|
return render(request, 'dcim/interfaceconnection_delete.html', {
|
|
'interfaceconnection': interfaceconnection,
|
|
'device_id': device_id,
|
|
'form': form,
|
|
'cancel_url': cancel_url,
|
|
})
|
|
|
|
|
|
class InterfaceConnectionsBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|
permission_required = 'dcim.change_interface'
|
|
form = InterfaceConnectionImportForm
|
|
table = InterfaceConnectionTable
|
|
template_name = 'dcim/interface_connections_import.html'
|
|
|
|
|
|
#
|
|
# Connections
|
|
#
|
|
|
|
class ConsoleConnectionsListView(ObjectListView):
|
|
queryset = ConsolePort.objects.select_related('device', 'cs_port__device').filter(cs_port__isnull=False)\
|
|
.order_by('cs_port__device__name', 'cs_port__name')
|
|
filter = ConsoleConnectionFilter
|
|
filter_form = ConsoleConnectionFilterForm
|
|
table = ConsoleConnectionTable
|
|
template_name = 'dcim/console_connections_list.html'
|
|
|
|
|
|
class PowerConnectionsListView(ObjectListView):
|
|
queryset = PowerPort.objects.select_related('device', 'power_outlet__device').filter(power_outlet__isnull=False)\
|
|
.order_by('power_outlet__device__name', 'power_outlet__name')
|
|
filter = PowerConnectionFilter
|
|
filter_form = PowerConnectionFilterForm
|
|
table = PowerConnectionTable
|
|
template_name = 'dcim/power_connections_list.html'
|
|
|
|
|
|
class InterfaceConnectionsListView(ObjectListView):
|
|
queryset = InterfaceConnection.objects.select_related('interface_a__device', 'interface_b__device')\
|
|
.order_by('interface_a__device__name', 'interface_a__name')
|
|
filter = InterfaceConnectionFilter
|
|
filter_form = InterfaceConnectionFilterForm
|
|
table = InterfaceConnectionTable
|
|
template_name = 'dcim/interface_connections_list.html'
|
|
|
|
|
|
#
|
|
# IP addresses
|
|
#
|
|
|
|
@permission_required('ipam.add_ipaddress')
|
|
def ipaddress_assign(request, pk):
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
|
|
if request.method == 'POST':
|
|
form = IPAddressForm(device, request.POST)
|
|
if form.is_valid():
|
|
|
|
ipaddress = form.save(commit=False)
|
|
ipaddress.interface = form.cleaned_data['interface']
|
|
ipaddress.save()
|
|
messages.success(request, "Added new IP address {0} to interface {1}".format(ipaddress, ipaddress.interface))
|
|
|
|
if form.cleaned_data['set_as_primary']:
|
|
device.primary_ip = ipaddress
|
|
device.save()
|
|
|
|
if '_addanother' in request.POST:
|
|
return redirect('dcim:ipaddress_assign', pk=device.pk)
|
|
else:
|
|
return redirect('dcim:device', pk=device.pk)
|
|
|
|
else:
|
|
form = IPAddressForm(device)
|
|
|
|
return render(request, 'dcim/ipaddress_assign.html', {
|
|
'device': device,
|
|
'form': form,
|
|
'cancel_url': reverse('dcim:device', kwargs={'pk': device.pk}),
|
|
})
|