mirror of
https://github.com/drygdryg/netbox-plugin-interface-sync
synced 2024-11-25 18:10:52 +03:00
Fix comparison for every get. Changed signature in centralized get
This commit is contained in:
parent
b6bdbf9028
commit
80112869e0
@ -3,30 +3,39 @@ from dataclasses import dataclass
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ParentComparison:
|
||||
"""Common fields of a device component"""
|
||||
|
||||
id: int
|
||||
name: str
|
||||
label: str
|
||||
description: str
|
||||
|
||||
def __eq__(self, other):
|
||||
# Ignore some fields when comparing; ignore interface name case and whitespaces
|
||||
return self.name.lower().replace(" ", "") == other.name.lower().replace(" ", "")
|
||||
return (
|
||||
(self.name.lower().replace(" ", "") == other.name.lower().replace(" ", ""))
|
||||
and (self.label == other.label)
|
||||
and (self.description == other.description)
|
||||
)
|
||||
|
||||
def __hash__(self):
|
||||
# Ignore some fields when hashing; ignore interface name case and whitespaces
|
||||
return hash(self.name.lower().replace(" ", ""))
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ParentTypedComparison(ParentComparison):
|
||||
"""Common fields of a device typed component"""
|
||||
|
||||
type: str
|
||||
type_display: str
|
||||
|
||||
def __eq__(self, other):
|
||||
# Ignore some fields when comparing; ignore interface name case and whitespaces
|
||||
return (
|
||||
self.name.lower().replace(" ", "") == other.name.lower().replace(" ", "")
|
||||
) and (self.type == other.type)
|
||||
(self.name.lower().replace(" ", "") == other.name.lower().replace(" ", ""))
|
||||
and (self.label == other.label)
|
||||
and (self.description == other.description)
|
||||
and (self.type == other.type)
|
||||
)
|
||||
|
||||
def __hash__(self):
|
||||
# Ignore some fields when hashing; ignore interface name case and whitespaces
|
||||
@ -34,28 +43,78 @@ class ParentTypedComparison(ParentComparison):
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiedInterface:
|
||||
class InterfaceComparison(ParentTypedComparison):
|
||||
"""A unified way to represent the interface and interface template"""
|
||||
|
||||
id: int
|
||||
name: str
|
||||
type: str = ""
|
||||
type_display: str = ""
|
||||
mgmt_only: bool
|
||||
is_template: bool = False
|
||||
|
||||
def __eq__(self, other):
|
||||
# Ignore some fields when comparing; ignore interface name case and whitespaces
|
||||
return (
|
||||
self.name.lower().replace(" ", "") == other.name.lower().replace(" ", "")
|
||||
) and (self.type == other.type)
|
||||
|
||||
def __hash__(self):
|
||||
# Ignore some fields when hashing; ignore interface name case and whitespaces
|
||||
return hash((self.name.lower().replace(" ", ""), self.type))
|
||||
(self.name.lower().replace(" ", "") == other.name.lower().replace(" ", ""))
|
||||
and (self.label == other.label)
|
||||
and (self.description == other.description)
|
||||
and (self.type == other.type)
|
||||
and (self.mgmt_only == other.mgmt_only)
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ComparisonPowerOutlet(ParentTypedComparison):
|
||||
class FrontPortComparison(ParentTypedComparison):
|
||||
"""A unified way to represent the front port and front port template"""
|
||||
|
||||
color: str
|
||||
rearports: str
|
||||
is_template: bool = False
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RearPortComparison(ParentTypedComparison):
|
||||
"""A unified way to represent the rear port and rear port template"""
|
||||
|
||||
color: str
|
||||
positions: str
|
||||
is_template: bool = False
|
||||
|
||||
|
||||
@dataclass(frozen=True, eq=False)
|
||||
class ConsolePortComparison(ParentTypedComparison):
|
||||
"""A unified way to represent the consoleport and consoleport template"""
|
||||
|
||||
is_template: bool = False
|
||||
|
||||
|
||||
@dataclass(frozen=True, eq=False)
|
||||
class ConsoleServerPortComparison(ParentTypedComparison):
|
||||
"""A unified way to represent the consoleserverport and consoleserverport template"""
|
||||
|
||||
is_template: bool = False
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PowerPortComparison(ParentTypedComparison):
|
||||
"""A unified way to represent the power port and power port template"""
|
||||
|
||||
maximum_draw: str
|
||||
allocated_draw: str
|
||||
is_template: bool = False
|
||||
|
||||
def __eq__(self, other):
|
||||
# Ignore some fields when comparing; ignore interface name case and whitespaces
|
||||
return (
|
||||
(self.name.lower().replace(" ", "") == other.name.lower().replace(" ", ""))
|
||||
and (self.label == other.label)
|
||||
and (self.description == other.description)
|
||||
and (self.type == other.type)
|
||||
and (self.maximum_draw == other.maximum_draw)
|
||||
and (self.allocated_draw == other.allocated_draw)
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PowerOutletComparison(ParentTypedComparison):
|
||||
"""A unified way to represent the power outlet and power outlet template"""
|
||||
|
||||
power_port_name: str = ""
|
||||
feed_leg: str = ""
|
||||
@ -77,3 +136,31 @@ class ComparisonPowerOutlet(ParentTypedComparison):
|
||||
return hash(
|
||||
(self.name.lower().replace(" ", ""), self.type, self.power_port_name)
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True, eq=False)
|
||||
class DeviceBayComparison(ParentComparison):
|
||||
"""A unified way to represent the interface and interface template"""
|
||||
|
||||
is_template: bool = False
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnifiedInterface:
|
||||
"""A unified way to represent the interface and interface template"""
|
||||
|
||||
id: int
|
||||
name: str
|
||||
type: str = ""
|
||||
type_display: str = ""
|
||||
is_template: bool = False
|
||||
|
||||
def __eq__(self, other):
|
||||
# Ignore some fields when comparing; ignore interface name case and whitespaces
|
||||
return (
|
||||
self.name.lower().replace(" ", "") == other.name.lower().replace(" ", "")
|
||||
) and (self.type == other.type)
|
||||
|
||||
def __hash__(self):
|
||||
# Ignore some fields when hashing; ignore interface name case and whitespaces
|
||||
return hash((self.name.lower().replace(" ", ""), self.type))
|
||||
|
@ -2,11 +2,12 @@ import re
|
||||
from typing import Iterable
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib import messages
|
||||
from .comparison import UnifiedInterface, ComparisonPowerOutlet
|
||||
from .comparison import UnifiedInterface
|
||||
|
||||
|
||||
def split(s):
|
||||
for x, y in re.findall(r'(\d*)(\D*)', s):
|
||||
yield '', int(x or '0')
|
||||
for x, y in re.findall(r"(\d*)(\D*)", s):
|
||||
yield "", int(x or "0")
|
||||
yield y, 0
|
||||
|
||||
|
||||
@ -17,18 +18,19 @@ def natural_keys(c):
|
||||
def human_sorted(iterable: Iterable):
|
||||
return sorted(iterable, key=natural_keys)
|
||||
|
||||
def get_components(request, device, components, component_templates):
|
||||
try:
|
||||
unified_components = [UnifiedInterface(i.id, i.name, i.type, i.get_type_display()) for i in components]
|
||||
except AttributeError:
|
||||
unified_components = [UnifiedInterface(i.id, i.name) for i in components]
|
||||
|
||||
try:
|
||||
unified_component_templates = [
|
||||
UnifiedInterface(i.id, i.name, i.type, i.get_type_display(), is_template=True) for i in component_templates]
|
||||
except AttributeError:
|
||||
unified_component_templates = [
|
||||
UnifiedInterface(i.id, i.name, is_template=True) for i in component_templates]
|
||||
def get_components(request, device, components, unified_components, unified_component_templates):
|
||||
# try:
|
||||
# unified_components = [UnifiedInterface(i.id, i.name, i.type, i.get_type_display()) for i in components]
|
||||
# except AttributeError:
|
||||
# unified_components = [UnifiedInterface(i.id, i.name) for i in components]
|
||||
|
||||
# try:
|
||||
# unified_component_templates = [
|
||||
# UnifiedInterface(i.id, i.name, i.type, i.get_type_display(), is_template=True) for i in component_templates]
|
||||
# except AttributeError:
|
||||
# unified_component_templates = [
|
||||
# UnifiedInterface(i.id, i.name, is_template=True) for i in component_templates]
|
||||
|
||||
# List of interfaces and interface templates presented in the unified format
|
||||
overall_powers = list(set(unified_component_templates + unified_components))
|
||||
@ -38,35 +40,46 @@ def get_components(request, device, components, component_templates):
|
||||
comparison_interfaces = []
|
||||
for i in overall_powers:
|
||||
try:
|
||||
comparison_templates.append(unified_component_templates[unified_component_templates.index(i)])
|
||||
comparison_templates.append(
|
||||
unified_component_templates[unified_component_templates.index(i)]
|
||||
)
|
||||
except ValueError:
|
||||
comparison_templates.append(None)
|
||||
|
||||
try:
|
||||
comparison_interfaces.append(unified_components[unified_components.index(i)])
|
||||
comparison_interfaces.append(
|
||||
unified_components[unified_components.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",
|
||||
request,
|
||||
"netbox_interface_sync/interface_comparison.html",
|
||||
{
|
||||
"comparison_items": comparison_items,
|
||||
"templates_count": len(unified_component_templates),
|
||||
"interfaces_count": len(components),
|
||||
"device": device
|
||||
}
|
||||
"device": device,
|
||||
},
|
||||
)
|
||||
|
||||
def post_components(request, device, components, component_templates, ObjectType, ObjectTemplateType):
|
||||
|
||||
def post_components(
|
||||
request, device, components, component_templates, ObjectType, ObjectTemplateType
|
||||
):
|
||||
# Manually validating interfaces and interface templates lists
|
||||
add_to_device = filter(
|
||||
lambda i: i in component_templates.values_list("id", flat=True),
|
||||
map(int, filter(lambda x: x.isdigit(), request.POST.getlist("add_to_device")))
|
||||
map(int, filter(lambda x: x.isdigit(), request.POST.getlist("add_to_device"))),
|
||||
)
|
||||
remove_from_device = filter(
|
||||
lambda i: i in components.values_list("id", flat=True),
|
||||
map(int, filter(lambda x: x.isdigit(), request.POST.getlist("remove_from_device")))
|
||||
map(
|
||||
int,
|
||||
filter(lambda x: x.isdigit(), request.POST.getlist("remove_from_device")),
|
||||
),
|
||||
)
|
||||
|
||||
# Remove selected interfaces from the device and count them
|
||||
@ -89,26 +102,38 @@ def post_components(request, device, components, component_templates, ObjectType
|
||||
created = len(ObjectType.objects.bulk_create(bulk_create))
|
||||
|
||||
# Getting and validating a list of interfaces to rename
|
||||
fix_name_components = filter(lambda i: str(i.id) in request.POST.getlist("fix_name"), components)
|
||||
fix_name_components = filter(
|
||||
lambda i: str(i.id) in request.POST.getlist("fix_name"), components
|
||||
)
|
||||
# Casting interface templates into UnifiedInterface objects for proper comparison with interfaces for renaming
|
||||
try:
|
||||
unified_component_templates = [
|
||||
UnifiedInterface(i.id, i.name, i.type, i.get_type_display()) for i in component_templates]
|
||||
UnifiedInterface(i.id, i.name, i.type, i.get_type_display())
|
||||
for i in component_templates
|
||||
]
|
||||
except AttributeError:
|
||||
unified_component_templates = [
|
||||
UnifiedInterface(i.id, i.name) for i in component_templates]
|
||||
UnifiedInterface(i.id, i.name) for i in component_templates
|
||||
]
|
||||
|
||||
# Rename selected interfaces
|
||||
fixed = 0
|
||||
for component in fix_name_components:
|
||||
try:
|
||||
unified_component = UnifiedInterface(component.id, component.name, component.type, component.get_type_display())
|
||||
unified_component = UnifiedInterface(
|
||||
component.id,
|
||||
component.name,
|
||||
component.type,
|
||||
component.get_type_display(),
|
||||
)
|
||||
except AttributeError:
|
||||
unified_component = UnifiedInterface(component.id, component.name)
|
||||
|
||||
try:
|
||||
# Try to extract an interface template with the corresponding name
|
||||
corresponding_template = unified_component_templates[unified_component_templates.index(unified_component)]
|
||||
corresponding_template = unified_component_templates[
|
||||
unified_component_templates.index(unified_component)
|
||||
]
|
||||
component.name = corresponding_template.name
|
||||
component.save()
|
||||
fixed += 1
|
||||
|
@ -8,7 +8,7 @@ from django.conf import settings
|
||||
from django.contrib import messages
|
||||
|
||||
from .utils import natural_keys, get_components, post_components
|
||||
from .comparison import ComparisonPowerOutlet, UnifiedInterface
|
||||
from .comparison import PowerPortComparison, PowerOutletComparison, InterfaceComparison, ConsolePortComparison, ConsoleServerPortComparison, DeviceBayComparison
|
||||
from .forms import InterfaceComparisonForm
|
||||
|
||||
config = settings.PLUGINS_CONFIG['netbox_interface_sync']
|
||||
@ -25,7 +25,11 @@ class InterfaceComparisonView(LoginRequiredMixin, PermissionRequiredMixin, View)
|
||||
interfaces = list(filter(lambda i: not i.is_virtual, interfaces))
|
||||
interface_templates = InterfaceTemplate.objects.filter(device_type=device.device_type)
|
||||
|
||||
return get_components(request, device, interfaces, interface_templates)
|
||||
unified_interfaces = [InterfaceComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), i.mgmt_only) for i in interfaces]
|
||||
unified_interface_templates = [
|
||||
InterfaceComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), i.mgmt_only, is_template=True) for i in interface_templates]
|
||||
|
||||
return get_components(request, device, interfaces, unified_interfaces, unified_interface_templates)
|
||||
|
||||
def post(self, request, device_id):
|
||||
form = InterfaceComparisonForm(request.POST)
|
||||
@ -47,8 +51,12 @@ class PowerPortComparisonView(LoginRequiredMixin, PermissionRequiredMixin, View)
|
||||
|
||||
powerports = device.powerports.all()
|
||||
powerports_templates = PowerPortTemplate.objects.filter(device_type=device.device_type)
|
||||
|
||||
unified_powerports = [PowerPortComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), i.maximum_draw, i.allocated_draw) for i in powerports]
|
||||
unified_powerport_templates = [
|
||||
PowerPortComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), i.maximum_draw, i.allocated_draw, is_template=True) for i in powerports_templates]
|
||||
|
||||
return get_components(request, device, powerports, powerports_templates)
|
||||
return get_components(request, device, powerports, unified_powerports, unified_powerport_templates)
|
||||
|
||||
def post(self, request, device_id):
|
||||
form = InterfaceComparisonForm(request.POST)
|
||||
@ -70,7 +78,11 @@ class ConsolePortComparisonView(LoginRequiredMixin, PermissionRequiredMixin, Vie
|
||||
consoleports = device.consoleports.all()
|
||||
consoleports_templates = ConsolePortTemplate.objects.filter(device_type=device.device_type)
|
||||
|
||||
return get_components(request, device, consoleports, consoleports_templates)
|
||||
unified_consoleports = [ConsolePortComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display()) for i in consoleports]
|
||||
unified_consoleport_templates = [
|
||||
ConsolePortComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), is_template=True) for i in consoleports_templates]
|
||||
|
||||
return get_components(request, device, consoleports, unified_consoleports, unified_consoleport_templates)
|
||||
|
||||
def post(self, request, device_id):
|
||||
form = InterfaceComparisonForm(request.POST)
|
||||
@ -92,7 +104,11 @@ class ConsoleServerPortComparisonView(LoginRequiredMixin, PermissionRequiredMixi
|
||||
consoleserverports = device.consoleserverports.all()
|
||||
consoleserverports_templates = ConsoleServerPortTemplate.objects.filter(device_type=device.device_type)
|
||||
|
||||
return get_components(request, device, consoleserverports, consoleserverports_templates)
|
||||
unified_consoleserverports = [ConsoleServerPortComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display()) for i in consoleserverports]
|
||||
unified_consoleserverport_templates = [
|
||||
ConsoleServerPortComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), is_template=True) for i in consoleserverports_templates]
|
||||
|
||||
return get_components(request, device, consoleserverports, unified_consoleserverports, unified_consoleserverport_templates)
|
||||
|
||||
def post(self, request, device_id):
|
||||
form = InterfaceComparisonForm(request.POST)
|
||||
@ -114,38 +130,11 @@ class PowerOutletComparisonView(LoginRequiredMixin, PermissionRequiredMixin, Vie
|
||||
poweroutlets = device.poweroutlets.all()
|
||||
poweroutlets_templates = PowerOutletTemplate.objects.filter(device_type=device.device_type)
|
||||
|
||||
|
||||
unified_components = [ComparisonPowerOutlet(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), power_port_name=PowerPort.objects.get(id=i.power_port_id).name if i.power_port_id is not None else "", feed_leg=i.feed_leg) for i in poweroutlets]
|
||||
unified_component_templates = [
|
||||
ComparisonPowerOutlet(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), power_port_name=PowerPortTemplate.objects.get(id=i.power_port_id).name if i.power_port_id is not None else "", feed_leg=i.feed_leg, is_template=True) for i in poweroutlets_templates]
|
||||
unified_poweroutlets = [PowerOutletComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), power_port_name=PowerPort.objects.get(id=i.power_port_id).name if i.power_port_id is not None else "", feed_leg=i.feed_leg) for i in poweroutlets]
|
||||
unified_poweroutlet_templates = [
|
||||
PowerOutletComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), power_port_name=PowerPortTemplate.objects.get(id=i.power_port_id).name if i.power_port_id is not None else "", feed_leg=i.feed_leg, is_template=True) for i in poweroutlets_templates]
|
||||
|
||||
# List of interfaces and interface templates presented in the unified format
|
||||
overall_powers = list(set(unified_component_templates + unified_components))
|
||||
overall_powers.sort(key=lambda o: natural_keys(o.name))
|
||||
|
||||
comparison_templates = []
|
||||
comparison_interfaces = []
|
||||
for i in overall_powers:
|
||||
try:
|
||||
comparison_templates.append(unified_component_templates[unified_component_templates.index(i)])
|
||||
except ValueError:
|
||||
comparison_templates.append(None)
|
||||
|
||||
try:
|
||||
comparison_interfaces.append(unified_components[unified_components.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(unified_component_templates),
|
||||
"interfaces_count": len(poweroutlets),
|
||||
"device": device
|
||||
}
|
||||
)
|
||||
return get_components(request, device, poweroutlets, unified_poweroutlets, unified_poweroutlet_templates)
|
||||
|
||||
def post(self, request, device_id):
|
||||
form = InterfaceComparisonForm(request.POST)
|
||||
@ -234,12 +223,12 @@ class PowerOutletComparisonView(LoginRequiredMixin, PermissionRequiredMixin, Vie
|
||||
|
||||
# Casting interface templates into UnifiedInterface objects for proper comparison with interfaces for renaming
|
||||
unified_component_templates = [
|
||||
ComparisonPowerOutlet(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), power_port_name=PowerPortTemplate.objects.get(id=i.power_port_id).name if i.power_port_id is not None else "", feed_leg=i.feed_leg, is_template=True) for i in poweroutlets_templates]
|
||||
PowerOutletComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), power_port_name=PowerPortTemplate.objects.get(id=i.power_port_id).name if i.power_port_id is not None else "", feed_leg=i.feed_leg, is_template=True) for i in poweroutlets_templates]
|
||||
|
||||
# Rename selected interfaces
|
||||
fixed = 0
|
||||
for component in fix_name_components:
|
||||
unified_component = [ComparisonPowerOutlet(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), power_port_name=PowerPort.objects.get(id=i.power_port_id).name if i.power_port_id is not None else "", feed_leg=i.feed_leg) for i in poweroutlets]
|
||||
unified_component = [PowerOutletComparison(i.id, i.name, i.label, i.description, i.type, i.get_type_display(), power_port_name=PowerPort.objects.get(id=i.power_port_id).name if i.power_port_id is not None else "", feed_leg=i.feed_leg) for i in poweroutlets]
|
||||
|
||||
try:
|
||||
# Try to extract an interface template with the corresponding name
|
||||
@ -318,8 +307,12 @@ class DeviceBayComparisonView(LoginRequiredMixin, PermissionRequiredMixin, View)
|
||||
|
||||
devicebays = device.devicebays.all()
|
||||
devicebays_templates = DeviceBayTemplate.objects.filter(device_type=device.device_type)
|
||||
|
||||
return get_components(request, device, devicebays, devicebays_templates)
|
||||
|
||||
unified_devicebays = [DeviceBayComparison(i.id, i.name, i.label, i.description) for i in devicebays]
|
||||
unified_devicebay_templates = [
|
||||
DeviceBayComparison(i.id, i.name, i.label, i.description, is_template=True) for i in devicebays_templates]
|
||||
|
||||
return get_components(request, device, devicebays, unified_devicebays, unified_devicebay_templates)
|
||||
|
||||
def post(self, request, device_id):
|
||||
form = InterfaceComparisonForm(request.POST)
|
||||
|
Loading…
Reference in New Issue
Block a user