devices.py 21 KB

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