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

693 lines
23 KiB
Python
Raw Normal View History

2017-07-14 16:07:28 -04:00
from collections import OrderedDict
2017-05-24 11:33:11 -04:00
from django.conf import settings
2019-04-19 16:58:39 -04:00
from django.db.models import Count, F
from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import get_object_or_404
from drf_yasg import openapi
from drf_yasg.openapi import Parameter
from drf_yasg.utils import swagger_auto_schema
from rest_framework.decorators import action
from rest_framework.mixins import ListModelMixin
2016-03-01 11:23:03 -05:00
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ViewSet
2016-03-01 11:23:03 -05:00
from circuits.models import Circuit
from dcim import filters
from dcim.models import (Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device,
DeviceBay, DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface,
InterfaceTemplate, InventoryItem, Manufacturer, Platform, PowerFeed, PowerOutlet,
PowerOutletTemplate, PowerPanel, PowerPort, PowerPortTemplate, Rack, RackGroup,
RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site, VirtualChassis)
2017-03-20 15:14:33 -04:00
from extras.api.serializers import RenderedGraphSerializer
2017-01-30 17:00:58 -05:00
from extras.api.views import CustomFieldModelViewSet
from extras.models import Graph
from ipam.models import Prefix, VLAN
from utilities.api import (IsAuthenticatedOrLoginNotRequired, ModelViewSet, ServiceUnavailable,
get_serializer_for_model)
2019-12-10 03:18:10 -05:00
from utilities.utils import get_subquery
from virtualization.models import VirtualMachine
2016-08-22 13:20:30 -04:00
from . import serializers
from .exceptions import MissingFilterException
2016-03-01 11:23:03 -05:00
# Mixins
class CableTraceMixin(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).
"""
obj = get_object_or_404(self.queryset.model, pk=pk)
# Initialize the path array
path = []
for near_end, cable, far_end in obj.trace()[0]:
# Serialize each object
serializer_a = get_serializer_for_model(near_end, prefix='Nested')
x = serializer_a(near_end, context={
'request': request
}).data
if cable is not None:
y = serializers.TracedCableSerializer(cable, context={
'request': request
}).data
else:
y = None
if far_end is not None:
serializer_b = get_serializer_for_model(far_end, prefix='Nested')
z = serializer_b(far_end, context={
'request': request
}).data
else:
z = None
path.append((x, y, z))
return Response(path)
2017-02-28 16:10:53 -05:00
#
# Regions
#
class RegionViewSet(ModelViewSet):
queryset = Region.objects.annotate(
site_count=Count('sites')
)
2017-02-28 16:10:53 -05:00
serializer_class = serializers.RegionSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.RegionFilterSet
2017-02-28 16:10:53 -05:00
2016-03-01 11:23:03 -05:00
#
# Sites
#
class SiteViewSet(CustomFieldModelViewSet):
queryset = Site.objects.prefetch_related(
'region', 'tenant', 'tags'
).annotate(
device_count=get_subquery(Device, 'site'),
rack_count=get_subquery(Rack, 'site'),
prefix_count=get_subquery(Prefix, 'site'),
vlan_count=get_subquery(VLAN, 'site'),
circuit_count=get_subquery(Circuit, 'terminations__site'),
virtualmachine_count=get_subquery(VirtualMachine, 'cluster__site'),
)
2016-05-18 16:02:53 -04:00
serializer_class = serializers.SiteSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.SiteFilterSet
2016-03-01 11:23:03 -05:00
@action(detail=True)
def graphs(self, request, pk):
2017-03-20 15:14:33 -04:00
"""
A convenience method for rendering graphs for a particular site.
"""
2017-01-30 17:00:58 -05:00
site = get_object_or_404(Site, pk=pk)
queryset = Graph.objects.filter(type__model='site')
serializer = RenderedGraphSerializer(queryset, many=True, context={
'graphed_object': site
})
2017-01-30 17:00:58 -05:00
return Response(serializer.data)
2016-03-01 11:23:03 -05:00
#
# Rack groups
#
class RackGroupViewSet(ModelViewSet):
queryset = RackGroup.objects.prefetch_related('site').annotate(
rack_count=Count('racks')
)
2016-05-18 16:02:53 -04:00
serializer_class = serializers.RackGroupSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.RackGroupFilterSet
2016-03-01 11:23:03 -05:00
2016-08-10 11:52:27 -04:00
#
# Rack roles
#
2017-01-24 17:12:16 -05:00
class RackRoleViewSet(ModelViewSet):
queryset = RackRole.objects.annotate(
rack_count=Count('racks')
)
2016-08-10 11:52:27 -04:00
serializer_class = serializers.RackRoleSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.RackRoleFilterSet
2016-08-10 11:52:27 -04:00
2016-03-01 11:23:03 -05:00
#
# Racks
#
class RackViewSet(CustomFieldModelViewSet):
queryset = Rack.objects.prefetch_related(
'site', 'group__site', 'role', 'tenant', 'tags'
).annotate(
device_count=get_subquery(Device, 'rack'),
powerfeed_count=get_subquery(PowerFeed, 'rack')
)
serializer_class = serializers.RackSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.RackFilterSet
2016-03-01 11:23:03 -05:00
2019-12-11 09:45:08 -05:00
@swagger_auto_schema(
responses={
200: serializers.RackUnitSerializer(many=True)
},
2019-12-11 09:45:08 -05:00
query_serializer=serializers.RackElevationDetailFilterSerializer
)
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.
"""
rack = get_object_or_404(Rack, 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':
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'],
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('/')
)
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'],
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
})
2019-12-10 03:18:10 -05:00
return self.get_paginated_response(rack_units.data)
#
# Rack reservations
#
class RackReservationViewSet(ModelViewSet):
queryset = RackReservation.objects.prefetch_related('rack', 'user', 'tenant')
serializer_class = serializers.RackReservationSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.RackReservationFilterSet
# Assign user from request
def perform_create(self, serializer):
serializer.save(user=self.request.user)
2016-03-01 11:23:03 -05:00
#
# Manufacturers
#
2017-01-24 17:12:16 -05:00
class ManufacturerViewSet(ModelViewSet):
queryset = Manufacturer.objects.annotate(
devicetype_count=get_subquery(DeviceType, 'manufacturer'),
inventoryitem_count=get_subquery(InventoryItem, 'manufacturer'),
platform_count=get_subquery(Platform, 'manufacturer')
)
2016-05-18 16:02:53 -04:00
serializer_class = serializers.ManufacturerSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.ManufacturerFilterSet
2016-03-01 11:23:03 -05:00
#
# Device types
2016-03-01 11:23:03 -05:00
#
class DeviceTypeViewSet(CustomFieldModelViewSet):
queryset = DeviceType.objects.prefetch_related('manufacturer').prefetch_related('tags').annotate(
device_count=Count('instances')
)
serializer_class = serializers.DeviceTypeSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.DeviceTypeFilterSet
2016-03-01 11:23:03 -05:00
#
# Device type components
#
class ConsolePortTemplateViewSet(ModelViewSet):
queryset = ConsolePortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.ConsolePortTemplateSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.ConsolePortTemplateFilterSet
class ConsoleServerPortTemplateViewSet(ModelViewSet):
queryset = ConsoleServerPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.ConsoleServerPortTemplateSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.ConsoleServerPortTemplateFilterSet
class PowerPortTemplateViewSet(ModelViewSet):
queryset = PowerPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.PowerPortTemplateSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.PowerPortTemplateFilterSet
class PowerOutletTemplateViewSet(ModelViewSet):
queryset = PowerOutletTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.PowerOutletTemplateSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.PowerOutletTemplateFilterSet
class InterfaceTemplateViewSet(ModelViewSet):
queryset = InterfaceTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.InterfaceTemplateSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.InterfaceTemplateFilterSet
class FrontPortTemplateViewSet(ModelViewSet):
queryset = FrontPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.FrontPortTemplateSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.FrontPortTemplateFilterSet
2018-10-03 14:04:16 -04:00
class RearPortTemplateViewSet(ModelViewSet):
queryset = RearPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.RearPortTemplateSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.RearPortTemplateFilterSet
2018-10-03 14:04:16 -04:00
class DeviceBayTemplateViewSet(ModelViewSet):
queryset = DeviceBayTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.DeviceBayTemplateSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.DeviceBayTemplateFilterSet
#
# Device roles
2016-03-01 11:23:03 -05:00
#
2017-01-24 17:12:16 -05:00
class DeviceRoleViewSet(ModelViewSet):
queryset = DeviceRole.objects.all()
# annotate(
# device_count=Count('devices'),
# virtualmachine_count=Count('virtual_machines')
# )
2016-05-18 16:02:53 -04:00
serializer_class = serializers.DeviceRoleSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.DeviceRoleFilterSet
2016-03-01 11:23:03 -05:00
#
# Platforms
#
2017-01-24 17:12:16 -05:00
class PlatformViewSet(ModelViewSet):
queryset = Platform.objects.annotate(
device_count=get_subquery(Device, 'platform'),
virtualmachine_count=get_subquery(VirtualMachine, 'platform')
)
2016-05-18 16:02:53 -04:00
serializer_class = serializers.PlatformSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.PlatformFilterSet
2016-03-01 11:23:03 -05:00
#
# Devices
#
class DeviceViewSet(CustomFieldModelViewSet):
queryset = Device.objects.prefetch_related(
2018-02-01 13:02:34 -05:00
'device_type__manufacturer', 'device_role', 'tenant', 'platform', 'site', 'rack', 'parent_bay',
'virtual_chassis__master', 'primary_ip4__nat_outside', 'primary_ip6__nat_outside', 'tags',
2017-01-24 17:12:16 -05:00
)
2020-01-09 20:30:40 -05:00
filterset_class = filters.DeviceFilterSet
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 request.query_params.get('brief', False):
return serializers.NestedDeviceSerializer
elif 'config_context' in request.query_params.get('exclude', []):
return serializers.DeviceSerializer
return serializers.DeviceWithConfigContextSerializer
2018-06-27 16:02:34 -04:00
@action(detail=True)
def graphs(self, request, pk):
"""
A convenience method for rendering graphs for a particular Device.
"""
device = get_object_or_404(Device, pk=pk)
queryset = Graph.objects.filter(type__model='device')
serializer = RenderedGraphSerializer(queryset, many=True, context={
'graphed_object': device
})
return Response(serializer.data)
2020-01-09 16:39:13 +00:00
@swagger_auto_schema(
manual_parameters=[
Parameter(
name='method',
in_='query',
required=True,
type=openapi.TYPE_STRING
)
],
responses={
'200': serializers.DeviceNAPALMSerializer
}
2020-01-09 16:39:13 +00:00
)
@action(detail=True, url_path='napalm')
2017-07-14 16:07:28 -04:00
def napalm(self, request, pk):
2017-07-14 14:42:56 -04:00
"""
Execute a NAPALM method on a Device
"""
device = get_object_or_404(Device, pk=pk)
if not device.primary_ip:
raise ServiceUnavailable("This device does not have a primary IP address configured.")
if device.platform is None:
raise ServiceUnavailable("No platform is configured for this device.")
if not device.platform.napalm_driver:
raise ServiceUnavailable("No NAPALM driver is configured for this device's platform ().".format(
device.platform
))
2017-11-08 09:51:37 -05:00
# Check that NAPALM is installed
2017-07-14 14:42:56 -04:00
try:
import napalm
from napalm.base.exceptions import ModuleImportError
2017-07-14 14:42:56 -04:00
except ImportError:
raise ServiceUnavailable("NAPALM is not installed. Please see the documentation for instructions.")
2017-11-08 09:51:37 -05:00
# Validate the configured driver
2017-07-14 14:42:56 -04:00
try:
driver = napalm.get_network_driver(device.platform.napalm_driver)
except ModuleImportError:
raise ServiceUnavailable("NAPALM driver for platform {} not found: {}.".format(
device.platform, device.platform.napalm_driver
))
# Verify user permission
if not request.user.has_perm('dcim.napalm_read'):
return HttpResponseForbidden()
# Connect to the device
2017-07-14 16:07:28 -04:00
napalm_methods = request.GET.getlist('method')
response = OrderedDict([(m, None) for m in napalm_methods])
2017-07-14 14:42:56 -04:00
ip_address = str(device.primary_ip.address.ip)
username = settings.NAPALM_USERNAME
password = settings.NAPALM_PASSWORD
optional_args = settings.NAPALM_ARGS.copy()
if device.platform.napalm_args is not None:
optional_args.update(device.platform.napalm_args)
2020-01-08 16:01:18 +00:00
# Update NAPALM parameters according to the request headers
for header in request.headers:
if header[:9].lower() != 'x-napalm-':
continue
key = header[9:]
if key.lower() == 'username':
username = request.headers[header]
elif key.lower() == 'password':
password = request.headers[header]
elif key:
2020-01-08 16:01:18 +00:00
optional_args[key.lower()] = request.headers[header]
2017-07-14 14:42:56 -04:00
d = driver(
hostname=ip_address,
username=username,
password=password,
timeout=settings.NAPALM_TIMEOUT,
optional_args=optional_args
2017-07-14 14:42:56 -04:00
)
try:
d.open()
except Exception as e:
raise ServiceUnavailable("Error connecting to the device at {}: {}".format(ip_address, e))
2017-07-14 14:42:56 -04:00
# Validate and execute each specified NAPALM method
for method in napalm_methods:
if not hasattr(driver, method):
response[method] = {
'error': 'Unknown NAPALM method'
}
continue
if not method.startswith('get_'):
response[method] = {
'error': 'Only get_* NAPALM methods are supported'
}
continue
try:
response[method] = getattr(d, method)()
except NotImplementedError:
response[method] = {
'error': 'Method {} not implemented for NAPALM driver {}'.format(method, driver)
}
except Exception as e:
response[method] = {
'error': 'Method {} failed: {}'.format(method, e)
}
2017-07-14 16:07:28 -04:00
d.close()
2017-07-14 14:42:56 -04:00
return Response(response)
2016-03-01 11:23:03 -05:00
#
# Device components
2016-03-01 11:23:03 -05:00
#
class ConsolePortViewSet(CableTraceMixin, ModelViewSet):
queryset = ConsolePort.objects.prefetch_related('device', 'connected_endpoint__device', 'cable', 'tags')
serializer_class = serializers.ConsolePortSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.ConsolePortFilterSet
class ConsoleServerPortViewSet(CableTraceMixin, ModelViewSet):
queryset = ConsoleServerPort.objects.prefetch_related('device', 'connected_endpoint__device', 'cable', 'tags')
serializer_class = serializers.ConsoleServerPortSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.ConsoleServerPortFilterSet
class PowerPortViewSet(CableTraceMixin, ModelViewSet):
queryset = PowerPort.objects.prefetch_related(
'device', '_connected_poweroutlet__device', '_connected_powerfeed', 'cable', 'tags'
2018-10-29 13:26:09 -04:00
)
serializer_class = serializers.PowerPortSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.PowerPortFilterSet
class PowerOutletViewSet(CableTraceMixin, ModelViewSet):
queryset = PowerOutlet.objects.prefetch_related('device', 'connected_endpoint__device', 'cable', 'tags')
serializer_class = serializers.PowerOutletSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.PowerOutletFilterSet
class InterfaceViewSet(CableTraceMixin, ModelViewSet):
queryset = Interface.objects.prefetch_related(
'device', '_connected_interface', '_connected_circuittermination', 'cable', 'ip_addresses', 'tags'
).filter(
device__isnull=False
2018-10-29 13:26:09 -04:00
)
serializer_class = serializers.InterfaceSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.InterfaceFilterSet
@action(detail=True)
def graphs(self, request, pk):
2017-03-20 15:14:33 -04:00
"""
A convenience method for rendering graphs for a particular interface.
"""
2017-01-30 17:00:58 -05:00
interface = get_object_or_404(Interface, pk=pk)
queryset = Graph.objects.filter(type__model='interface')
serializer = RenderedGraphSerializer(queryset, many=True, context={
'graphed_object': interface
})
2017-01-30 17:00:58 -05:00
return Response(serializer.data)
class FrontPortViewSet(CableTraceMixin, ModelViewSet):
queryset = FrontPort.objects.prefetch_related('device__device_type__manufacturer', 'rear_port', 'cable', 'tags')
serializer_class = serializers.FrontPortSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.FrontPortFilterSet
2018-10-03 14:04:16 -04:00
class RearPortViewSet(CableTraceMixin, ModelViewSet):
queryset = RearPort.objects.prefetch_related('device__device_type__manufacturer', 'cable', 'tags')
serializer_class = serializers.RearPortSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.RearPortFilterSet
2018-10-03 14:04:16 -04:00
class DeviceBayViewSet(ModelViewSet):
queryset = DeviceBay.objects.prefetch_related('installed_device').prefetch_related('tags')
serializer_class = serializers.DeviceBaySerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.DeviceBayFilterSet
class InventoryItemViewSet(ModelViewSet):
queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer').prefetch_related('tags')
serializer_class = serializers.InventoryItemSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.InventoryItemFilterSet
2017-01-31 12:19:41 -05:00
2016-07-05 13:43:19 -04:00
#
# Connections
#
class ConsoleConnectionViewSet(ListModelMixin, GenericViewSet):
queryset = ConsolePort.objects.prefetch_related(
'device', 'connected_endpoint__device'
).filter(
connected_endpoint__isnull=False
)
serializer_class = serializers.ConsolePortSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.ConsoleConnectionFilterSet
class PowerConnectionViewSet(ListModelMixin, GenericViewSet):
queryset = PowerPort.objects.prefetch_related(
'device', 'connected_endpoint__device'
).filter(
2019-03-21 17:47:43 -04:00
_connected_poweroutlet__isnull=False
)
serializer_class = serializers.PowerPortSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.PowerConnectionFilterSet
class InterfaceConnectionViewSet(ListModelMixin, GenericViewSet):
queryset = Interface.objects.prefetch_related(
'device', '_connected_interface__device'
).filter(
# Avoid duplicate connections by only selecting the lower PK in a connected pair
_connected_interface__isnull=False,
pk__lt=F('_connected_interface')
)
serializer_class = serializers.InterfaceConnectionSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.InterfaceConnectionFilterSet
2018-10-26 12:25:11 -04:00
#
# Cables
#
class CableViewSet(ModelViewSet):
queryset = Cable.objects.prefetch_related(
'termination_a', 'termination_b'
)
2018-10-26 12:25:11 -04:00
serializer_class = serializers.CableSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.CableFilterSet
2018-10-26 12:25:11 -04:00
#
# Virtual chassis
#
class VirtualChassisViewSet(ModelViewSet):
queryset = VirtualChassis.objects.prefetch_related('tags').annotate(
member_count=Count('members')
)
serializer_class = serializers.VirtualChassisSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.VirtualChassisFilterSet
2019-03-12 11:36:29 -04:00
#
# Power panels
#
class PowerPanelViewSet(ModelViewSet):
queryset = PowerPanel.objects.prefetch_related(
'site', 'rack_group'
).annotate(
powerfeed_count=Count('powerfeeds')
)
2019-03-12 11:36:29 -04:00
serializer_class = serializers.PowerPanelSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.PowerPanelFilterSet
2019-03-12 11:36:29 -04:00
#
# Power feeds
#
2019-04-11 10:49:43 -04:00
class PowerFeedViewSet(CustomFieldModelViewSet):
queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack', 'tags')
2019-03-12 11:36:29 -04:00
serializer_class = serializers.PowerFeedSerializer
2020-01-09 20:30:40 -05:00
filterset_class = filters.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 = Parameter(
name='peer_device',
in_='query',
description='The name of the peer device',
required=True,
type=openapi.TYPE_STRING
)
_interface_param = Parameter(
name='peer_interface',
in_='query',
description='The name of the peer interface',
required=True,
type=openapi.TYPE_STRING
)
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"
@swagger_auto_schema(
manual_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 interface from peer interface's connection
peer_interface = get_object_or_404(Interface, device__name=peer_device_name, name=peer_interface_name)
local_interface = peer_interface._connected_interface
2016-03-01 11:23:03 -05:00
if local_interface is None:
return Response()
2016-03-01 11:23:03 -05:00
return Response(serializers.DeviceSerializer(local_interface.device, context={
'request': request
}).data)