serializers.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. from __future__ import unicode_literals
  2. from rest_framework import serializers
  3. from rest_framework.validators import UniqueTogetherValidator
  4. from ipam.models import IPAddress
  5. from dcim.models import (
  6. CONNECTION_STATUS_CHOICES, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device,
  7. DeviceBay, DeviceBayTemplate, DeviceType, DeviceRole, IFACE_FF_CHOICES, IFACE_ORDERING_CHOICES, Interface,
  8. InterfaceConnection, InterfaceTemplate, Manufacturer, InventoryItem, Platform, PowerOutlet, PowerOutletTemplate, PowerPort,
  9. PowerPortTemplate, Rack, RackGroup, RackReservation, RackRole, RACK_FACE_CHOICES, RACK_TYPE_CHOICES,
  10. RACK_WIDTH_CHOICES, Region, Site, STATUS_CHOICES, SUBDEVICE_ROLE_CHOICES,
  11. )
  12. from extras.api.customfields import CustomFieldModelSerializer
  13. from tenancy.api.serializers import NestedTenantSerializer
  14. from utilities.api import ChoiceFieldSerializer
  15. #
  16. # Regions
  17. #
  18. class NestedRegionSerializer(serializers.ModelSerializer):
  19. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail')
  20. class Meta:
  21. model = Region
  22. fields = ['id', 'url', 'name', 'slug']
  23. class RegionSerializer(serializers.ModelSerializer):
  24. parent = NestedRegionSerializer()
  25. class Meta:
  26. model = Region
  27. fields = ['id', 'name', 'slug', 'parent']
  28. class WritableRegionSerializer(serializers.ModelSerializer):
  29. class Meta:
  30. model = Region
  31. fields = ['id', 'name', 'slug', 'parent']
  32. #
  33. # Sites
  34. #
  35. class SiteSerializer(CustomFieldModelSerializer):
  36. region = NestedRegionSerializer()
  37. tenant = NestedTenantSerializer()
  38. class Meta:
  39. model = Site
  40. fields = [
  41. 'id', 'name', 'slug', 'region', 'tenant', 'facility', 'asn', 'physical_address', 'shipping_address',
  42. 'contact_name', 'contact_phone', 'contact_email', 'comments', 'custom_fields', 'count_prefixes',
  43. 'count_vlans', 'count_racks', 'count_devices', 'count_circuits',
  44. ]
  45. class NestedSiteSerializer(serializers.ModelSerializer):
  46. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:site-detail')
  47. class Meta:
  48. model = Site
  49. fields = ['id', 'url', 'name', 'slug']
  50. class WritableSiteSerializer(CustomFieldModelSerializer):
  51. class Meta:
  52. model = Site
  53. fields = [
  54. 'id', 'name', 'slug', 'region', 'tenant', 'facility', 'asn', 'physical_address', 'shipping_address',
  55. 'contact_name', 'contact_phone', 'contact_email', 'comments', 'custom_fields',
  56. ]
  57. #
  58. # Rack groups
  59. #
  60. class RackGroupSerializer(serializers.ModelSerializer):
  61. site = NestedSiteSerializer()
  62. class Meta:
  63. model = RackGroup
  64. fields = ['id', 'name', 'slug', 'site']
  65. class NestedRackGroupSerializer(serializers.ModelSerializer):
  66. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackgroup-detail')
  67. class Meta:
  68. model = RackGroup
  69. fields = ['id', 'url', 'name', 'slug']
  70. class WritableRackGroupSerializer(serializers.ModelSerializer):
  71. class Meta:
  72. model = RackGroup
  73. fields = ['id', 'name', 'slug', 'site']
  74. #
  75. # Rack roles
  76. #
  77. class RackRoleSerializer(serializers.ModelSerializer):
  78. class Meta:
  79. model = RackRole
  80. fields = ['id', 'name', 'slug', 'color']
  81. class NestedRackRoleSerializer(serializers.ModelSerializer):
  82. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail')
  83. class Meta:
  84. model = RackRole
  85. fields = ['id', 'url', 'name', 'slug']
  86. #
  87. # Racks
  88. #
  89. class RackSerializer(CustomFieldModelSerializer):
  90. site = NestedSiteSerializer()
  91. group = NestedRackGroupSerializer()
  92. tenant = NestedTenantSerializer()
  93. role = NestedRackRoleSerializer()
  94. type = ChoiceFieldSerializer(choices=RACK_TYPE_CHOICES)
  95. width = ChoiceFieldSerializer(choices=RACK_WIDTH_CHOICES)
  96. class Meta:
  97. model = Rack
  98. fields = [
  99. 'id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'role', 'type', 'width', 'u_height',
  100. 'desc_units', 'comments', 'custom_fields',
  101. ]
  102. class NestedRackSerializer(serializers.ModelSerializer):
  103. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rack-detail')
  104. class Meta:
  105. model = Rack
  106. fields = ['id', 'url', 'name', 'display_name']
  107. class WritableRackSerializer(CustomFieldModelSerializer):
  108. class Meta:
  109. model = Rack
  110. fields = [
  111. 'id', 'name', 'facility_id', 'site', 'group', 'tenant', 'role', 'type', 'width', 'u_height', 'desc_units',
  112. 'comments', 'custom_fields',
  113. ]
  114. # Omit the UniqueTogetherValidator that would be automatically added to validate (site, facility_id). This
  115. # prevents facility_id from being interpreted as a required field.
  116. validators = [
  117. UniqueTogetherValidator(queryset=Rack.objects.all(), fields=('site', 'name'))
  118. ]
  119. def validate(self, data):
  120. # Validate uniqueness of (site, facility_id) since we omitted the automatically-created validator from Meta.
  121. if data.get('facility_id', None):
  122. validator = UniqueTogetherValidator(queryset=Rack.objects.all(), fields=('site', 'facility_id'))
  123. validator.set_context(self)
  124. validator(data)
  125. return data
  126. #
  127. # Rack units
  128. #
  129. class NestedDeviceSerializer(serializers.ModelSerializer):
  130. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail')
  131. class Meta:
  132. model = Device
  133. fields = ['id', 'url', 'name', 'display_name']
  134. class RackUnitSerializer(serializers.Serializer):
  135. """
  136. A rack unit is an abstraction formed by the set (rack, position, face); it does not exist as a row in the database.
  137. """
  138. id = serializers.IntegerField(read_only=True)
  139. name = serializers.CharField(read_only=True)
  140. face = serializers.IntegerField(read_only=True)
  141. device = NestedDeviceSerializer(read_only=True)
  142. #
  143. # Rack reservations
  144. #
  145. class RackReservationSerializer(serializers.ModelSerializer):
  146. rack = NestedRackSerializer()
  147. class Meta:
  148. model = RackReservation
  149. fields = ['id', 'rack', 'units', 'created', 'user', 'description']
  150. class WritableRackReservationSerializer(serializers.ModelSerializer):
  151. class Meta:
  152. model = RackReservation
  153. fields = ['id', 'rack', 'units', 'description']
  154. #
  155. # Manufacturers
  156. #
  157. class ManufacturerSerializer(serializers.ModelSerializer):
  158. class Meta:
  159. model = Manufacturer
  160. fields = ['id', 'name', 'slug']
  161. class NestedManufacturerSerializer(serializers.ModelSerializer):
  162. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail')
  163. class Meta:
  164. model = Manufacturer
  165. fields = ['id', 'url', 'name', 'slug']
  166. #
  167. # Device types
  168. #
  169. class DeviceTypeSerializer(CustomFieldModelSerializer):
  170. manufacturer = NestedManufacturerSerializer()
  171. interface_ordering = ChoiceFieldSerializer(choices=IFACE_ORDERING_CHOICES)
  172. subdevice_role = ChoiceFieldSerializer(choices=SUBDEVICE_ROLE_CHOICES)
  173. instance_count = serializers.IntegerField(source='instances.count', read_only=True)
  174. class Meta:
  175. model = DeviceType
  176. fields = [
  177. 'id', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'interface_ordering',
  178. 'is_console_server', 'is_pdu', 'is_network_device', 'subdevice_role', 'comments', 'custom_fields',
  179. 'instance_count',
  180. ]
  181. class NestedDeviceTypeSerializer(serializers.ModelSerializer):
  182. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail')
  183. manufacturer = NestedManufacturerSerializer()
  184. class Meta:
  185. model = DeviceType
  186. fields = ['id', 'url', 'manufacturer', 'model', 'slug']
  187. class WritableDeviceTypeSerializer(CustomFieldModelSerializer):
  188. class Meta:
  189. model = DeviceType
  190. fields = [
  191. 'id', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'interface_ordering',
  192. 'is_console_server', 'is_pdu', 'is_network_device', 'subdevice_role', 'comments', 'custom_fields',
  193. ]
  194. #
  195. # Console port templates
  196. #
  197. class ConsolePortTemplateSerializer(serializers.ModelSerializer):
  198. device_type = NestedDeviceTypeSerializer()
  199. class Meta:
  200. model = ConsolePortTemplate
  201. fields = ['id', 'device_type', 'name']
  202. class WritableConsolePortTemplateSerializer(serializers.ModelSerializer):
  203. class Meta:
  204. model = ConsolePortTemplate
  205. fields = ['id', 'device_type', 'name']
  206. #
  207. # Console server port templates
  208. #
  209. class ConsoleServerPortTemplateSerializer(serializers.ModelSerializer):
  210. device_type = NestedDeviceTypeSerializer()
  211. class Meta:
  212. model = ConsoleServerPortTemplate
  213. fields = ['id', 'device_type', 'name']
  214. class WritableConsoleServerPortTemplateSerializer(serializers.ModelSerializer):
  215. class Meta:
  216. model = ConsoleServerPortTemplate
  217. fields = ['id', 'device_type', 'name']
  218. #
  219. # Power port templates
  220. #
  221. class PowerPortTemplateSerializer(serializers.ModelSerializer):
  222. device_type = NestedDeviceTypeSerializer()
  223. class Meta:
  224. model = PowerPortTemplate
  225. fields = ['id', 'device_type', 'name']
  226. class WritablePowerPortTemplateSerializer(serializers.ModelSerializer):
  227. class Meta:
  228. model = PowerPortTemplate
  229. fields = ['id', 'device_type', 'name']
  230. #
  231. # Power outlet templates
  232. #
  233. class PowerOutletTemplateSerializer(serializers.ModelSerializer):
  234. device_type = NestedDeviceTypeSerializer()
  235. class Meta:
  236. model = PowerOutletTemplate
  237. fields = ['id', 'device_type', 'name']
  238. class WritablePowerOutletTemplateSerializer(serializers.ModelSerializer):
  239. class Meta:
  240. model = PowerOutletTemplate
  241. fields = ['id', 'device_type', 'name']
  242. #
  243. # Interface templates
  244. #
  245. class InterfaceTemplateSerializer(serializers.ModelSerializer):
  246. device_type = NestedDeviceTypeSerializer()
  247. form_factor = ChoiceFieldSerializer(choices=IFACE_FF_CHOICES)
  248. class Meta:
  249. model = InterfaceTemplate
  250. fields = ['id', 'device_type', 'name', 'form_factor', 'mgmt_only']
  251. class WritableInterfaceTemplateSerializer(serializers.ModelSerializer):
  252. class Meta:
  253. model = InterfaceTemplate
  254. fields = ['id', 'device_type', 'name', 'form_factor', 'mgmt_only']
  255. #
  256. # Device bay templates
  257. #
  258. class DeviceBayTemplateSerializer(serializers.ModelSerializer):
  259. device_type = NestedDeviceTypeSerializer()
  260. class Meta:
  261. model = DeviceBayTemplate
  262. fields = ['id', 'device_type', 'name']
  263. class WritableDeviceBayTemplateSerializer(serializers.ModelSerializer):
  264. class Meta:
  265. model = DeviceBayTemplate
  266. fields = ['id', 'device_type', 'name']
  267. #
  268. # Device roles
  269. #
  270. class DeviceRoleSerializer(serializers.ModelSerializer):
  271. class Meta:
  272. model = DeviceRole
  273. fields = ['id', 'name', 'slug', 'color']
  274. class NestedDeviceRoleSerializer(serializers.ModelSerializer):
  275. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail')
  276. class Meta:
  277. model = DeviceRole
  278. fields = ['id', 'url', 'name', 'slug']
  279. #
  280. # Platforms
  281. #
  282. class PlatformSerializer(serializers.ModelSerializer):
  283. class Meta:
  284. model = Platform
  285. fields = ['id', 'name', 'slug', 'rpc_client']
  286. class NestedPlatformSerializer(serializers.ModelSerializer):
  287. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail')
  288. class Meta:
  289. model = Platform
  290. fields = ['id', 'url', 'name', 'slug']
  291. #
  292. # Devices
  293. #
  294. # Cannot import ipam.api.NestedIPAddressSerializer due to circular dependency
  295. class DeviceIPAddressSerializer(serializers.ModelSerializer):
  296. url = serializers.HyperlinkedIdentityField(view_name='ipam-api:ipaddress-detail')
  297. class Meta:
  298. model = IPAddress
  299. fields = ['id', 'url', 'family', 'address']
  300. class DeviceSerializer(CustomFieldModelSerializer):
  301. device_type = NestedDeviceTypeSerializer()
  302. device_role = NestedDeviceRoleSerializer()
  303. tenant = NestedTenantSerializer()
  304. platform = NestedPlatformSerializer()
  305. site = NestedSiteSerializer()
  306. rack = NestedRackSerializer()
  307. face = ChoiceFieldSerializer(choices=RACK_FACE_CHOICES)
  308. status = ChoiceFieldSerializer(choices=STATUS_CHOICES)
  309. primary_ip = DeviceIPAddressSerializer()
  310. primary_ip4 = DeviceIPAddressSerializer()
  311. primary_ip6 = DeviceIPAddressSerializer()
  312. parent_device = serializers.SerializerMethodField()
  313. class Meta:
  314. model = Device
  315. fields = [
  316. 'id', 'name', 'display_name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag',
  317. 'site', 'rack', 'position', 'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4', 'primary_ip6',
  318. 'comments', 'custom_fields',
  319. ]
  320. def get_parent_device(self, obj):
  321. try:
  322. device_bay = obj.parent_bay
  323. except DeviceBay.DoesNotExist:
  324. return None
  325. return {
  326. 'id': device_bay.device.pk,
  327. 'name': device_bay.device.name,
  328. 'device_bay': {
  329. 'id': device_bay.pk,
  330. 'name': device_bay.name,
  331. }
  332. }
  333. class WritableDeviceSerializer(CustomFieldModelSerializer):
  334. class Meta:
  335. model = Device
  336. fields = [
  337. 'id', 'name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag', 'site', 'rack',
  338. 'position', 'face', 'status', 'primary_ip4', 'primary_ip6', 'comments', 'custom_fields',
  339. ]
  340. validators = []
  341. def validate(self, data):
  342. # Validate uniqueness of (rack, position, face) since we omitted the automatically-created validator from Meta.
  343. if data.get('rack') and data.get('position') and data.get('face'):
  344. validator = UniqueTogetherValidator(queryset=Device.objects.all(), fields=('rack', 'position', 'face'))
  345. validator.set_context(self)
  346. validator(data)
  347. return data
  348. #
  349. # Console server ports
  350. #
  351. class ConsoleServerPortSerializer(serializers.ModelSerializer):
  352. device = NestedDeviceSerializer()
  353. class Meta:
  354. model = ConsoleServerPort
  355. fields = ['id', 'device', 'name', 'connected_console']
  356. read_only_fields = ['connected_console']
  357. class WritableConsoleServerPortSerializer(serializers.ModelSerializer):
  358. class Meta:
  359. model = ConsoleServerPort
  360. fields = ['id', 'device', 'name']
  361. #
  362. # Console ports
  363. #
  364. class ConsolePortSerializer(serializers.ModelSerializer):
  365. device = NestedDeviceSerializer()
  366. cs_port = ConsoleServerPortSerializer()
  367. class Meta:
  368. model = ConsolePort
  369. fields = ['id', 'device', 'name', 'cs_port', 'connection_status']
  370. class WritableConsolePortSerializer(serializers.ModelSerializer):
  371. class Meta:
  372. model = ConsolePort
  373. fields = ['id', 'device', 'name', 'cs_port', 'connection_status']
  374. #
  375. # Power outlets
  376. #
  377. class PowerOutletSerializer(serializers.ModelSerializer):
  378. device = NestedDeviceSerializer()
  379. class Meta:
  380. model = PowerOutlet
  381. fields = ['id', 'device', 'name', 'connected_port']
  382. read_only_fields = ['connected_port']
  383. class WritablePowerOutletSerializer(serializers.ModelSerializer):
  384. class Meta:
  385. model = PowerOutlet
  386. fields = ['id', 'device', 'name']
  387. #
  388. # Power ports
  389. #
  390. class PowerPortSerializer(serializers.ModelSerializer):
  391. device = NestedDeviceSerializer()
  392. power_outlet = PowerOutletSerializer()
  393. class Meta:
  394. model = PowerPort
  395. fields = ['id', 'device', 'name', 'power_outlet', 'connection_status']
  396. class WritablePowerPortSerializer(serializers.ModelSerializer):
  397. class Meta:
  398. model = PowerPort
  399. fields = ['id', 'device', 'name', 'power_outlet', 'connection_status']
  400. #
  401. # Interfaces
  402. #
  403. class NestedInterfaceSerializer(serializers.ModelSerializer):
  404. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
  405. class Meta:
  406. model = Interface
  407. fields = ['id', 'url', 'name']
  408. class InterfaceSerializer(serializers.ModelSerializer):
  409. device = NestedDeviceSerializer()
  410. form_factor = ChoiceFieldSerializer(choices=IFACE_FF_CHOICES)
  411. lag = NestedInterfaceSerializer()
  412. connection = serializers.SerializerMethodField(read_only=True)
  413. connected_interface = serializers.SerializerMethodField(read_only=True)
  414. class Meta:
  415. model = Interface
  416. fields = [
  417. 'id', 'device', 'name', 'form_factor', 'lag', 'mac_address', 'mgmt_only', 'description', 'connection',
  418. 'connected_interface',
  419. ]
  420. def get_connection(self, obj):
  421. if obj.connection:
  422. return NestedInterfaceConnectionSerializer(obj.connection, context=self.context).data
  423. return None
  424. def get_connected_interface(self, obj):
  425. if obj.connected_interface:
  426. return PeerInterfaceSerializer(obj.connected_interface, context=self.context).data
  427. return None
  428. class PeerInterfaceSerializer(serializers.ModelSerializer):
  429. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
  430. device = NestedDeviceSerializer()
  431. form_factor = ChoiceFieldSerializer(choices=IFACE_FF_CHOICES)
  432. lag = NestedInterfaceSerializer()
  433. class Meta:
  434. model = Interface
  435. fields = ['id', 'url', 'device', 'name', 'form_factor', 'lag', 'mac_address', 'mgmt_only', 'description']
  436. class WritableInterfaceSerializer(serializers.ModelSerializer):
  437. class Meta:
  438. model = Interface
  439. fields = ['id', 'device', 'name', 'form_factor', 'lag', 'mac_address', 'mgmt_only', 'description']
  440. #
  441. # Device bays
  442. #
  443. class DeviceBaySerializer(serializers.ModelSerializer):
  444. device = NestedDeviceSerializer()
  445. installed_device = NestedDeviceSerializer()
  446. class Meta:
  447. model = DeviceBay
  448. fields = ['id', 'device', 'name', 'installed_device']
  449. class WritableDeviceBaySerializer(serializers.ModelSerializer):
  450. class Meta:
  451. model = DeviceBay
  452. fields = ['id', 'device', 'name', 'installed_device']
  453. #
  454. # Inventory items
  455. #
  456. class InventoryItemSerializer(serializers.ModelSerializer):
  457. device = NestedDeviceSerializer()
  458. manufacturer = NestedManufacturerSerializer()
  459. class Meta:
  460. model = InventoryItem
  461. fields = ['id', 'device', 'parent', 'name', 'manufacturer', 'part_id', 'serial', 'discovered']
  462. class WritableInventoryItemSerializer(serializers.ModelSerializer):
  463. class Meta:
  464. model = InventoryItem
  465. fields = ['id', 'device', 'parent', 'name', 'manufacturer', 'part_id', 'serial', 'discovered']
  466. #
  467. # Interface connections
  468. #
  469. class InterfaceConnectionSerializer(serializers.ModelSerializer):
  470. interface_a = PeerInterfaceSerializer()
  471. interface_b = PeerInterfaceSerializer()
  472. connection_status = ChoiceFieldSerializer(choices=CONNECTION_STATUS_CHOICES)
  473. class Meta:
  474. model = InterfaceConnection
  475. fields = ['id', 'interface_a', 'interface_b', 'connection_status']
  476. class NestedInterfaceConnectionSerializer(serializers.ModelSerializer):
  477. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interfaceconnection-detail')
  478. class Meta:
  479. model = InterfaceConnection
  480. fields = ['id', 'url', 'connection_status']
  481. class WritableInterfaceConnectionSerializer(serializers.ModelSerializer):
  482. class Meta:
  483. model = InterfaceConnection
  484. fields = ['id', 'interface_a', 'interface_b', 'connection_status']