views.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. from rest_framework import generics
  2. from rest_framework.permissions import DjangoModelPermissionsOrAnonReadOnly
  3. from rest_framework.response import Response
  4. from rest_framework.settings import api_settings
  5. from rest_framework.views import APIView
  6. from django.conf import settings
  7. from django.http import Http404
  8. from django.shortcuts import get_object_or_404
  9. from dcim.models import Site, Rack, RackGroup, Manufacturer, DeviceType, DeviceRole, Platform, Device, ConsolePort, \
  10. ConsoleServerPort, PowerPort, PowerOutlet, Interface, InterfaceConnection, IFACE_FF_VIRTUAL
  11. from dcim.filters import RackGroupFilter, RackFilter, DeviceTypeFilter, DeviceFilter, InterfaceFilter
  12. from .exceptions import MissingFilterException
  13. from .serializers import SiteSerializer, RackGroupSerializer, RackSerializer, RackDetailSerializer, \
  14. ManufacturerSerializer, DeviceTypeSerializer, DeviceRoleSerializer, PlatformSerializer, DeviceSerializer, \
  15. DeviceNestedSerializer, ConsolePortSerializer, ConsoleServerPortSerializer, PowerPortSerializer, \
  16. PowerOutletSerializer, InterfaceSerializer, InterfaceDetailSerializer, InterfaceConnectionSerializer
  17. from extras.api.renderers import BINDZoneRenderer, FlatJSONRenderer
  18. from utilities.api import ServiceUnavailable
  19. #
  20. # Sites
  21. #
  22. class SiteListView(generics.ListAPIView):
  23. """
  24. List all sites
  25. """
  26. queryset = Site.objects.all()
  27. serializer_class = SiteSerializer
  28. class SiteDetailView(generics.RetrieveAPIView):
  29. """
  30. Retrieve a single site
  31. """
  32. queryset = Site.objects.all()
  33. serializer_class = SiteSerializer
  34. #
  35. # Rack groups
  36. #
  37. class RackGroupListView(generics.ListAPIView):
  38. """
  39. List all rack groups
  40. """
  41. queryset = RackGroup.objects.all()
  42. serializer_class = RackGroupSerializer
  43. filter_class = RackGroupFilter
  44. class RackGroupDetailView(generics.RetrieveAPIView):
  45. """
  46. Retrieve a single rack group
  47. """
  48. queryset = RackGroup.objects.all()
  49. serializer_class = RackGroupSerializer
  50. #
  51. # Racks
  52. #
  53. class RackListView(generics.ListAPIView):
  54. """
  55. List racks (filterable)
  56. """
  57. queryset = Rack.objects.select_related('site')
  58. serializer_class = RackSerializer
  59. filter_class = RackFilter
  60. class RackDetailView(generics.RetrieveAPIView):
  61. """
  62. Retrieve a single rack
  63. """
  64. queryset = Rack.objects.select_related('site')
  65. serializer_class = RackDetailSerializer
  66. #
  67. # Rack units
  68. #
  69. class RackUnitListView(APIView):
  70. """
  71. List rack units (by rack)
  72. """
  73. def get(self, request, pk):
  74. rack = get_object_or_404(Rack, pk=pk)
  75. face = request.GET.get('face', 0)
  76. elevation = rack.get_rack_units(face)
  77. # Serialize Devices within the rack elevation
  78. for u in elevation:
  79. if u['device']:
  80. u['device'] = DeviceNestedSerializer(instance=u['device']).data
  81. return Response(elevation)
  82. #
  83. # Manufacturers
  84. #
  85. class ManufacturerListView(generics.ListAPIView):
  86. """
  87. List all hardware manufacturers
  88. """
  89. queryset = Manufacturer.objects.all()
  90. serializer_class = ManufacturerSerializer
  91. class ManufacturerDetailView(generics.RetrieveAPIView):
  92. """
  93. Retrieve a single hardware manufacturers
  94. """
  95. queryset = Manufacturer.objects.all()
  96. serializer_class = ManufacturerSerializer
  97. #
  98. # Device Types
  99. #
  100. class DeviceTypeListView(generics.ListAPIView):
  101. """
  102. List device types (filterable)
  103. """
  104. queryset = DeviceType.objects.select_related('manufacturer')
  105. serializer_class = DeviceTypeSerializer
  106. filter_class = DeviceTypeFilter
  107. class DeviceTypeDetailView(generics.RetrieveAPIView):
  108. """
  109. Retrieve a single device type
  110. """
  111. queryset = DeviceType.objects.select_related('manufacturer')
  112. serializer_class = DeviceTypeSerializer
  113. #
  114. # Device roles
  115. #
  116. class DeviceRoleListView(generics.ListAPIView):
  117. """
  118. List all device roles
  119. """
  120. queryset = DeviceRole.objects.all()
  121. serializer_class = DeviceRoleSerializer
  122. class DeviceRoleDetailView(generics.RetrieveAPIView):
  123. """
  124. Retrieve a single device role
  125. """
  126. queryset = DeviceRole.objects.all()
  127. serializer_class = DeviceRoleSerializer
  128. #
  129. # Platforms
  130. #
  131. class PlatformListView(generics.ListAPIView):
  132. """
  133. List all platforms
  134. """
  135. queryset = Platform.objects.all()
  136. serializer_class = PlatformSerializer
  137. class PlatformDetailView(generics.RetrieveAPIView):
  138. """
  139. Retrieve a single platform
  140. """
  141. queryset = Platform.objects.all()
  142. serializer_class = PlatformSerializer
  143. #
  144. # Devices
  145. #
  146. class DeviceListView(generics.ListAPIView):
  147. """
  148. List devices (filterable)
  149. """
  150. queryset = Device.objects.select_related('device_type__manufacturer', 'device_role', 'platform', 'rack__site')\
  151. .prefetch_related('primary_ip__nat_outside')
  152. serializer_class = DeviceSerializer
  153. filter_class = DeviceFilter
  154. renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + [BINDZoneRenderer, FlatJSONRenderer]
  155. class DeviceDetailView(generics.RetrieveAPIView):
  156. """
  157. Retrieve a single device
  158. """
  159. queryset = Device.objects.all()
  160. serializer_class = DeviceSerializer
  161. #
  162. # Console ports
  163. #
  164. class ConsolePortListView(generics.ListAPIView):
  165. """
  166. List console ports (by device)
  167. """
  168. serializer_class = ConsolePortSerializer
  169. def get_queryset(self):
  170. device = get_object_or_404(Device, pk=self.kwargs['pk'])
  171. return ConsolePort.objects.filter(device=device).select_related('cs_port')
  172. class ConsolePortView(generics.RetrieveUpdateDestroyAPIView):
  173. permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
  174. serializer_class = ConsolePortSerializer
  175. queryset = ConsolePort.objects.all()
  176. #
  177. # Console server ports
  178. #
  179. class ConsoleServerPortListView(generics.ListAPIView):
  180. """
  181. List console server ports (by device)
  182. """
  183. serializer_class = ConsoleServerPortSerializer
  184. def get_queryset(self):
  185. device = get_object_or_404(Device, pk=self.kwargs['pk'])
  186. return ConsoleServerPort.objects.filter(device=device).select_related('connected_console')
  187. #
  188. # Power ports
  189. #
  190. class PowerPortListView(generics.ListAPIView):
  191. """
  192. List power ports (by device)
  193. """
  194. serializer_class = PowerPortSerializer
  195. def get_queryset(self):
  196. device = get_object_or_404(Device, pk=self.kwargs['pk'])
  197. return PowerPort.objects.filter(device=device).select_related('power_outlet')
  198. class PowerPortView(generics.RetrieveUpdateDestroyAPIView):
  199. permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
  200. serializer_class = PowerPortSerializer
  201. queryset = PowerPort.objects.all()
  202. #
  203. # Power outlets
  204. #
  205. class PowerOutletListView(generics.ListAPIView):
  206. """
  207. List power outlets (by device)
  208. """
  209. serializer_class = PowerOutletSerializer
  210. def get_queryset(self):
  211. device = get_object_or_404(Device, pk=self.kwargs['pk'])
  212. return PowerOutlet.objects.filter(device=device).select_related('connected_port')
  213. #
  214. # Interfaces
  215. #
  216. class InterfaceListView(generics.ListAPIView):
  217. """
  218. List interfaces (by device)
  219. """
  220. serializer_class = InterfaceSerializer
  221. filter_class = InterfaceFilter
  222. def get_queryset(self):
  223. device = get_object_or_404(Device, pk=self.kwargs['pk'])
  224. queryset = Interface.objects.filter(device=device).select_related('connected_as_a', 'connected_as_b')
  225. # Filter by type (physical or virtual)
  226. iface_type = self.request.query_params.get('type')
  227. if iface_type == 'physical':
  228. queryset = queryset.exclude(form_factor=IFACE_FF_VIRTUAL)
  229. elif iface_type == 'virtual':
  230. queryset = queryset.filter(form_factor=IFACE_FF_VIRTUAL)
  231. elif iface_type is not None:
  232. queryset = queryset.empty()
  233. return queryset
  234. class InterfaceDetailView(generics.RetrieveAPIView):
  235. """
  236. Retrieve a single interface
  237. """
  238. queryset = Interface.objects.select_related('device')
  239. serializer_class = InterfaceDetailSerializer
  240. class InterfaceConnectionView(generics.RetrieveUpdateDestroyAPIView):
  241. permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
  242. serializer_class = InterfaceConnectionSerializer
  243. queryset = InterfaceConnection.objects.all()
  244. #
  245. # Live queries
  246. #
  247. class LLDPNeighborsView(APIView):
  248. """
  249. Retrieve live LLDP neighbors of a device
  250. """
  251. def get(self, request, pk):
  252. device = get_object_or_404(Device, pk=pk)
  253. if not device.primary_ip:
  254. raise ServiceUnavailable(detail="No IP configured for this device.")
  255. hostname = str(device.primary_ip.address.ip)
  256. RPC = device.get_rpc_client()
  257. if not RPC:
  258. raise ServiceUnavailable(detail="No RPC client available for this platform ({}).".format(device.platform))
  259. # Connect to device and retrieve inventory info
  260. try:
  261. with RPC(device, username=settings.NETBOX_USERNAME, password=settings.NETBOX_PASSWORD) as rpc_client:
  262. lldp_neighbors = rpc_client.get_lldp_neighbors()
  263. except:
  264. raise ServiceUnavailable(detail="Error connecting to the remote device.")
  265. return Response(lldp_neighbors)
  266. #
  267. # Miscellaneous
  268. #
  269. class RelatedConnectionsView(APIView):
  270. """
  271. Retrieve all connections related to a given console/power/interface connection
  272. """
  273. def get(self, request):
  274. peer_device = request.GET.get('peer-device')
  275. peer_interface = request.GET.get('peer-interface')
  276. # Search by interface
  277. if peer_device and peer_interface:
  278. # Determine local interface from peer interface's connection
  279. try:
  280. peer_iface = Interface.objects.get(device__name=peer_device, name=peer_interface)
  281. except Interface.DoesNotExist:
  282. raise Http404()
  283. local_iface = peer_iface.get_connected_interface()
  284. if local_iface:
  285. device = local_iface.device
  286. else:
  287. return Response()
  288. else:
  289. raise MissingFilterException(detail='Must specify search parameters (peer-device and peer-interface).')
  290. # Initialize response skeleton
  291. response = dict()
  292. response['device'] = DeviceSerializer(device).data
  293. response['console-ports'] = []
  294. response['power-ports'] = []
  295. response['interfaces'] = []
  296. # Build console connections
  297. console_ports = ConsolePort.objects.filter(device=device).select_related('cs_port__device')
  298. for cp in console_ports:
  299. cp_info = dict()
  300. cp_info['name'] = cp.name
  301. if cp.cs_port:
  302. cp_info['console-server'] = cp.cs_port.device.name
  303. cp_info['port'] = cp.cs_port.name
  304. else:
  305. cp_info['console-server'] = None
  306. cp_info['port'] = None
  307. response['console-ports'].append(cp_info)
  308. # Build power connections
  309. power_ports = PowerPort.objects.filter(device=device).select_related('power_outlet__device')
  310. for pp in power_ports:
  311. pp_info = dict()
  312. pp_info['name'] = pp.name
  313. if pp.power_outlet:
  314. pp_info['pdu'] = pp.power_outlet.device.name
  315. pp_info['outlet'] = pp.power_outlet.name
  316. else:
  317. pp_info['pdu'] = None
  318. pp_info['outlet'] = None
  319. response['power-ports'].append(pp_info)
  320. # Built interface connections
  321. interfaces = Interface.objects.filter(device=device)
  322. for iface in interfaces:
  323. iface_info = dict()
  324. iface_info['name'] = iface.name
  325. peer_interface = iface.get_connected_interface()
  326. if peer_interface:
  327. iface_info['device'] = peer_interface.device.name
  328. iface_info['interface'] = peer_interface.name
  329. else:
  330. iface_info['device'] = None
  331. iface_info['interface'] = None
  332. response['interfaces'].append(iface_info)
  333. return Response(response)