devices.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. import django_tables2 as tables
  2. from django_tables2.utils import Accessor
  3. from django.conf import settings
  4. from dcim.models import (
  5. ConsolePort, ConsoleServerPort, Device, DeviceBay, DeviceRole, FrontPort, Interface, InventoryItem, Platform,
  6. PowerOutlet, PowerPort, RearPort, VirtualChassis,
  7. )
  8. from tenancy.tables import TenantColumn
  9. from utilities.tables import (
  10. BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ColorColumn, ColoredLabelColumn, LinkedCountColumn,
  11. MarkdownColumn, TagColumn, TemplateColumn, ToggleColumn,
  12. )
  13. from .template_code import (
  14. CABLETERMINATION, CONSOLEPORT_BUTTONS, CONSOLESERVERPORT_BUTTONS, DEVICE_LINK, DEVICEBAY_BUTTONS, DEVICEBAY_STATUS,
  15. FRONTPORT_BUTTONS, INTERFACE_BUTTONS, INTERFACE_IPADDRESSES, INTERFACE_TAGGED_VLANS, POWEROUTLET_BUTTONS,
  16. POWERPORT_BUTTONS, REARPORT_BUTTONS,
  17. )
  18. __all__ = (
  19. 'BaseInterfaceTable',
  20. 'ConsolePortTable',
  21. 'ConsoleServerPortTable',
  22. 'DeviceBayTable',
  23. 'DeviceConsolePortTable',
  24. 'DeviceConsoleServerPortTable',
  25. 'DeviceDeviceBayTable',
  26. 'DeviceFrontPortTable',
  27. 'DeviceImportTable',
  28. 'DeviceInterfaceTable',
  29. 'DeviceInventoryItemTable',
  30. 'DevicePowerPortTable',
  31. 'DevicePowerOutletTable',
  32. 'DeviceRearPortTable',
  33. 'DeviceRoleTable',
  34. 'DeviceTable',
  35. 'FrontPortTable',
  36. 'InterfaceTable',
  37. 'InventoryItemTable',
  38. 'PlatformTable',
  39. 'PowerOutletTable',
  40. 'PowerPortTable',
  41. 'RearPortTable',
  42. 'VirtualChassisTable',
  43. )
  44. def get_cabletermination_row_class(record):
  45. if record.mark_connected:
  46. return 'success'
  47. elif record.cable:
  48. return record.cable.get_status_class()
  49. return ''
  50. def get_interface_state_attribute(record):
  51. """
  52. Get interface enabled state as string to attach to <tr/> DOM element.
  53. """
  54. if record.enabled:
  55. return "enabled"
  56. else:
  57. return "disabled"
  58. #
  59. # Device roles
  60. #
  61. class DeviceRoleTable(BaseTable):
  62. pk = ToggleColumn()
  63. name = tables.Column(
  64. linkify=True
  65. )
  66. device_count = LinkedCountColumn(
  67. viewname='dcim:device_list',
  68. url_params={'role_id': 'pk'},
  69. verbose_name='Devices'
  70. )
  71. vm_count = LinkedCountColumn(
  72. viewname='virtualization:virtualmachine_list',
  73. url_params={'role_id': 'pk'},
  74. verbose_name='VMs'
  75. )
  76. color = ColorColumn()
  77. vm_role = BooleanColumn()
  78. actions = ButtonsColumn(DeviceRole)
  79. class Meta(BaseTable.Meta):
  80. model = DeviceRole
  81. fields = ('pk', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'description', 'slug', 'actions')
  82. default_columns = ('pk', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'description', 'actions')
  83. #
  84. # Platforms
  85. #
  86. class PlatformTable(BaseTable):
  87. pk = ToggleColumn()
  88. name = tables.Column(
  89. linkify=True
  90. )
  91. device_count = LinkedCountColumn(
  92. viewname='dcim:device_list',
  93. url_params={'platform_id': 'pk'},
  94. verbose_name='Devices'
  95. )
  96. vm_count = LinkedCountColumn(
  97. viewname='virtualization:virtualmachine_list',
  98. url_params={'platform_id': 'pk'},
  99. verbose_name='VMs'
  100. )
  101. actions = ButtonsColumn(Platform)
  102. class Meta(BaseTable.Meta):
  103. model = Platform
  104. fields = (
  105. 'pk', 'name', 'manufacturer', 'device_count', 'vm_count', 'slug', 'napalm_driver', 'napalm_args',
  106. 'description', 'actions',
  107. )
  108. default_columns = (
  109. 'pk', 'name', 'manufacturer', 'device_count', 'vm_count', 'napalm_driver', 'description', 'actions',
  110. )
  111. #
  112. # Devices
  113. #
  114. class DeviceTable(BaseTable):
  115. pk = ToggleColumn()
  116. name = tables.TemplateColumn(
  117. order_by=('_name',),
  118. template_code=DEVICE_LINK
  119. )
  120. status = ChoiceFieldColumn()
  121. tenant = TenantColumn()
  122. site = tables.Column(
  123. linkify=True
  124. )
  125. location = tables.Column(
  126. linkify=True
  127. )
  128. rack = tables.Column(
  129. linkify=True
  130. )
  131. device_role = ColoredLabelColumn(
  132. verbose_name='Role'
  133. )
  134. manufacturer = tables.Column(
  135. accessor=Accessor('device_type__manufacturer'),
  136. linkify=True
  137. )
  138. device_type = tables.Column(
  139. linkify=True,
  140. verbose_name='Type'
  141. )
  142. if settings.PREFER_IPV4:
  143. primary_ip = tables.Column(
  144. linkify=True,
  145. order_by=('primary_ip4', 'primary_ip6'),
  146. verbose_name='IP Address'
  147. )
  148. else:
  149. primary_ip = tables.Column(
  150. linkify=True,
  151. order_by=('primary_ip6', 'primary_ip4'),
  152. verbose_name='IP Address'
  153. )
  154. primary_ip4 = tables.Column(
  155. linkify=True,
  156. verbose_name='IPv4 Address'
  157. )
  158. primary_ip6 = tables.Column(
  159. linkify=True,
  160. verbose_name='IPv6 Address'
  161. )
  162. cluster = tables.Column(
  163. linkify=True
  164. )
  165. virtual_chassis = tables.Column(
  166. linkify=True
  167. )
  168. vc_position = tables.Column(
  169. verbose_name='VC Position'
  170. )
  171. vc_priority = tables.Column(
  172. verbose_name='VC Priority'
  173. )
  174. comments = MarkdownColumn()
  175. tags = TagColumn(
  176. url_name='dcim:device_list'
  177. )
  178. class Meta(BaseTable.Meta):
  179. model = Device
  180. fields = (
  181. 'pk', 'name', 'status', 'tenant', 'device_role', 'manufacturer', 'device_type', 'platform', 'serial',
  182. 'asset_tag', 'site', 'location', 'rack', 'position', 'face', 'primary_ip', 'primary_ip4', 'primary_ip6',
  183. 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'tags',
  184. )
  185. default_columns = (
  186. 'pk', 'name', 'status', 'tenant', 'site', 'location', 'rack', 'device_role', 'manufacturer', 'device_type',
  187. 'primary_ip',
  188. )
  189. class DeviceImportTable(BaseTable):
  190. name = tables.TemplateColumn(
  191. template_code=DEVICE_LINK
  192. )
  193. status = ChoiceFieldColumn()
  194. tenant = TenantColumn()
  195. site = tables.Column(
  196. linkify=True
  197. )
  198. rack = tables.Column(
  199. linkify=True
  200. )
  201. device_role = tables.Column(
  202. verbose_name='Role'
  203. )
  204. device_type = tables.Column(
  205. verbose_name='Type'
  206. )
  207. class Meta(BaseTable.Meta):
  208. model = Device
  209. fields = ('name', 'status', 'tenant', 'site', 'rack', 'position', 'device_role', 'device_type')
  210. empty_text = False
  211. #
  212. # Device components
  213. #
  214. class DeviceComponentTable(BaseTable):
  215. pk = ToggleColumn()
  216. device = tables.Column(
  217. linkify=True
  218. )
  219. name = tables.Column(
  220. linkify=True,
  221. order_by=('_name',)
  222. )
  223. class Meta(BaseTable.Meta):
  224. order_by = ('device', 'name')
  225. class CableTerminationTable(BaseTable):
  226. cable = tables.Column(
  227. linkify=True
  228. )
  229. cable_color = ColorColumn(
  230. accessor='cable.color',
  231. orderable=False,
  232. verbose_name='Cable Color'
  233. )
  234. cable_peer = TemplateColumn(
  235. accessor='_cable_peer',
  236. template_code=CABLETERMINATION,
  237. orderable=False,
  238. verbose_name='Cable Peer'
  239. )
  240. mark_connected = BooleanColumn()
  241. class PathEndpointTable(CableTerminationTable):
  242. connection = TemplateColumn(
  243. accessor='_path.last_node',
  244. template_code=CABLETERMINATION,
  245. verbose_name='Connection',
  246. orderable=False
  247. )
  248. class ConsolePortTable(DeviceComponentTable, PathEndpointTable):
  249. device = tables.Column(
  250. linkify={
  251. 'viewname': 'dcim:device_consoleports',
  252. 'args': [Accessor('device_id')],
  253. }
  254. )
  255. tags = TagColumn(
  256. url_name='dcim:consoleport_list'
  257. )
  258. class Meta(DeviceComponentTable.Meta):
  259. model = ConsolePort
  260. fields = (
  261. 'pk', 'name', 'device', 'label', 'type', 'speed', 'description', 'mark_connected', 'cable', 'cable_color',
  262. 'cable_peer', 'connection', 'tags',
  263. )
  264. default_columns = ('pk', 'name', 'device', 'label', 'type', 'speed', 'description')
  265. class DeviceConsolePortTable(ConsolePortTable):
  266. name = tables.TemplateColumn(
  267. template_code='<i class="mdi mdi-console"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  268. order_by=Accessor('_name'),
  269. attrs={'td': {'class': 'text-nowrap'}}
  270. )
  271. actions = ButtonsColumn(
  272. model=ConsolePort,
  273. buttons=('edit', 'delete'),
  274. prepend_template=CONSOLEPORT_BUTTONS
  275. )
  276. class Meta(DeviceComponentTable.Meta):
  277. model = ConsolePort
  278. fields = (
  279. 'pk', 'name', 'label', 'type', 'speed', 'description', 'mark_connected', 'cable', 'cable_color',
  280. 'cable_peer', 'connection', 'tags', 'actions'
  281. )
  282. default_columns = ('pk', 'name', 'label', 'type', 'speed', 'description', 'cable', 'connection', 'actions')
  283. row_attrs = {
  284. 'class': get_cabletermination_row_class
  285. }
  286. class ConsoleServerPortTable(DeviceComponentTable, PathEndpointTable):
  287. device = tables.Column(
  288. linkify={
  289. 'viewname': 'dcim:device_consoleserverports',
  290. 'args': [Accessor('device_id')],
  291. }
  292. )
  293. tags = TagColumn(
  294. url_name='dcim:consoleserverport_list'
  295. )
  296. class Meta(DeviceComponentTable.Meta):
  297. model = ConsoleServerPort
  298. fields = (
  299. 'pk', 'name', 'device', 'label', 'type', 'speed', 'description', 'mark_connected', 'cable', 'cable_color',
  300. 'cable_peer', 'connection', 'tags',
  301. )
  302. default_columns = ('pk', 'name', 'device', 'label', 'type', 'speed', 'description')
  303. class DeviceConsoleServerPortTable(ConsoleServerPortTable):
  304. name = tables.TemplateColumn(
  305. template_code='<i class="mdi mdi-console-network-outline"></i> '
  306. '<a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  307. order_by=Accessor('_name'),
  308. attrs={'td': {'class': 'text-nowrap'}}
  309. )
  310. actions = ButtonsColumn(
  311. model=ConsoleServerPort,
  312. buttons=('edit', 'delete'),
  313. prepend_template=CONSOLESERVERPORT_BUTTONS
  314. )
  315. class Meta(DeviceComponentTable.Meta):
  316. model = ConsoleServerPort
  317. fields = (
  318. 'pk', 'name', 'label', 'type', 'speed', 'description', 'mark_connected', 'cable', 'cable_color',
  319. 'cable_peer', 'connection', 'tags', 'actions',
  320. )
  321. default_columns = ('pk', 'name', 'label', 'type', 'speed', 'description', 'cable', 'connection', 'actions')
  322. row_attrs = {
  323. 'class': get_cabletermination_row_class
  324. }
  325. class PowerPortTable(DeviceComponentTable, PathEndpointTable):
  326. device = tables.Column(
  327. linkify={
  328. 'viewname': 'dcim:device_powerports',
  329. 'args': [Accessor('device_id')],
  330. }
  331. )
  332. tags = TagColumn(
  333. url_name='dcim:powerport_list'
  334. )
  335. class Meta(DeviceComponentTable.Meta):
  336. model = PowerPort
  337. fields = (
  338. 'pk', 'name', 'device', 'label', 'type', 'description', 'mark_connected', 'maximum_draw', 'allocated_draw',
  339. 'cable', 'cable_color', 'cable_peer', 'connection', 'tags',
  340. )
  341. default_columns = ('pk', 'name', 'device', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description')
  342. class DevicePowerPortTable(PowerPortTable):
  343. name = tables.TemplateColumn(
  344. template_code='<i class="mdi mdi-power-plug-outline"></i> <a href="{{ record.get_absolute_url }}">'
  345. '{{ value }}</a>',
  346. order_by=Accessor('_name'),
  347. attrs={'td': {'class': 'text-nowrap'}}
  348. )
  349. actions = ButtonsColumn(
  350. model=PowerPort,
  351. buttons=('edit', 'delete'),
  352. prepend_template=POWERPORT_BUTTONS
  353. )
  354. class Meta(DeviceComponentTable.Meta):
  355. model = PowerPort
  356. fields = (
  357. 'pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'mark_connected', 'cable',
  358. 'cable_color', 'cable_peer', 'connection', 'tags', 'actions',
  359. )
  360. default_columns = (
  361. 'pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'cable', 'connection',
  362. 'actions',
  363. )
  364. row_attrs = {
  365. 'class': get_cabletermination_row_class
  366. }
  367. class PowerOutletTable(DeviceComponentTable, PathEndpointTable):
  368. device = tables.Column(
  369. linkify={
  370. 'viewname': 'dcim:device_poweroutlets',
  371. 'args': [Accessor('device_id')],
  372. }
  373. )
  374. power_port = tables.Column(
  375. linkify=True
  376. )
  377. tags = TagColumn(
  378. url_name='dcim:poweroutlet_list'
  379. )
  380. class Meta(DeviceComponentTable.Meta):
  381. model = PowerOutlet
  382. fields = (
  383. 'pk', 'name', 'device', 'label', 'type', 'description', 'power_port', 'feed_leg', 'mark_connected', 'cable',
  384. 'cable_color', 'cable_peer', 'connection', 'tags',
  385. )
  386. default_columns = ('pk', 'name', 'device', 'label', 'type', 'power_port', 'feed_leg', 'description')
  387. class DevicePowerOutletTable(PowerOutletTable):
  388. name = tables.TemplateColumn(
  389. template_code='<i class="mdi mdi-power-socket"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  390. order_by=Accessor('_name'),
  391. attrs={'td': {'class': 'text-nowrap'}}
  392. )
  393. actions = ButtonsColumn(
  394. model=PowerOutlet,
  395. buttons=('edit', 'delete'),
  396. prepend_template=POWEROUTLET_BUTTONS
  397. )
  398. class Meta(DeviceComponentTable.Meta):
  399. model = PowerOutlet
  400. fields = (
  401. 'pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'mark_connected', 'cable',
  402. 'cable_color', 'cable_peer', 'connection', 'tags', 'actions',
  403. )
  404. default_columns = (
  405. 'pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'cable', 'connection', 'actions',
  406. )
  407. row_attrs = {
  408. 'class': get_cabletermination_row_class
  409. }
  410. class BaseInterfaceTable(BaseTable):
  411. enabled = BooleanColumn()
  412. ip_addresses = tables.TemplateColumn(
  413. template_code=INTERFACE_IPADDRESSES,
  414. orderable=False,
  415. verbose_name='IP Addresses'
  416. )
  417. untagged_vlan = tables.Column(linkify=True)
  418. tagged_vlans = TemplateColumn(
  419. template_code=INTERFACE_TAGGED_VLANS,
  420. orderable=False,
  421. verbose_name='Tagged VLANs'
  422. )
  423. class InterfaceTable(DeviceComponentTable, BaseInterfaceTable, PathEndpointTable):
  424. device = tables.Column(
  425. linkify={
  426. 'viewname': 'dcim:device_interfaces',
  427. 'args': [Accessor('device_id')],
  428. }
  429. )
  430. mgmt_only = BooleanColumn()
  431. tags = TagColumn(
  432. url_name='dcim:interface_list'
  433. )
  434. class Meta(DeviceComponentTable.Meta):
  435. model = Interface
  436. fields = (
  437. 'pk', 'name', 'device', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', 'mode', 'mac_address',
  438. 'description', 'mark_connected', 'cable', 'cable_color', 'cable_peer', 'connection', 'tags', 'ip_addresses',
  439. 'untagged_vlan', 'tagged_vlans',
  440. )
  441. default_columns = ('pk', 'name', 'device', 'label', 'enabled', 'type', 'description')
  442. class DeviceInterfaceTable(InterfaceTable):
  443. name = tables.TemplateColumn(
  444. template_code='<i class="mdi mdi-{% if iface.mgmt_only %}wrench{% elif iface.is_lag %}drag-horizontal-variant'
  445. '{% elif iface.is_virtual %}circle{% elif iface.is_wireless %}wifi{% else %}ethernet'
  446. '{% endif %}"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  447. order_by=Accessor('_name'),
  448. attrs={'td': {'class': 'text-nowrap'}}
  449. )
  450. parent = tables.Column(
  451. linkify=True,
  452. verbose_name='Parent'
  453. )
  454. lag = tables.Column(
  455. linkify=True,
  456. verbose_name='LAG'
  457. )
  458. actions = ButtonsColumn(
  459. model=Interface,
  460. buttons=('edit', 'delete'),
  461. prepend_template=INTERFACE_BUTTONS
  462. )
  463. class Meta(DeviceComponentTable.Meta):
  464. model = Interface
  465. fields = (
  466. 'pk', 'name', 'label', 'enabled', 'type', 'parent', 'lag', 'mgmt_only', 'mtu', 'mode', 'mac_address',
  467. 'description', 'mark_connected', 'cable', 'cable_color', 'cable_peer', 'connection', 'tags', 'ip_addresses',
  468. 'untagged_vlan', 'tagged_vlans', 'actions',
  469. )
  470. order_by = ('name',)
  471. default_columns = (
  472. 'pk', 'name', 'label', 'enabled', 'type', 'parent', 'lag', 'mtu', 'mode', 'description', 'ip_addresses',
  473. 'cable', 'connection', 'actions',
  474. )
  475. row_attrs = {
  476. 'class': get_cabletermination_row_class,
  477. 'data-name': lambda record: record.name,
  478. 'data-enabled': get_interface_state_attribute,
  479. }
  480. class FrontPortTable(DeviceComponentTable, CableTerminationTable):
  481. device = tables.Column(
  482. linkify={
  483. 'viewname': 'dcim:device_frontports',
  484. 'args': [Accessor('device_id')],
  485. }
  486. )
  487. color = ColorColumn()
  488. rear_port_position = tables.Column(
  489. verbose_name='Position'
  490. )
  491. rear_port = tables.Column(
  492. linkify=True
  493. )
  494. tags = TagColumn(
  495. url_name='dcim:frontport_list'
  496. )
  497. class Meta(DeviceComponentTable.Meta):
  498. model = FrontPort
  499. fields = (
  500. 'pk', 'name', 'device', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'description',
  501. 'mark_connected', 'cable', 'cable_color', 'cable_peer', 'tags',
  502. )
  503. default_columns = (
  504. 'pk', 'name', 'device', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'description',
  505. )
  506. class DeviceFrontPortTable(FrontPortTable):
  507. name = tables.TemplateColumn(
  508. template_code='<i class="mdi mdi-square-rounded{% if not record.cable %}-outline{% endif %}"></i> '
  509. '<a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  510. order_by=Accessor('_name'),
  511. attrs={'td': {'class': 'text-nowrap'}}
  512. )
  513. actions = ButtonsColumn(
  514. model=FrontPort,
  515. buttons=('edit', 'delete'),
  516. prepend_template=FRONTPORT_BUTTONS
  517. )
  518. class Meta(DeviceComponentTable.Meta):
  519. model = FrontPort
  520. fields = (
  521. 'pk', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'mark_connected', 'cable',
  522. 'cable_color', 'cable_peer', 'tags', 'actions',
  523. )
  524. default_columns = (
  525. 'pk', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable', 'cable_peer',
  526. 'actions',
  527. )
  528. row_attrs = {
  529. 'class': get_cabletermination_row_class
  530. }
  531. class RearPortTable(DeviceComponentTable, CableTerminationTable):
  532. device = tables.Column(
  533. linkify={
  534. 'viewname': 'dcim:device_rearports',
  535. 'args': [Accessor('device_id')],
  536. }
  537. )
  538. color = ColorColumn()
  539. tags = TagColumn(
  540. url_name='dcim:rearport_list'
  541. )
  542. class Meta(DeviceComponentTable.Meta):
  543. model = RearPort
  544. fields = (
  545. 'pk', 'name', 'device', 'label', 'type', 'color', 'positions', 'description', 'mark_connected', 'cable',
  546. 'cable_color', 'cable_peer', 'tags',
  547. )
  548. default_columns = ('pk', 'name', 'device', 'label', 'type', 'color', 'description')
  549. class DeviceRearPortTable(RearPortTable):
  550. name = tables.TemplateColumn(
  551. template_code='<i class="mdi mdi-square-rounded{% if not record.cable %}-outline{% endif %}"></i> '
  552. '<a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  553. order_by=Accessor('_name'),
  554. attrs={'td': {'class': 'text-nowrap'}}
  555. )
  556. actions = ButtonsColumn(
  557. model=RearPort,
  558. buttons=('edit', 'delete'),
  559. prepend_template=REARPORT_BUTTONS
  560. )
  561. class Meta(DeviceComponentTable.Meta):
  562. model = RearPort
  563. fields = (
  564. 'pk', 'name', 'label', 'type', 'positions', 'description', 'mark_connected', 'cable', 'cable_color',
  565. 'cable_peer', 'tags', 'actions',
  566. )
  567. default_columns = (
  568. 'pk', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer', 'actions',
  569. )
  570. row_attrs = {
  571. 'class': get_cabletermination_row_class
  572. }
  573. class DeviceBayTable(DeviceComponentTable):
  574. device = tables.Column(
  575. linkify={
  576. 'viewname': 'dcim:device_devicebays',
  577. 'args': [Accessor('device_id')],
  578. }
  579. )
  580. status = tables.TemplateColumn(
  581. template_code=DEVICEBAY_STATUS
  582. )
  583. installed_device = tables.Column(
  584. linkify=True
  585. )
  586. tags = TagColumn(
  587. url_name='dcim:devicebay_list'
  588. )
  589. class Meta(DeviceComponentTable.Meta):
  590. model = DeviceBay
  591. fields = ('pk', 'name', 'device', 'label', 'status', 'installed_device', 'description', 'tags')
  592. default_columns = ('pk', 'name', 'device', 'label', 'status', 'installed_device', 'description')
  593. class DeviceDeviceBayTable(DeviceBayTable):
  594. name = tables.TemplateColumn(
  595. template_code='<i class="mdi mdi-circle{% if record.installed_device %}slice-8{% else %}outline{% endif %}'
  596. '"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
  597. order_by=Accessor('_name'),
  598. attrs={'td': {'class': 'text-nowrap'}}
  599. )
  600. actions = ButtonsColumn(
  601. model=DeviceBay,
  602. buttons=('edit', 'delete'),
  603. prepend_template=DEVICEBAY_BUTTONS
  604. )
  605. class Meta(DeviceComponentTable.Meta):
  606. model = DeviceBay
  607. fields = (
  608. 'pk', 'name', 'label', 'status', 'installed_device', 'description', 'tags', 'actions',
  609. )
  610. default_columns = (
  611. 'pk', 'name', 'label', 'status', 'installed_device', 'description', 'actions',
  612. )
  613. class InventoryItemTable(DeviceComponentTable):
  614. device = tables.Column(
  615. linkify={
  616. 'viewname': 'dcim:device_inventory',
  617. 'args': [Accessor('device_id')],
  618. }
  619. )
  620. manufacturer = tables.Column(
  621. linkify=True
  622. )
  623. discovered = BooleanColumn()
  624. tags = TagColumn(
  625. url_name='dcim:inventoryitem_list'
  626. )
  627. cable = None # Override DeviceComponentTable
  628. class Meta(BaseTable.Meta):
  629. model = InventoryItem
  630. fields = (
  631. 'pk', 'name', 'device', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description',
  632. 'discovered', 'tags',
  633. )
  634. default_columns = ('pk', 'name', 'device', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag')
  635. class DeviceInventoryItemTable(InventoryItemTable):
  636. name = tables.TemplateColumn(
  637. template_code='<a href="{{ record.get_absolute_url }}" style="padding-left: {{ record.level }}0px">'
  638. '{{ value }}</a>',
  639. order_by=Accessor('_name'),
  640. attrs={'td': {'class': 'text-nowrap'}}
  641. )
  642. actions = ButtonsColumn(
  643. model=InventoryItem,
  644. buttons=('edit', 'delete')
  645. )
  646. class Meta(BaseTable.Meta):
  647. model = InventoryItem
  648. fields = (
  649. 'pk', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'discovered',
  650. 'tags', 'actions',
  651. )
  652. default_columns = (
  653. 'pk', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'discovered',
  654. 'actions',
  655. )
  656. #
  657. # Virtual chassis
  658. #
  659. class VirtualChassisTable(BaseTable):
  660. pk = ToggleColumn()
  661. name = tables.Column(
  662. linkify=True
  663. )
  664. master = tables.Column(
  665. linkify=True
  666. )
  667. member_count = LinkedCountColumn(
  668. viewname='dcim:device_list',
  669. url_params={'virtual_chassis_id': 'pk'},
  670. verbose_name='Members'
  671. )
  672. tags = TagColumn(
  673. url_name='dcim:virtualchassis_list'
  674. )
  675. class Meta(BaseTable.Meta):
  676. model = VirtualChassis
  677. fields = ('pk', 'name', 'domain', 'master', 'member_count', 'tags')
  678. default_columns = ('pk', 'name', 'domain', 'master', 'member_count')