serializers.py 18 KB

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