Files
Netbox-Utilities/netbox_utilities/topology_views.py
T

111 lines
3.7 KiB
Python

import logging
from django.apps import apps
from django.core.exceptions import ObjectDoesNotExist
from django.db import OperationalError, ProgrammingError
from netbox.plugins import get_plugin_config
from .rack_width import effective_width_positions
logger = logging.getLogger(__name__)
TOPOLOGY_RACK_ELEVATION_VIEW = "plugins:netbox_topology_views:rack_elevation"
def is_topology_rack_elevation_request(request):
resolver_match = getattr(request, "resolver_match", None)
return getattr(resolver_match, "view_name", None) == TOPOLOGY_RACK_ELEVATION_VIEW
def topology_rack_width_enabled(request):
"""Return whether the optional Topology Views rack integration applies."""
return bool(
is_topology_rack_elevation_request(request)
and get_plugin_config("netbox_utilities", "topology_views_rack_width_enabled")
and apps.is_installed("netbox_topology_views")
)
def serialize_topology_placement(placement):
return serialize_topology_width(
placement.device,
placement.width,
placement.horizontal_position,
source="stored",
)
def serialize_topology_width(device, width, horizontal_position, *, source):
width = int(width)
horizontal_position = int(horizontal_position)
return {
"device_id": device.pk,
"url": device.get_absolute_url(),
"width": width,
"horizontal_position": horizontal_position,
"left_percent": round((horizontal_position - 1) / width * 100, 8),
"width_percent": round(100 / width, 8),
"width_source": source,
}
def get_topology_rack_width_data(request):
"""Return permitted partial-width devices shown by Topology Views."""
if not topology_rack_width_enabled(request):
return None
data = {"devices": [], "status": "ready", "schema_version": 3, "complete": False}
if not request.GET:
return data
from dcim.models import Device, Rack
try:
racks = Rack.objects.restrict(request.user, "view")
selected_racks = request.GET.getlist("rack_id")
if selected_racks:
racks = racks.filter(pk__in=selected_racks)
else:
selected_sites = request.GET.getlist("site_id")
selected_locations = request.GET.getlist("location_id")
if selected_sites:
racks = racks.filter(site_id__in=selected_sites)
if selected_locations:
racks = racks.filter(location_id__in=selected_locations)
devices = list(
Device.objects.restrict(request.user, "view")
.filter(
rack_id__in=racks.values("pk"),
position__gt=0,
device_type__u_height__gt=0,
)
.select_related("device_type", "netbox_utilities_rack_placement")
.order_by("rack_id", "face", "position", "pk")
)
widths = effective_width_positions(devices)
data["devices"] = [
serialize_topology_width(device, width, position, source=source)
for device in devices
for width, position, source in (widths[device.pk],)
if width > 1
]
data["complete"] = True
return data
except (
AttributeError,
ObjectDoesNotExist,
OperationalError,
ProgrammingError,
TypeError,
ValueError,
):
# Keep NetBox usable while plugin migrations are being installed.
logger.warning(
"Could not load partial rack widths for NetBox Topology Views path %s; using its native rack layout",
request.get_full_path(),
exc_info=True,
)
data["status"] = "native-fallback"
return data