1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00
Files
netbox-community-netbox/netbox/dcim/api/views.py

611 lines
19 KiB
Python
Raw Normal View History

from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema, OpenApiParameter
from rest_framework.decorators import action
2016-03-01 11:23:03 -05:00
from rest_framework.response import Response
from rest_framework.routers import APIRootView
from rest_framework.viewsets import ViewSet
2016-03-01 11:23:03 -05:00
2021-04-29 16:38:56 -04:00
from dcim import filtersets
2022-06-27 15:53:34 -04:00
from dcim.constants import CABLE_TRACE_SVG_DEFAULT_WIDTH
from dcim.models import *
2022-07-07 12:48:44 -04:00
from dcim.svg import CableTraceSVG
from extras.api.mixins import ConfigContextQuerySetMixin, RenderConfigMixin
from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired
from netbox.api.metadata import ContentTypeMetadata
from netbox.api.pagination import StripCountAnnotationsPaginator
from netbox.api.viewsets import NetBoxModelViewSet, MPTTLockedMixin
from netbox.api.viewsets.mixins import SequentialBulkCreatesMixin
from utilities.api import get_serializer_for_model
from utilities.query_functions import CollateAsChar
2016-08-22 13:20:30 -04:00
from . import serializers
from .exceptions import MissingFilterException
2016-03-01 11:23:03 -05:00
class DCIMRootView(APIRootView):
"""
DCIM API root view
"""
def get_view_name(self):
return 'DCIM'
# Mixins
2020-10-02 14:54:16 -04:00
class PathEndpointMixin(object):
@action(detail=True, url_path='trace')
def trace(self, request, pk):
"""
Trace a complete cable path and return each segment as a three-tuple of (termination, cable, termination).
"""
2020-06-29 14:41:43 -04:00
obj = get_object_or_404(self.queryset, pk=pk)
# Initialize the path array
path = []
2022-07-07 12:48:44 -04:00
# Render SVG image if requested
if request.GET.get('render', None) == 'svg':
try:
2022-06-27 15:53:34 -04:00
width = int(request.GET.get('width', CABLE_TRACE_SVG_DEFAULT_WIDTH))
except (ValueError, TypeError):
2022-06-27 15:53:34 -04:00
width = CABLE_TRACE_SVG_DEFAULT_WIDTH
drawing = CableTraceSVG(obj, base_url=request.build_absolute_uri('/'), width=width)
2022-07-07 12:48:44 -04:00
return HttpResponse(drawing.render().tostring(), content_type='image/svg+xml')
2022-07-07 12:48:44 -04:00
# Serialize path objects, iterating over each three-tuple in the path
for near_ends, cable, far_ends in obj.trace():
if near_ends:
serializer_a = get_serializer_for_model(near_ends[0])
near_ends = serializer_a(near_ends, nested=True, many=True, context={'request': request}).data
2022-07-07 12:48:44 -04:00
else:
# Path is split; stop here
2020-10-08 14:01:47 -04:00
break
if cable:
2022-07-07 12:48:44 -04:00
cable = serializers.TracedCableSerializer(cable[0], context={'request': request}).data
if far_ends:
serializer_b = get_serializer_for_model(far_ends[0])
far_ends = serializer_b(far_ends, nested=True, many=True, context={'request': request}).data
path.append((near_ends, cable, far_ends))
return Response(path)
class PassThroughPortMixin(object):
@action(detail=True, url_path='paths')
def paths(self, request, pk):
"""
Return all CablePaths which traverse a given pass-through port.
"""
obj = get_object_or_404(self.queryset, pk=pk)
cablepaths = CablePath.objects.filter(_nodes__contains=obj)
serializer = serializers.CablePathSerializer(cablepaths, context={'request': request}, many=True)
return Response(serializer.data)
2017-02-28 16:10:53 -05:00
#
# Regions
#
class RegionViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = Region.objects.add_related_count(
Region.objects.all(),
Site,
'region',
'site_count',
cumulative=True
)
2017-02-28 16:10:53 -05:00
serializer_class = serializers.RegionSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.RegionFilterSet
2017-02-28 16:10:53 -05:00
#
# Site groups
#
class SiteGroupViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = SiteGroup.objects.add_related_count(
SiteGroup.objects.all(),
Site,
'group',
'site_count',
cumulative=True
)
serializer_class = serializers.SiteGroupSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.SiteGroupFilterSet
2016-03-01 11:23:03 -05:00
#
# Sites
#
class SiteViewSet(NetBoxModelViewSet):
queryset = Site.objects.all()
2016-05-18 16:02:53 -04:00
serializer_class = serializers.SiteSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.SiteFilterSet
2016-03-01 11:23:03 -05:00
#
# Locations
2016-03-01 11:23:03 -05:00
#
class LocationViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = Location.objects.add_related_count(
2021-04-05 11:04:12 -04:00
Location.objects.add_related_count(
Location.objects.all(),
Device,
'location',
'device_count',
cumulative=True
),
Rack,
'location',
'rack_count',
cumulative=True
)
serializer_class = serializers.LocationSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.LocationFilterSet
2016-03-01 11:23:03 -05:00
2016-08-10 11:52:27 -04:00
#
# Rack roles
#
class RackRoleViewSet(NetBoxModelViewSet):
queryset = RackRole.objects.all()
2016-08-10 11:52:27 -04:00
serializer_class = serializers.RackRoleSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.RackRoleFilterSet
2016-08-10 11:52:27 -04:00
2016-03-01 11:23:03 -05:00
#
# Racks
#
class RackViewSet(NetBoxModelViewSet):
queryset = Rack.objects.all()
serializer_class = serializers.RackSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.RackFilterSet
2016-03-01 11:23:03 -05:00
@extend_schema(
operation_id='dcim_racks_elevation_retrieve',
filters=False,
parameters=[serializers.RackElevationDetailFilterSerializer],
responses={200: serializers.RackUnitSerializer(many=True)}
)
2019-12-10 03:18:10 -05:00
@action(detail=True)
def elevation(self, request, pk=None):
"""
Rack elevation representing the list of rack units. Also supports rendering the elevation as an SVG.
"""
2020-06-29 14:41:43 -04:00
rack = get_object_or_404(self.queryset, pk=pk)
2019-12-11 09:45:08 -05:00
serializer = serializers.RackElevationDetailFilterSerializer(data=request.GET)
if not serializer.is_valid():
return Response(serializer.errors, 400)
data = serializer.validated_data
if data['render'] == 'svg':
# Determine attributes for highlighting devices (if any)
highlight_params = []
for param in request.GET.getlist('highlight'):
try:
highlight_params.append(param.split(':', 1))
except ValueError:
pass
2019-12-11 13:39:10 -05:00
# Render and return the elevation as an SVG drawing with the correct content type
drawing = rack.get_elevation_svg(
face=data['face'],
user=request.user,
unit_width=data['unit_width'],
unit_height=data['unit_height'],
legend_width=data['legend_width'],
include_images=data['include_images'],
base_url=request.build_absolute_uri('/'),
highlight_params=highlight_params
)
2019-12-10 03:18:10 -05:00
return HttpResponse(drawing.tostring(), content_type='image/svg+xml')
else:
2019-12-11 13:39:10 -05:00
# Return a JSON representation of the rack units in the elevation
2019-12-11 09:45:08 -05:00
elevation = rack.get_rack_units(
face=data['face'],
user=request.user,
2019-12-11 09:45:08 -05:00
exclude=data['exclude'],
expand_devices=data['expand_devices']
)
2019-11-20 18:27:04 +01:00
# Enable filtering rack units by ID
q = data['q']
if q:
elevation = [u for u in elevation if q in str(u['id']) or q in str(u['name'])]
2019-12-10 03:18:10 -05:00
page = self.paginate_queryset(elevation)
if page is not None:
rack_units = serializers.RackUnitSerializer(page, many=True, context={'request': request})
return self.get_paginated_response(rack_units.data)
#
# Rack reservations
#
2022-03-09 11:09:06 -05:00
class RackReservationViewSet(NetBoxModelViewSet):
queryset = RackReservation.objects.all()
serializer_class = serializers.RackReservationSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.RackReservationFilterSet
2016-03-01 11:23:03 -05:00
#
# Manufacturers
#
class ManufacturerViewSet(NetBoxModelViewSet):
queryset = Manufacturer.objects.all()
2016-05-18 16:02:53 -04:00
serializer_class = serializers.ManufacturerSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.ManufacturerFilterSet
2016-03-01 11:23:03 -05:00
#
2021-12-17 12:18:37 -05:00
# Device/module types
2016-03-01 11:23:03 -05:00
#
class DeviceTypeViewSet(NetBoxModelViewSet):
queryset = DeviceType.objects.all()
serializer_class = serializers.DeviceTypeSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.DeviceTypeFilterSet
2016-03-01 11:23:03 -05:00
class ModuleTypeViewSet(NetBoxModelViewSet):
queryset = ModuleType.objects.all()
2021-12-17 12:18:37 -05:00
serializer_class = serializers.ModuleTypeSerializer
filterset_class = filtersets.ModuleTypeFilterSet
2016-03-01 11:23:03 -05:00
#
# Device type components
#
2022-03-09 11:09:06 -05:00
class ConsolePortTemplateViewSet(NetBoxModelViewSet):
queryset = ConsolePortTemplate.objects.all()
serializer_class = serializers.ConsolePortTemplateSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.ConsolePortTemplateFilterSet
2022-03-09 11:09:06 -05:00
class ConsoleServerPortTemplateViewSet(NetBoxModelViewSet):
queryset = ConsoleServerPortTemplate.objects.all()
serializer_class = serializers.ConsoleServerPortTemplateSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.ConsoleServerPortTemplateFilterSet
2022-03-09 11:09:06 -05:00
class PowerPortTemplateViewSet(NetBoxModelViewSet):
queryset = PowerPortTemplate.objects.all()
serializer_class = serializers.PowerPortTemplateSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.PowerPortTemplateFilterSet
2022-03-09 11:09:06 -05:00
class PowerOutletTemplateViewSet(NetBoxModelViewSet):
queryset = PowerOutletTemplate.objects.all()
serializer_class = serializers.PowerOutletTemplateSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.PowerOutletTemplateFilterSet
2022-03-09 11:09:06 -05:00
class InterfaceTemplateViewSet(NetBoxModelViewSet):
queryset = InterfaceTemplate.objects.all()
serializer_class = serializers.InterfaceTemplateSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.InterfaceTemplateFilterSet
2022-03-09 11:09:06 -05:00
class FrontPortTemplateViewSet(NetBoxModelViewSet):
queryset = FrontPortTemplate.objects.all()
serializer_class = serializers.FrontPortTemplateSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.FrontPortTemplateFilterSet
2018-10-03 14:04:16 -04:00
2022-03-09 11:09:06 -05:00
class RearPortTemplateViewSet(NetBoxModelViewSet):
queryset = RearPortTemplate.objects.all()
serializer_class = serializers.RearPortTemplateSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.RearPortTemplateFilterSet
2018-10-03 14:04:16 -04:00
2022-03-09 11:09:06 -05:00
class ModuleBayTemplateViewSet(NetBoxModelViewSet):
queryset = ModuleBayTemplate.objects.all()
serializer_class = serializers.ModuleBayTemplateSerializer
filterset_class = filtersets.ModuleBayTemplateFilterSet
2022-03-09 11:09:06 -05:00
class DeviceBayTemplateViewSet(NetBoxModelViewSet):
queryset = DeviceBayTemplate.objects.all()
serializer_class = serializers.DeviceBayTemplateSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.DeviceBayTemplateFilterSet
class InventoryItemTemplateViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = InventoryItemTemplate.objects.all()
2021-12-29 15:02:25 -05:00
serializer_class = serializers.InventoryItemTemplateSerializer
filterset_class = filtersets.InventoryItemTemplateFilterSet
#
# Device roles
2016-03-01 11:23:03 -05:00
#
class DeviceRoleViewSet(NetBoxModelViewSet):
queryset = DeviceRole.objects.all()
2016-05-18 16:02:53 -04:00
serializer_class = serializers.DeviceRoleSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.DeviceRoleFilterSet
2016-03-01 11:23:03 -05:00
#
# Platforms
#
class PlatformViewSet(NetBoxModelViewSet):
queryset = Platform.objects.all()
2016-05-18 16:02:53 -04:00
serializer_class = serializers.PlatformSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.PlatformFilterSet
2016-03-01 11:23:03 -05:00
#
2021-12-17 16:12:03 -05:00
# Devices/modules
2016-03-01 11:23:03 -05:00
#
class DeviceViewSet(
SequentialBulkCreatesMixin,
ConfigContextQuerySetMixin,
RenderConfigMixin,
NetBoxModelViewSet
):
queryset = Device.objects.prefetch_related(
'parent_bay', # Referenced by DeviceSerializer.get_parent_device()
2017-01-24 17:12:16 -05:00
)
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.DeviceFilterSet
pagination_class = StripCountAnnotationsPaginator
2016-03-01 11:23:03 -05:00
def get_serializer_class(self):
"""
Select the specific serializer based on the request context.
If the `brief` query param equates to True, return the NestedDeviceSerializer
If the `exclude` query param includes `config_context` as a value, return the DeviceSerializer
Else, return the DeviceWithConfigContextSerializer
"""
2018-10-04 16:20:01 -04:00
request = self.get_serializer_context()['request']
if self.brief or 'config_context' in request.query_params.get('exclude', []):
return serializers.DeviceSerializer
return serializers.DeviceWithConfigContextSerializer
2018-06-27 16:02:34 -04:00
2017-07-14 14:42:56 -04:00
Closes: #7854 - Add VDC/Instances/etc (#10787) * Work on #7854 * Move to new URL scheme. * Fix PEP8 errors * Fix PEP8 errors * Add GraphQL and fix primary_ip missing * Fix PEP8 on GQL Type * Fix missing NestedSerializer. * Fix missing NestedSerializer & rename VDC to VDCs * Fix migration * Change Validation for identifier * Fix missing migration * Rebase to feature * Post-review changes * Remove VDC Type * Remove M2M Enforcement logic * Interface related changes * Add filter fields to filterset for Interface filter * Add form field to filterset form for Interface filter * Add VDC display to interface detail template * Remove VirtualDeviceContextTypeChoices * Accommodate recent changes in feature branch * Add tests Add missing search() * Update tests, and fix model form * Update test_api * Update test_api.InterfaceTest create_data * Fix issue with tests * Update interface serializer * Update serializer and tests * Update status to be required * Remove error message for constraint * Remove extraneous import * Re-ordered devices menu to place VDC below virtual chassis * Add helptext for `identifier` field * Fix breadcrumb link * Remove add interface link * Add missing tenant and status fields * Changes to tests as per Jeremy * Change for #9623 Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Update filterset form for status field * Remove Rename View * Change tabs to spaces * Update netbox/dcim/tables/devices.py Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Update netbox/dcim/tables/devices.py Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Fix tenant in bulk_edit * Apply suggestions from code review Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Add status field to table. * Re-order table fields. Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2022-11-11 06:55:49 -06:00
class VirtualDeviceContextViewSet(NetBoxModelViewSet):
queryset = VirtualDeviceContext.objects.all()
Closes: #7854 - Add VDC/Instances/etc (#10787) * Work on #7854 * Move to new URL scheme. * Fix PEP8 errors * Fix PEP8 errors * Add GraphQL and fix primary_ip missing * Fix PEP8 on GQL Type * Fix missing NestedSerializer. * Fix missing NestedSerializer & rename VDC to VDCs * Fix migration * Change Validation for identifier * Fix missing migration * Rebase to feature * Post-review changes * Remove VDC Type * Remove M2M Enforcement logic * Interface related changes * Add filter fields to filterset for Interface filter * Add form field to filterset form for Interface filter * Add VDC display to interface detail template * Remove VirtualDeviceContextTypeChoices * Accommodate recent changes in feature branch * Add tests Add missing search() * Update tests, and fix model form * Update test_api * Update test_api.InterfaceTest create_data * Fix issue with tests * Update interface serializer * Update serializer and tests * Update status to be required * Remove error message for constraint * Remove extraneous import * Re-ordered devices menu to place VDC below virtual chassis * Add helptext for `identifier` field * Fix breadcrumb link * Remove add interface link * Add missing tenant and status fields * Changes to tests as per Jeremy * Change for #9623 Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Update filterset form for status field * Remove Rename View * Change tabs to spaces * Update netbox/dcim/tables/devices.py Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Update netbox/dcim/tables/devices.py Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Fix tenant in bulk_edit * Apply suggestions from code review Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Add status field to table. * Re-order table fields. Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2022-11-11 06:55:49 -06:00
serializer_class = serializers.VirtualDeviceContextSerializer
filterset_class = filtersets.VirtualDeviceContextFilterSet
class ModuleViewSet(NetBoxModelViewSet):
queryset = Module.objects.all()
2021-12-17 16:12:03 -05:00
serializer_class = serializers.ModuleSerializer
filterset_class = filtersets.ModuleFilterSet
2016-03-01 11:23:03 -05:00
#
# Device components
2016-03-01 11:23:03 -05:00
#
2022-03-09 11:09:06 -05:00
class ConsolePortViewSet(PathEndpointMixin, NetBoxModelViewSet):
queryset = ConsolePort.objects.prefetch_related(
'_path', 'cable__terminations',
)
serializer_class = serializers.ConsolePortSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.ConsolePortFilterSet
2022-03-09 11:09:06 -05:00
class ConsoleServerPortViewSet(PathEndpointMixin, NetBoxModelViewSet):
queryset = ConsoleServerPort.objects.prefetch_related(
'_path', 'cable__terminations',
)
serializer_class = serializers.ConsoleServerPortSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.ConsoleServerPortFilterSet
2022-03-09 11:09:06 -05:00
class PowerPortViewSet(PathEndpointMixin, NetBoxModelViewSet):
queryset = PowerPort.objects.prefetch_related(
'_path', 'cable__terminations',
)
serializer_class = serializers.PowerPortSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.PowerPortFilterSet
2022-03-09 11:09:06 -05:00
class PowerOutletViewSet(PathEndpointMixin, NetBoxModelViewSet):
queryset = PowerOutlet.objects.prefetch_related(
'_path', 'cable__terminations',
)
serializer_class = serializers.PowerOutletSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.PowerOutletFilterSet
2022-03-09 11:09:06 -05:00
class InterfaceViewSet(PathEndpointMixin, NetBoxModelViewSet):
queryset = Interface.objects.prefetch_related(
'_path', 'cable__terminations',
'l2vpn_terminations', # Referenced by InterfaceSerializer.l2vpn_termination
'ip_addresses', # Referenced by Interface.count_ipaddresses()
'fhrp_group_assignments', # Referenced by Interface.count_fhrp_groups()
)
serializer_class = serializers.InterfaceSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.InterfaceFilterSet
def get_bulk_destroy_queryset(self):
# Ensure child interfaces are deleted prior to their parents
return self.get_queryset().order_by('device', 'parent', CollateAsChar('_name'))
2022-03-09 11:09:06 -05:00
class FrontPortViewSet(PassThroughPortMixin, NetBoxModelViewSet):
queryset = FrontPort.objects.prefetch_related(
'cable__terminations',
)
serializer_class = serializers.FrontPortSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.FrontPortFilterSet
2018-10-03 14:04:16 -04:00
2022-03-09 11:09:06 -05:00
class RearPortViewSet(PassThroughPortMixin, NetBoxModelViewSet):
queryset = RearPort.objects.prefetch_related(
'cable__terminations',
)
serializer_class = serializers.RearPortSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.RearPortFilterSet
2018-10-03 14:04:16 -04:00
2022-03-09 11:09:06 -05:00
class ModuleBayViewSet(NetBoxModelViewSet):
queryset = ModuleBay.objects.all()
serializer_class = serializers.ModuleBaySerializer
filterset_class = filtersets.ModuleBayFilterSet
2022-03-09 11:09:06 -05:00
class DeviceBayViewSet(NetBoxModelViewSet):
queryset = DeviceBay.objects.all()
serializer_class = serializers.DeviceBaySerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.DeviceBayFilterSet
class InventoryItemViewSet(MPTTLockedMixin, NetBoxModelViewSet):
queryset = InventoryItem.objects.all()
serializer_class = serializers.InventoryItemSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.InventoryItemFilterSet
2017-01-31 12:19:41 -05:00
2016-07-05 13:43:19 -04:00
2021-12-27 10:18:39 -05:00
#
# Device component roles
#
class InventoryItemRoleViewSet(NetBoxModelViewSet):
queryset = InventoryItemRole.objects.all()
2021-12-27 10:18:39 -05:00
serializer_class = serializers.InventoryItemRoleSerializer
filterset_class = filtersets.InventoryItemRoleFilterSet
2018-10-26 12:25:11 -04:00
#
# Cables
#
2022-03-09 11:09:06 -05:00
class CableViewSet(NetBoxModelViewSet):
2022-05-16 15:33:57 -04:00
queryset = Cable.objects.prefetch_related('terminations__termination')
2018-10-26 12:25:11 -04:00
serializer_class = serializers.CableSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.CableFilterSet
2018-10-26 12:25:11 -04:00
class CableTerminationViewSet(NetBoxModelViewSet):
metadata_class = ContentTypeMetadata
queryset = CableTermination.objects.all()
serializer_class = serializers.CableTerminationSerializer
filterset_class = filtersets.CableTerminationFilterSet
#
# Virtual chassis
#
2022-03-09 11:09:06 -05:00
class VirtualChassisViewSet(NetBoxModelViewSet):
queryset = VirtualChassis.objects.prefetch_related(
# Prefetch related object for the display of unnamed devices
'master__virtual_chassis',
)
serializer_class = serializers.VirtualChassisSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.VirtualChassisFilterSet
2019-03-12 11:36:29 -04:00
#
# Power panels
#
2022-03-09 11:09:06 -05:00
class PowerPanelViewSet(NetBoxModelViewSet):
queryset = PowerPanel.objects.all()
2019-03-12 11:36:29 -04:00
serializer_class = serializers.PowerPanelSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.PowerPanelFilterSet
2019-03-12 11:36:29 -04:00
#
# Power feeds
#
class PowerFeedViewSet(PathEndpointMixin, NetBoxModelViewSet):
queryset = PowerFeed.objects.prefetch_related(
'_path', 'cable__terminations',
)
2019-03-12 11:36:29 -04:00
serializer_class = serializers.PowerFeedSerializer
2021-04-29 16:38:56 -04:00
filterset_class = filtersets.PowerFeedFilterSet
2019-03-12 11:36:29 -04:00
2016-03-01 11:23:03 -05:00
#
# Miscellaneous
#
class ConnectedDeviceViewSet(ViewSet):
2016-03-01 11:23:03 -05:00
"""
This endpoint allows a user to determine what device (if any) is connected to a given peer device and peer
interface. This is useful in a situation where a device boots with no configuration, but can detect its neighbors
via a protocol such as LLDP. Two query parameters must be included in the request:
2017-01-24 17:12:16 -05:00
* `peer_device`: The name of the peer device
* `peer_interface`: The name of the peer interface
"""
permission_classes = [IsAuthenticatedOrLoginNotRequired]
_device_param = OpenApiParameter(
name='peer_device',
location='query',
description='The name of the peer device',
required=True,
type=OpenApiTypes.STR
)
_interface_param = OpenApiParameter(
name='peer_interface',
location='query',
description='The name of the peer interface',
required=True,
type=OpenApiTypes.STR
)
serializer_class = serializers.DeviceSerializer
2017-01-24 17:12:16 -05:00
2017-03-20 21:54:01 -04:00
def get_view_name(self):
return "Connected Device Locator"
2023-06-14 15:45:07 +05:30
@extend_schema(
parameters=[_device_param, _interface_param],
responses={200: serializers.DeviceSerializer}
)
def list(self, request):
2016-08-22 17:15:20 -04:00
peer_device_name = request.query_params.get(self._device_param.name)
peer_interface_name = request.query_params.get(self._interface_param.name)
if not peer_device_name or not peer_interface_name:
raise MissingFilterException(detail='Request must include "peer_device" and "peer_interface" filters.')
2016-03-01 11:23:03 -05:00
# Determine local endpoint from peer interface's connection
peer_device = get_object_or_404(
Device.objects.restrict(request.user, 'view'),
name=peer_device_name
)
2020-06-29 14:41:43 -04:00
peer_interface = get_object_or_404(
Interface.objects.restrict(request.user, 'view'),
device=peer_device,
2020-06-29 14:41:43 -04:00
name=peer_interface_name
)
2022-05-13 16:23:44 -04:00
endpoints = peer_interface.connected_endpoints
2016-03-01 11:23:03 -05:00
# If an Interface, return the parent device
2022-05-13 16:23:44 -04:00
if endpoints and type(endpoints[0]) is Interface:
device = get_object_or_404(
Device.objects.restrict(request.user, 'view'),
2022-05-13 16:23:44 -04:00
pk=endpoints[0].device_id
)
return Response(serializers.DeviceSerializer(device, context={'request': request}).data)
2016-03-01 11:23:03 -05:00
# Connected endpoint is none or not an Interface
raise Http404