devices.py 21 KB

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