2017-01-26 17:58:36 -05:00
|
|
|
from rest_framework.mixins import (
|
|
|
|
CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin,
|
|
|
|
)
|
2016-03-01 11:23:03 -05:00
|
|
|
from rest_framework.response import Response
|
|
|
|
from rest_framework.settings import api_settings
|
|
|
|
from rest_framework.views import APIView
|
2017-01-26 17:58:36 -05:00
|
|
|
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
from django.conf import settings
|
2016-08-22 17:15:20 -04:00
|
|
|
from django.contrib.contenttypes.models import ContentType
|
2016-03-01 11:23:03 -05:00
|
|
|
from django.http import Http404
|
|
|
|
from django.shortcuts import get_object_or_404
|
|
|
|
|
2016-05-18 16:02:53 -04:00
|
|
|
from dcim.models import (
|
2017-01-26 17:58:36 -05:00
|
|
|
ConsolePort, ConsoleServerPort, Device, DeviceBay, DeviceRole, DeviceType, Interface, InterfaceConnection,
|
|
|
|
Manufacturer, Module, Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackRole, Site,
|
2016-05-18 16:02:53 -04:00
|
|
|
)
|
|
|
|
from dcim import filters
|
2017-01-24 17:12:16 -05:00
|
|
|
from extras.api.views import CustomFieldModelViewSet
|
2016-03-07 23:57:49 -06:00
|
|
|
from extras.api.renderers import BINDZoneRenderer, FlatJSONRenderer
|
2016-03-01 11:23:03 -05:00
|
|
|
from utilities.api import ServiceUnavailable
|
2016-08-22 13:20:30 -04:00
|
|
|
from .exceptions import MissingFilterException
|
|
|
|
from . import serializers
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Sites
|
|
|
|
#
|
|
|
|
|
2017-01-24 17:12:16 -05:00
|
|
|
class SiteViewSet(CustomFieldModelViewSet):
|
|
|
|
queryset = Site.objects.select_related('tenant')
|
2016-05-18 16:02:53 -04:00
|
|
|
serializer_class = serializers.SiteSerializer
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Rack groups
|
|
|
|
#
|
|
|
|
|
2017-01-24 17:12:16 -05:00
|
|
|
class RackGroupViewSet(ModelViewSet):
|
2016-07-27 14:40:19 -04:00
|
|
|
queryset = RackGroup.objects.select_related('site')
|
2016-05-18 16:02:53 -04:00
|
|
|
serializer_class = serializers.RackGroupSerializer
|
|
|
|
filter_class = filters.RackGroupFilter
|
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):
|
2016-08-10 11:52:27 -04:00
|
|
|
queryset = RackRole.objects.all()
|
|
|
|
serializer_class = serializers.RackRoleSerializer
|
|
|
|
|
|
|
|
|
2016-03-01 11:23:03 -05:00
|
|
|
#
|
|
|
|
# Racks
|
|
|
|
#
|
|
|
|
|
2017-01-24 17:12:16 -05:00
|
|
|
class RackViewSet(CustomFieldModelViewSet):
|
|
|
|
queryset = Rack.objects.select_related('site', 'group__site', 'tenant')
|
2016-05-18 16:02:53 -04:00
|
|
|
filter_class = filters.RackFilter
|
2016-03-01 11:23:03 -05:00
|
|
|
|
2017-01-24 17:12:16 -05:00
|
|
|
def get_serializer_class(self):
|
|
|
|
if self.action == 'retrieve':
|
|
|
|
return serializers.RackDetailSerializer
|
|
|
|
return serializers.RackSerializer
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
|
|
|
|
class RackUnitListView(APIView):
|
|
|
|
"""
|
|
|
|
List rack units (by rack)
|
|
|
|
"""
|
|
|
|
|
|
|
|
def get(self, request, pk):
|
|
|
|
|
|
|
|
rack = get_object_or_404(Rack, pk=pk)
|
|
|
|
face = request.GET.get('face', 0)
|
2017-01-04 10:58:11 -05:00
|
|
|
exclude_pk = request.GET.get('exclude', None)
|
|
|
|
if exclude_pk is not None:
|
|
|
|
try:
|
|
|
|
exclude_pk = int(exclude_pk)
|
|
|
|
except ValueError:
|
|
|
|
exclude_pk = None
|
|
|
|
elevation = rack.get_rack_units(face, exclude_pk)
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
# Serialize Devices within the rack elevation
|
|
|
|
for u in elevation:
|
|
|
|
if u['device']:
|
2016-05-18 16:02:53 -04:00
|
|
|
u['device'] = serializers.DeviceNestedSerializer(instance=u['device']).data
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
return Response(elevation)
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Manufacturers
|
|
|
|
#
|
|
|
|
|
2017-01-24 17:12:16 -05:00
|
|
|
class ManufacturerViewSet(ModelViewSet):
|
2016-03-01 11:23:03 -05:00
|
|
|
queryset = Manufacturer.objects.all()
|
2016-05-18 16:02:53 -04:00
|
|
|
serializer_class = serializers.ManufacturerSerializer
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Device Types
|
|
|
|
#
|
|
|
|
|
2017-01-24 17:12:16 -05:00
|
|
|
class DeviceTypeViewSet(CustomFieldModelViewSet):
|
|
|
|
queryset = DeviceType.objects.select_related('manufacturer')
|
2016-05-18 16:02:53 -04:00
|
|
|
filter_class = filters.DeviceTypeFilter
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
|
|
|
|
#
|
2017-01-26 17:58:36 -05:00
|
|
|
# Device Roles
|
2016-03-01 11:23:03 -05:00
|
|
|
#
|
|
|
|
|
2017-01-24 17:12:16 -05:00
|
|
|
class DeviceRoleViewSet(ModelViewSet):
|
2016-03-01 11:23:03 -05:00
|
|
|
queryset = DeviceRole.objects.all()
|
2016-05-18 16:02:53 -04:00
|
|
|
serializer_class = serializers.DeviceRoleSerializer
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Platforms
|
|
|
|
#
|
|
|
|
|
2017-01-24 17:12:16 -05:00
|
|
|
class PlatformViewSet(ModelViewSet):
|
2016-03-01 11:23:03 -05:00
|
|
|
queryset = Platform.objects.all()
|
2016-05-18 16:02:53 -04:00
|
|
|
serializer_class = serializers.PlatformSerializer
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Devices
|
|
|
|
#
|
|
|
|
|
2017-01-24 17:12:16 -05:00
|
|
|
class DeviceViewSet(CustomFieldModelViewSet):
|
|
|
|
queryset = Device.objects.select_related(
|
|
|
|
'device_type__manufacturer', 'device_role', 'tenant', 'platform', 'rack__site', 'parent_bay',
|
|
|
|
).prefetch_related(
|
|
|
|
'primary_ip4__nat_outside', 'primary_ip6__nat_outside',
|
|
|
|
)
|
2016-05-18 16:02:53 -04:00
|
|
|
serializer_class = serializers.DeviceSerializer
|
|
|
|
filter_class = filters.DeviceFilter
|
2016-03-07 23:57:49 -06:00
|
|
|
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + [BINDZoneRenderer, FlatJSONRenderer]
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
|
|
|
|
#
|
2017-01-26 17:58:36 -05:00
|
|
|
# Console Ports
|
2016-03-01 11:23:03 -05:00
|
|
|
#
|
|
|
|
|
2017-01-26 17:58:36 -05:00
|
|
|
class ConsolePortViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
|
|
|
|
queryset = ConsolePort.objects.select_related('cs_port')
|
|
|
|
serializer_class = serializers.ConsolePortSerializer
|
|
|
|
|
|
|
|
|
|
|
|
class NestedConsolePortViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
|
2017-01-26 22:37:17 -05:00
|
|
|
serializer_class = serializers.NestedConsolePortSerializer
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
|
|
|
return ConsolePort.objects.filter(device=device).select_related('cs_port')
|
|
|
|
|
|
|
|
|
|
|
|
#
|
2017-01-26 17:58:36 -05:00
|
|
|
# Console Server Ports
|
2016-03-01 11:23:03 -05:00
|
|
|
#
|
|
|
|
|
2017-01-26 17:58:36 -05:00
|
|
|
class ConsoleServerPortViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
|
|
|
|
queryset = ConsoleServerPort.objects.select_related('connected_console')
|
|
|
|
serializer_class = serializers.ConsoleServerPortSerializer
|
|
|
|
|
|
|
|
|
|
|
|
class NestedConsoleServerPortViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
|
2017-01-26 22:37:17 -05:00
|
|
|
serializer_class = serializers.NestedConsoleServerPortSerializer
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
|
|
|
return ConsoleServerPort.objects.filter(device=device).select_related('connected_console')
|
|
|
|
|
|
|
|
|
|
|
|
#
|
2017-01-26 17:58:36 -05:00
|
|
|
# Power Ports
|
2016-03-01 11:23:03 -05:00
|
|
|
#
|
|
|
|
|
2017-01-26 17:58:36 -05:00
|
|
|
class PowerPortViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
|
|
|
|
queryset = PowerPort.objects.select_related('power_outlet')
|
|
|
|
serializer_class = serializers.PowerPortSerializer
|
|
|
|
|
|
|
|
|
|
|
|
class NestedPowerPortViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
|
2017-01-26 22:37:17 -05:00
|
|
|
serializer_class = serializers.NestedPowerPortSerializer
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
|
|
|
return PowerPort.objects.filter(device=device).select_related('power_outlet')
|
|
|
|
|
|
|
|
|
|
|
|
#
|
2017-01-26 17:58:36 -05:00
|
|
|
# Power Outlets
|
2016-03-01 11:23:03 -05:00
|
|
|
#
|
|
|
|
|
2017-01-26 17:58:36 -05:00
|
|
|
class PowerOutletViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
|
|
|
|
queryset = PowerOutlet.objects.select_related('connected_port')
|
|
|
|
serializer_class = serializers.PowerOutletSerializer
|
|
|
|
|
|
|
|
|
|
|
|
class NestedPowerOutletViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
|
2017-01-26 22:37:17 -05:00
|
|
|
serializer_class = serializers.NestedPowerOutletSerializer
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
|
|
|
return PowerOutlet.objects.filter(device=device).select_related('connected_port')
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Interfaces
|
|
|
|
#
|
|
|
|
|
2017-01-26 17:58:36 -05:00
|
|
|
class InterfaceViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
|
|
|
|
queryset = Interface.objects.select_related('device')
|
|
|
|
serializer_class = serializers.InterfaceDetailSerializer
|
|
|
|
|
|
|
|
|
|
|
|
class NestedInterfaceViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
|
2017-01-26 22:37:17 -05:00
|
|
|
serializer_class = serializers.NestedInterfaceSerializer
|
2016-05-18 16:02:53 -04:00
|
|
|
filter_class = filters.InterfaceFilter
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
2017-01-26 17:58:36 -05:00
|
|
|
return Interface.objects.order_naturally(device.device_type.interface_ordering).filter(device=device)\
|
2017-01-25 14:34:34 -05:00
|
|
|
.select_related('connected_as_a', 'connected_as_b', 'circuit_termination')
|
2016-03-01 11:23:03 -05:00
|
|
|
|
2016-07-15 21:13:15 -07:00
|
|
|
|
2016-07-05 13:43:19 -04:00
|
|
|
#
|
|
|
|
# Device bays
|
|
|
|
#
|
|
|
|
|
2017-01-26 17:58:36 -05:00
|
|
|
class DeviceBayViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
|
|
|
|
queryset = DeviceBay.objects.select_related('installed_device')
|
|
|
|
serializer_class = serializers.DeviceBaySerializer
|
|
|
|
|
|
|
|
|
|
|
|
class NestedDeviceBayViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
|
2017-01-26 22:37:17 -05:00
|
|
|
serializer_class = serializers.NestedDeviceBaySerializer
|
2016-07-05 13:43:19 -04:00
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
2016-08-10 10:44:37 -04:00
|
|
|
return DeviceBay.objects.filter(device=device).select_related('installed_device')
|
2016-07-05 13:43:19 -04:00
|
|
|
|
|
|
|
|
2016-08-10 10:44:37 -04:00
|
|
|
#
|
|
|
|
# Modules
|
|
|
|
#
|
|
|
|
|
2017-01-26 17:58:36 -05:00
|
|
|
class ModuleViewSet(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
|
|
|
|
queryset = Module.objects.select_related('device', 'manufacturer')
|
|
|
|
serializer_class = serializers.ModuleSerializer
|
|
|
|
|
|
|
|
|
|
|
|
class NestedModuleViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
|
2017-01-26 22:37:17 -05:00
|
|
|
serializer_class = serializers.NestedModuleSerializer
|
2016-08-10 10:44:37 -04:00
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
device = get_object_or_404(Device, pk=self.kwargs['pk'])
|
|
|
|
return Module.objects.filter(device=device).select_related('device', 'manufacturer')
|
2016-07-05 13:43:19 -04:00
|
|
|
|
|
|
|
|
2017-01-26 17:58:36 -05:00
|
|
|
#
|
|
|
|
# Interface connections
|
|
|
|
#
|
|
|
|
|
|
|
|
class InterfaceConnectionViewSet(ModelViewSet):
|
|
|
|
queryset = InterfaceConnection.objects.all()
|
|
|
|
serializer_class = serializers.InterfaceConnectionSerializer
|
|
|
|
|
|
|
|
|
2016-03-01 11:23:03 -05:00
|
|
|
#
|
|
|
|
# Live queries
|
|
|
|
#
|
|
|
|
|
|
|
|
class LLDPNeighborsView(APIView):
|
|
|
|
"""
|
|
|
|
Retrieve live LLDP neighbors of a device
|
|
|
|
"""
|
|
|
|
|
|
|
|
def get(self, request, pk):
|
|
|
|
|
|
|
|
device = get_object_or_404(Device, pk=pk)
|
|
|
|
if not device.primary_ip:
|
|
|
|
raise ServiceUnavailable(detail="No IP configured for this device.")
|
|
|
|
|
|
|
|
RPC = device.get_rpc_client()
|
|
|
|
if not RPC:
|
|
|
|
raise ServiceUnavailable(detail="No RPC client available for this platform ({}).".format(device.platform))
|
|
|
|
|
|
|
|
# Connect to device and retrieve inventory info
|
|
|
|
try:
|
|
|
|
with RPC(device, username=settings.NETBOX_USERNAME, password=settings.NETBOX_PASSWORD) as rpc_client:
|
|
|
|
lldp_neighbors = rpc_client.get_lldp_neighbors()
|
|
|
|
except:
|
|
|
|
raise ServiceUnavailable(detail="Error connecting to the remote device.")
|
|
|
|
|
|
|
|
return Response(lldp_neighbors)
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Miscellaneous
|
|
|
|
#
|
|
|
|
|
|
|
|
class RelatedConnectionsView(APIView):
|
|
|
|
"""
|
|
|
|
Retrieve all connections related to a given console/power/interface connection
|
|
|
|
"""
|
|
|
|
|
2016-08-22 17:15:20 -04:00
|
|
|
def __init__(self):
|
|
|
|
super(RelatedConnectionsView, self).__init__()
|
|
|
|
|
|
|
|
# Custom fields
|
2017-01-24 17:12:16 -05:00
|
|
|
content_type = ContentType.objects.get_for_model(Device)
|
|
|
|
custom_fields = content_type.custom_fields.prefetch_related('choices')
|
|
|
|
|
|
|
|
# Cache all relevant CustomFieldChoices. This saves us from having to do a lookup per select field per object.
|
|
|
|
custom_field_choices = {}
|
|
|
|
for field in custom_fields:
|
|
|
|
for cfc in field.choices.all():
|
|
|
|
custom_field_choices[cfc.id] = cfc.value
|
|
|
|
|
|
|
|
self.context = {
|
|
|
|
'custom_fields': custom_fields,
|
|
|
|
'custom_field_choices': custom_field_choices,
|
|
|
|
}
|
2016-08-22 17:15:20 -04:00
|
|
|
|
2016-03-01 11:23:03 -05:00
|
|
|
def get(self, request):
|
|
|
|
|
|
|
|
peer_device = request.GET.get('peer-device')
|
|
|
|
peer_interface = request.GET.get('peer-interface')
|
|
|
|
|
|
|
|
# Search by interface
|
|
|
|
if peer_device and peer_interface:
|
|
|
|
|
|
|
|
# Determine local interface from peer interface's connection
|
|
|
|
try:
|
|
|
|
peer_iface = Interface.objects.get(device__name=peer_device, name=peer_interface)
|
|
|
|
except Interface.DoesNotExist:
|
|
|
|
raise Http404()
|
2016-12-27 13:21:19 -05:00
|
|
|
local_iface = peer_iface.connected_interface
|
2016-03-01 11:23:03 -05:00
|
|
|
if local_iface:
|
|
|
|
device = local_iface.device
|
|
|
|
else:
|
|
|
|
return Response()
|
|
|
|
|
|
|
|
else:
|
2016-07-21 14:48:02 -04:00
|
|
|
raise MissingFilterException(detail='Must specify search parameters "peer-device" and "peer-interface".')
|
2016-03-01 11:23:03 -05:00
|
|
|
|
|
|
|
# Initialize response skeleton
|
2016-07-21 14:48:02 -04:00
|
|
|
response = {
|
2017-01-24 17:12:16 -05:00
|
|
|
'device': serializers.DeviceSerializer(device, context=self.context).data,
|
2016-07-21 14:48:02 -04:00
|
|
|
'console-ports': [],
|
|
|
|
'power-ports': [],
|
|
|
|
'interfaces': [],
|
|
|
|
}
|
|
|
|
|
|
|
|
# Console connections
|
2016-03-01 11:23:03 -05:00
|
|
|
console_ports = ConsolePort.objects.filter(device=device).select_related('cs_port__device')
|
|
|
|
for cp in console_ports:
|
2016-07-21 14:48:02 -04:00
|
|
|
data = serializers.ConsolePortSerializer(instance=cp).data
|
|
|
|
del(data['device'])
|
|
|
|
response['console-ports'].append(data)
|
2016-03-01 11:23:03 -05:00
|
|
|
|
2016-07-21 14:48:02 -04:00
|
|
|
# Power connections
|
2016-03-01 11:23:03 -05:00
|
|
|
power_ports = PowerPort.objects.filter(device=device).select_related('power_outlet__device')
|
|
|
|
for pp in power_ports:
|
2016-07-21 14:48:02 -04:00
|
|
|
data = serializers.PowerPortSerializer(instance=pp).data
|
|
|
|
del(data['device'])
|
|
|
|
response['power-ports'].append(data)
|
2016-03-01 11:23:03 -05:00
|
|
|
|
2016-07-21 14:48:02 -04:00
|
|
|
# Interface connections
|
2017-01-25 14:34:34 -05:00
|
|
|
interfaces = Interface.objects.order_naturally(device.device_type.interface_ordering).filter(device=device)\
|
|
|
|
.select_related('connected_as_a', 'connected_as_b', 'circuit_termination')
|
2016-03-01 11:23:03 -05:00
|
|
|
for iface in interfaces:
|
2016-07-21 14:48:02 -04:00
|
|
|
data = serializers.InterfaceDetailSerializer(instance=iface).data
|
|
|
|
del(data['device'])
|
|
|
|
response['interfaces'].append(data)
|
2016-03-01 11:23:03 -05:00
|
|
|
|
2016-06-16 15:02:01 -04:00
|
|
|
return Response(response)
|