2021-04-20 10:22:26 +03:00
|
|
|
from django.shortcuts import get_object_or_404, render, redirect
|
|
|
|
from django.views.generic import View
|
|
|
|
from dcim.models import Device, Interface, InterfaceTemplate
|
|
|
|
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
|
|
|
|
from django.conf import settings
|
|
|
|
from django.contrib import messages
|
|
|
|
|
|
|
|
from .utils import UnifiedInterface, natural_keys
|
|
|
|
from .forms import InterfaceComparisonForm
|
|
|
|
|
|
|
|
config = settings.PLUGINS_CONFIG['netbox_interface_sync']
|
|
|
|
|
|
|
|
|
|
|
|
class InterfaceComparisonView(LoginRequiredMixin, PermissionRequiredMixin, View):
|
|
|
|
"""Comparison of interfaces between a device and a device type and beautiful visualization"""
|
|
|
|
permission_required = ("dcim.view_interface", "dcim.add_interface", "dcim.change_interface", "dcim.delete_interface")
|
|
|
|
|
|
|
|
def get(self, request, device_id):
|
|
|
|
device = get_object_or_404(Device.objects.filter(id=device_id))
|
|
|
|
interfaces = Interface.objects.filter(device=device)
|
|
|
|
if config["exclude_virtual_interfaces"]:
|
|
|
|
interfaces = list(filter(lambda i: not i.is_virtual, interfaces))
|
|
|
|
interface_templates = InterfaceTemplate.objects.filter(device_type=device.device_type)
|
|
|
|
|
|
|
|
unified_interfaces = [UnifiedInterface(i.id, i.name, i.type) for i in interfaces]
|
|
|
|
unified_interface_templates = [UnifiedInterface(i.id, i.name, i.type, is_template=True) for i in interface_templates]
|
|
|
|
|
|
|
|
# List of interfaces and interface templates presented in the unified format
|
|
|
|
overall_interfaces = list(set(unified_interface_templates + unified_interfaces))
|
|
|
|
overall_interfaces.sort(key=lambda o: natural_keys(o.name))
|
|
|
|
|
|
|
|
comparison_templates = []
|
|
|
|
comparison_interfaces = []
|
|
|
|
for i in overall_interfaces:
|
|
|
|
try:
|
|
|
|
comparison_templates.append(unified_interface_templates[unified_interface_templates.index(i)])
|
|
|
|
except ValueError:
|
|
|
|
comparison_templates.append(None)
|
|
|
|
|
|
|
|
try:
|
|
|
|
comparison_interfaces.append(unified_interfaces[unified_interfaces.index(i)])
|
|
|
|
except ValueError:
|
|
|
|
comparison_interfaces.append(None)
|
|
|
|
|
|
|
|
comparison_items = list(zip(comparison_templates, comparison_interfaces))
|
|
|
|
return render(
|
|
|
|
request, "netbox_interface_sync/interface_comparison.html",
|
|
|
|
{
|
|
|
|
"comparison_items": comparison_items,
|
|
|
|
"templates_count": len(interface_templates),
|
|
|
|
"interfaces_count": len(interfaces),
|
|
|
|
"device": device
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
def post(self, request, device_id):
|
|
|
|
form = InterfaceComparisonForm(request.POST)
|
|
|
|
if form.is_valid():
|
|
|
|
device = get_object_or_404(Device.objects.filter(id=device_id))
|
|
|
|
interfaces = Interface.objects.filter(device=device)
|
|
|
|
if config["exclude_virtual_interfaces"]:
|
|
|
|
interfaces = interfaces.exclude(type__in=["virtual", "lag"])
|
|
|
|
interface_templates = InterfaceTemplate.objects.filter(device_type=device.device_type)
|
|
|
|
|
|
|
|
# Manually validating interfaces and interface templates lists
|
|
|
|
add_to_device = filter(
|
|
|
|
lambda i: i in interface_templates.values_list("id", flat=True),
|
|
|
|
map(int, filter(lambda x: x.isdigit(), request.POST.getlist("add_to_device")))
|
|
|
|
)
|
|
|
|
remove_from_device = filter(
|
|
|
|
lambda i: i in interfaces.values_list("id", flat=True),
|
|
|
|
map(int, filter(lambda x: x.isdigit(), request.POST.getlist("remove_from_device")))
|
|
|
|
)
|
|
|
|
|
2021-04-21 20:53:55 +03:00
|
|
|
# Remove selected interfaces from the device and count them
|
|
|
|
interfaces_deleted = Interface.objects.filter(id__in=remove_from_device).delete()[0]
|
|
|
|
|
2021-04-20 10:22:26 +03:00
|
|
|
# Add selected interfaces to the device and count them
|
|
|
|
add_to_device_interfaces = InterfaceTemplate.objects.filter(id__in=add_to_device)
|
|
|
|
interfaces_created = len(Interface.objects.bulk_create([
|
|
|
|
Interface(device=device, name=i.name, type=i.type) for i in add_to_device_interfaces
|
|
|
|
]))
|
|
|
|
|
|
|
|
# Getting and validating a list of interfaces to rename
|
|
|
|
fix_name_interfaces = filter(lambda i: str(i.id) in request.POST.getlist("fix_name"), interfaces)
|
|
|
|
# Casting interface templates into UnifiedInterface objects for proper comparison with interfaces for renaming
|
|
|
|
unified_interface_templates = [UnifiedInterface(i.id, i.name, i.type) for i in interface_templates]
|
|
|
|
|
|
|
|
# Rename selected interfaces
|
|
|
|
interfaces_fixed = 0
|
|
|
|
for interface in fix_name_interfaces:
|
|
|
|
unified_interface = UnifiedInterface(interface.id, interface.name, interface.type)
|
|
|
|
try:
|
|
|
|
# Try to extract an interface template with the corresponding name
|
|
|
|
corresponding_template = unified_interface_templates[unified_interface_templates.index(unified_interface)]
|
|
|
|
interface.name = corresponding_template.name
|
|
|
|
interface.save()
|
|
|
|
interfaces_fixed += 1
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
# Generating result message
|
|
|
|
message = []
|
|
|
|
if interfaces_created > 0:
|
|
|
|
message.append(f"created {interfaces_created} interfaces")
|
|
|
|
if interfaces_deleted > 0:
|
|
|
|
message.append(f"deleted {interfaces_deleted} interfaces")
|
|
|
|
if interfaces_fixed > 0:
|
|
|
|
message.append(f"fixed {interfaces_fixed} interfaces")
|
|
|
|
messages.success(request, "; ".join(message).capitalize())
|
|
|
|
|
|
|
|
return redirect(request.path)
|