device.html 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. {% extends '_base.html' %}
  2. {% load buttons %}
  3. {% load static %}
  4. {% load helpers %}
  5. {% load custom_links %}
  6. {% load plugins %}
  7. {% block title %}{{ device }}{% endblock %}
  8. {% block header %}
  9. <div class="row noprint">
  10. <div class="col-sm-8 col-md-9">
  11. <ol class="breadcrumb">
  12. <li><a href="{% url 'dcim:site' slug=device.site.slug %}">{{ device.site }}</a></li>
  13. {% if device.rack %}
  14. <li><a href="{% url 'dcim:rack_list' %}?site={{ device.site.slug }}">Racks</a></li>
  15. <li><a href="{% url 'dcim:rack' pk=device.rack.pk %}">{{ device.rack }}</a></li>
  16. {% endif %}
  17. {% if device.parent_bay %}
  18. <li><a href="{% url 'dcim:device' pk=device.parent_bay.device.pk %}">{{ device.parent_bay.device }}</a></li>
  19. <li>{{ device.parent_bay }}</li>
  20. {% endif %}
  21. <li>{{ device }}</li>
  22. </ol>
  23. </div>
  24. <div class="col-sm-4 col-md-3">
  25. <form action="{% url 'dcim:device_list' %}" method="get">
  26. <div class="input-group">
  27. <input type="text" name="q" class="form-control" placeholder="Search devices" />
  28. <span class="input-group-btn">
  29. <button type="submit" class="btn btn-primary">
  30. <span class="fa fa-search" aria-hidden="true"></span>
  31. </button>
  32. </span>
  33. </div>
  34. </form>
  35. </div>
  36. </div>
  37. <div class="pull-right noprint">
  38. {% plugin_buttons device %}
  39. {% if show_graphs %}
  40. <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#graphs_modal" data-obj="{{ device.name }}" data-url="{% url 'dcim-api:device-graphs' pk=device.pk %}" title="Show graphs">
  41. <i class="fa fa-signal" aria-hidden="true"></i>
  42. Graphs
  43. </button>
  44. {% endif %}
  45. {% if perms.dcim.change_device %}
  46. <div class="btn-group">
  47. <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
  48. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Components <span class="caret"></span>
  49. </button>
  50. <ul class="dropdown-menu">
  51. {% if perms.dcim.add_consoleport %}
  52. <li><a href="{% url 'dcim:consoleport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Console Ports</a></li>
  53. {% endif %}
  54. {% if perms.dcim.add_consoleserverport %}
  55. <li><a href="{% url 'dcim:consoleserverport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Console Server Ports</a></li>
  56. {% endif %}
  57. {% if perms.dcim.add_powerport %}
  58. <li><a href="{% url 'dcim:powerport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Power Ports</a></li>
  59. {% endif %}
  60. {% if perms.dcim.add_poweroutlet %}
  61. <li><a href="{% url 'dcim:poweroutlet_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Power Outlets</a></li>
  62. {% endif %}
  63. {% if perms.dcim.add_interface %}
  64. <li><a href="{% url 'dcim:interface_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Interfaces</a></li>
  65. {% endif %}
  66. {% if perms.dcim.add_frontport %}
  67. <li><a href="{% url 'dcim:frontport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Front Ports</a></li>
  68. {% endif %}
  69. {% if perms.dcim.add_rearport %}
  70. <li><a href="{% url 'dcim:rearport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Rear Ports</a></li>
  71. {% endif %}
  72. {% if perms.dcim.add_devicebay %}
  73. <li><a href="{% url 'dcim:devicebay_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}">Device Bays</a></li>
  74. {% endif %}
  75. </ul>
  76. </div>
  77. {% endif %}
  78. {% if perms.dcim.add_device %}
  79. {% clone_button device %}
  80. {% endif %}
  81. {% if perms.dcim.change_device %}
  82. {% edit_button device %}
  83. {% endif %}
  84. {% if perms.dcim.delete_device %}
  85. {% delete_button device %}
  86. {% endif %}
  87. </div>
  88. <h1>{{ device }}</h1>
  89. {% include 'inc/created_updated.html' with obj=device %}
  90. <div class="pull-right noprint">
  91. {% custom_links device %}
  92. </div>
  93. <ul class="nav nav-tabs">
  94. <li role="presentation"{% if not active_tab %} class="active"{% endif %}>
  95. <a href="{% url 'dcim:device' pk=device.pk %}">Device</a>
  96. </li>
  97. <li role="presentation"{% if active_tab == 'inventory' %} class="active"{% endif %}>
  98. <a href="{% url 'dcim:device_inventory' pk=device.pk %}">
  99. Inventory <span class="badge">{{ device.inventory_items.count }}</span>
  100. </a>
  101. </li>
  102. {% if perms.dcim.napalm_read %}
  103. {% if device.status != 'active' %}
  104. {% include 'dcim/inc/device_napalm_tabs.html' with disabled_message='Device must be in active status' %}
  105. {% elif not device.platform %}
  106. {% include 'dcim/inc/device_napalm_tabs.html' with disabled_message='No platform assigned to this device' %}
  107. {% elif not device.platform.napalm_driver %}
  108. {% include 'dcim/inc/device_napalm_tabs.html' with disabled_message='No NAPALM driver assigned for this platform' %}
  109. {% elif not device.primary_ip %}
  110. {% include 'dcim/inc/device_napalm_tabs.html' with disabled_message='No primary IP address assigned to this device' %}
  111. {% else %}
  112. {% include 'dcim/inc/device_napalm_tabs.html' %}
  113. {% endif %}
  114. {% endif %}
  115. {% if perms.extras.view_configcontext %}
  116. <li role="presentation"{% if active_tab == 'config-context' %} class="active"{% endif %}>
  117. <a href="{% url 'dcim:device_configcontext' pk=device.pk %}">Config Context</a>
  118. </li>
  119. {% endif %}
  120. {% if perms.extras.view_objectchange %}
  121. <li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}>
  122. <a href="{% url 'dcim:device_changelog' pk=device.pk %}">Change Log</a>
  123. </li>
  124. {% endif %}
  125. </ul>
  126. {% endblock %}
  127. {% block content %}
  128. <div class="row">
  129. <div class="col-md-6">
  130. <div class="panel panel-default">
  131. <div class="panel-heading">
  132. <strong>Device</strong>
  133. </div>
  134. <table class="table table-hover panel-body attr-table">
  135. <tr>
  136. <td>Site</td>
  137. <td>
  138. {% if device.site.region %}
  139. <a href="{{ device.site.region.get_absolute_url }}">{{ device.site.region }}</a>
  140. <i class="fa fa-angle-right"></i>
  141. {% endif %}
  142. <a href="{% url 'dcim:site' slug=device.site.slug %}">{{ device.site }}</a>
  143. </td>
  144. </tr>
  145. <tr>
  146. <td>Rack</td>
  147. <td>
  148. {% if device.rack %}
  149. {% if device.rack.group %}
  150. <a href="{{ device.rack.group.get_absolute_url }}">{{ device.rack.group }}</a>
  151. <i class="fa fa-angle-right"></i>
  152. {% endif %}
  153. <a href="{% url 'dcim:rack' pk=device.rack.pk %}">{{ device.rack }}</a>
  154. {% else %}
  155. <span class="text-muted">None</span>
  156. {% endif %}
  157. </td>
  158. </tr>
  159. <tr>
  160. <td>Position</td>
  161. <td>
  162. {% if device.parent_bay %}
  163. {% with device.parent_bay.device as parent %}
  164. <a href="{{ parent.get_absolute_url }}">{{ parent }}</a> <i class="fa fa-angle-right"></i> {{ device.parent_bay }}
  165. {% if parent.position %}
  166. (U{{ parent.position }} / {{ parent.get_face_display }})
  167. {% endif %}
  168. {% endwith %}
  169. {% elif device.rack and device.position %}
  170. <span>U{{ device.position }} / {{ device.get_face_display }}</span>
  171. {% elif device.rack and device.device_type.u_height %}
  172. <span class="label label-warning">Not racked</span>
  173. {% else %}
  174. <span class="text-muted">&mdash;</span>
  175. {% endif %}
  176. </td>
  177. </tr>
  178. <tr>
  179. <td>Tenant</td>
  180. <td>
  181. {% if device.tenant %}
  182. {% if device.tenant.group %}
  183. <a href="{{ device.tenant.group.get_absolute_url }}">{{ device.tenant.group }}</a>
  184. <i class="fa fa-angle-right"></i>
  185. {% endif %}
  186. <a href="{{ device.tenant.get_absolute_url }}">{{ device.tenant }}</a>
  187. {% else %}
  188. <span class="text-muted">None</span>
  189. {% endif %}
  190. </td>
  191. </tr>
  192. <tr>
  193. <td>Device Type</td>
  194. <td>
  195. <span><a href="{% url 'dcim:devicetype' pk=device.device_type.pk %}">{{ device.device_type.display_name }}</a> ({{ device.device_type.u_height }}U)</span>
  196. </td>
  197. </tr>
  198. <tr>
  199. <td>Serial Number</td>
  200. <td><span>{{ device.serial|placeholder }}</span></td>
  201. </tr>
  202. <tr>
  203. <td>Asset Tag</td>
  204. <td><span>{{ device.asset_tag|placeholder }}</span></td>
  205. </tr>
  206. </table>
  207. </div>
  208. {% if vc_members %}
  209. <div class="panel panel-default">
  210. <div class="panel-heading">
  211. <strong>Virtual Chassis</strong>
  212. </div>
  213. <table class="table table-hover panel-body attr-table">
  214. <tr>
  215. <th>Device</th>
  216. <th>Position</th>
  217. <th>Master</th>
  218. <th>Priority</th>
  219. </tr>
  220. {% for vc_member in vc_members %}
  221. <tr{% if vc_member == device %} class="info"{% endif %}>
  222. <td>
  223. <a href="{{ vc_member.get_absolute_url }}">{{ vc_member }}</a>
  224. </td>
  225. <td><span class="badge badge-default">{{ vc_member.vc_position }}</span></td>
  226. <td>{% if device.virtual_chassis.master == vc_member %}<i class="fa fa-check"></i>{% endif %}</td>
  227. <td>{{ vc_member.vc_priority|default:"" }}</td>
  228. </tr>
  229. {% endfor %}
  230. </table>
  231. <div class="panel-footer text-right noprint">
  232. {% if perms.dcim.change_virtualchassis %}
  233. <a href="{% url 'dcim:virtualchassis_add_member' pk=device.virtual_chassis.pk %}?site={{ device.site.pk }}&rack={{ device.rack.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
  234. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Member
  235. </a>
  236. <a href="{% url 'dcim:virtualchassis_edit' pk=device.virtual_chassis.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  237. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit Virtual Chassis
  238. </a>
  239. {% endif %}
  240. {% if perms.dcim.delete_virtualchassis %}
  241. <a href="{% url 'dcim:virtualchassis_delete' pk=device.virtual_chassis.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  242. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete Virtual Chassis
  243. </a>
  244. {% endif %}
  245. </div>
  246. </div>
  247. {% endif %}
  248. <div class="panel panel-default">
  249. <div class="panel-heading">
  250. <strong>Management</strong>
  251. </div>
  252. <table class="table table-hover panel-body attr-table">
  253. <tr>
  254. <td>Role</td>
  255. <td>
  256. <a href="{% url 'dcim:device_list' %}?role={{ device.device_role.slug }}">{{ device.device_role }}</a>
  257. </td>
  258. </tr>
  259. <tr>
  260. <td>Platform</td>
  261. <td>
  262. {% if device.platform %}
  263. <a href="{{ device.platform.get_absolute_url }}">{{ device.platform }}</a>
  264. {% else %}
  265. <span class="text-muted">None</span>
  266. {% endif %}
  267. </td>
  268. </tr>
  269. <tr>
  270. <td>Status</td>
  271. <td>
  272. <span class="label label-{{ device.get_status_class }}">{{ device.get_status_display }}</span>
  273. </td>
  274. </tr>
  275. <tr>
  276. <td>Primary IPv4</td>
  277. <td>
  278. {% if device.primary_ip4 %}
  279. <a href="{% url 'ipam:ipaddress' pk=device.primary_ip4.pk %}">{{ device.primary_ip4.address.ip }}</a>
  280. {% if device.primary_ip4.nat_inside %}
  281. <span>(NAT for {{ device.primary_ip4.nat_inside.address.ip }})</span>
  282. {% elif device.primary_ip4.nat_outside %}
  283. <span>(NAT: {{ device.primary_ip4.nat_outside.address.ip }})</span>
  284. {% endif %}
  285. {% else %}
  286. <span class="text-muted">&mdash;</span>
  287. {% endif %}
  288. </td>
  289. </tr>
  290. <tr>
  291. <td>Primary IPv6</td>
  292. <td>
  293. {% if device.primary_ip6 %}
  294. <a href="{% url 'ipam:ipaddress' pk=device.primary_ip6.pk %}">{{ device.primary_ip6.address.ip }}</a>
  295. {% if device.primary_ip6.nat_inside %}
  296. <span>(NAT for {{ device.primary_ip6.nat_inside.address.ip }})</span>
  297. {% elif device.primary_ip6.nat_outside %}
  298. <span>(NAT: {{ device.primary_ip6.nat_outside.address.ip }})</span>
  299. {% endif %}
  300. {% else %}
  301. <span class="text-muted">&mdash;</span>
  302. {% endif %}
  303. </td>
  304. </tr>
  305. {% if device.cluster %}
  306. <tr>
  307. <td>Cluster</td>
  308. <td>
  309. {% if device.cluster.group %}
  310. <a href="{{ device.cluster.group.get_absolute_url }}">{{ device.cluster.group }}</a>
  311. <i class="fa fa-angle-right"></i>
  312. {% endif %}
  313. <a href="{{ device.cluster.get_absolute_url }}">{{ device.cluster }}</a>
  314. </td>
  315. </tr>
  316. {% endif %}
  317. </table>
  318. </div>
  319. {% include 'inc/custom_fields_panel.html' with obj=device %}
  320. {% include 'extras/inc/tags_panel.html' with tags=device.tags.all url='dcim:device_list' %}
  321. <div class="panel panel-default">
  322. <div class="panel-heading">
  323. <strong>Comments</strong>
  324. </div>
  325. <div class="panel-body rendered-markdown">
  326. {% if device.comments %}
  327. {{ device.comments|render_markdown }}
  328. {% else %}
  329. <span class="text-muted">None</span>
  330. {% endif %}
  331. </div>
  332. </div>
  333. {% plugin_left_page device %}
  334. </div>
  335. <div class="col-md-6">
  336. {% if console_ports or power_ports %}
  337. <div class="panel panel-default">
  338. <div class="panel-heading">
  339. <strong>Console / Power</strong>
  340. </div>
  341. <table class="table table-hover panel-body component-list">
  342. {% for cp in console_ports %}
  343. {% include 'dcim/inc/consoleport.html' %}
  344. {% endfor %}
  345. {% for pp in power_ports %}
  346. {% include 'dcim/inc/powerport.html' %}
  347. {% endfor %}
  348. </table>
  349. {% if perms.dcim.add_interface or perms.dcim.add_consoleport or perms.dcim.add_powerport %}
  350. <div class="panel-footer text-right noprint">
  351. {% if perms.dcim.add_consoleport %}
  352. <a href="{% url 'dcim:consoleport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-xs btn-primary">
  353. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add console port
  354. </a>
  355. {% endif %}
  356. {% if perms.dcim.add_powerport %}
  357. <a href="{% url 'dcim:powerport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-xs btn-primary">
  358. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add power port
  359. </a>
  360. {% endif %}
  361. </div>
  362. {% endif %}
  363. </div>
  364. {% endif %}
  365. {% if power_ports and poweroutlets %}
  366. <div class="panel panel-default">
  367. <div class="panel-heading">
  368. <strong>Power Utilization</strong>
  369. </div>
  370. <table class="table table-hover panel-body">
  371. <tr>
  372. <th>Input</th>
  373. <th>Outlets</th>
  374. <th>Allocated</th>
  375. <th>Available</th>
  376. <th>Utilization</th>
  377. </tr>
  378. {% for pp in power_ports %}
  379. {% with utilization=pp.get_power_draw powerfeed=pp.connected_endpoint %}
  380. <tr>
  381. <td>{{ pp }}</td>
  382. <td>{{ utilization.outlet_count }}</td>
  383. <td>{{ utilization.allocated }}VA</td>
  384. {% if powerfeed.available_power %}
  385. <td>{{ powerfeed.available_power }}VA</td>
  386. <td>{% utilization_graph utilization.allocated|percentage:powerfeed.available_power %}</td>
  387. {% else %}
  388. <td class="text-muted">&mdash;</td>
  389. <td class="text-muted">&mdash;</td>
  390. {% endif %}
  391. </tr>
  392. {% for leg in utilization.legs %}
  393. <tr>
  394. <td style="padding-left: 20px">Leg {{ leg.name }}</td>
  395. <td>{{ leg.outlet_count }}</td>
  396. <td>{{ leg.allocated }}</td>
  397. <td>{{ powerfeed.available_power|divide:3 }}VA</td>
  398. {% with phase_available=powerfeed.available_power|divide:3 %}
  399. <td>{% utilization_graph leg.allocated|percentage:phase_available %}</td>
  400. {% endwith %}
  401. </tr>
  402. {% endfor %}
  403. {% endwith %}
  404. {% endfor %}
  405. </table>
  406. </div>
  407. {% endif %}
  408. {% if request.user.is_authenticated %}
  409. <div class="panel panel-default">
  410. <div class="panel-heading">
  411. <strong>Secrets</strong>
  412. </div>
  413. {% if secrets %}
  414. <table class="table table-hover panel-body">
  415. {% for secret in secrets %}
  416. {% include 'secrets/inc/secret_tr.html' %}
  417. {% endfor %}
  418. </table>
  419. {% else %}
  420. <div class="panel-body text-muted">
  421. None found
  422. </div>
  423. {% endif %}
  424. {% if perms.secrets.add_secret %}
  425. <form id="secret_form">
  426. {% csrf_token %}
  427. </form>
  428. <div class="panel-footer text-right noprint">
  429. <a href="{% url 'secrets:secret_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-xs btn-primary">
  430. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
  431. Add secret
  432. </a>
  433. </div>
  434. {% endif %}
  435. </div>
  436. {% endif %}
  437. <div class="panel panel-default">
  438. <div class="panel-heading">
  439. <strong>Services</strong>
  440. </div>
  441. {% if services %}
  442. <table class="table table-hover panel-body">
  443. {% for service in services %}
  444. {% include 'ipam/inc/service.html' %}
  445. {% endfor %}
  446. </table>
  447. {% else %}
  448. <div class="panel-body text-muted">
  449. None
  450. </div>
  451. {% endif %}
  452. {% if perms.ipam.add_service %}
  453. <div class="panel-footer text-right noprint">
  454. <a href="{% url 'dcim:device_service_assign' device=device.pk %}" class="btn btn-xs btn-primary">
  455. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Assign service
  456. </a>
  457. </div>
  458. {% endif %}
  459. </div>
  460. <div class="panel panel-default">
  461. <div class="panel-heading">
  462. <strong>Images</strong>
  463. </div>
  464. {% include 'inc/image_attachments.html' with images=device.images.all %}
  465. {% if perms.extras.add_imageattachment %}
  466. <div class="panel-footer text-right noprint">
  467. <a href="{% url 'dcim:device_add_image' object_id=device.pk %}" class="btn btn-primary btn-xs">
  468. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
  469. Attach an image
  470. </a>
  471. </div>
  472. {% endif %}
  473. </div>
  474. <div class="panel panel-default noprint">
  475. <div class="panel-heading">
  476. <strong>Related Devices</strong>
  477. </div>
  478. {% if related_devices %}
  479. <table class="table table-hover panel-body">
  480. {% for rd in related_devices %}
  481. <tr>
  482. <td>
  483. <a href="{% url 'dcim:device' pk=rd.pk %}">{{ rd }}</a>
  484. </td>
  485. <td>
  486. {% if rd.rack %}
  487. <a href="{% url 'dcim:rack' pk=rd.rack.pk %}">Rack {{ rd.rack }}</a>
  488. {% else %}
  489. <span class="text-muted">&mdash;</span>
  490. {% endif %}
  491. </td>
  492. <td>{{ rd.device_type.display_name }}</td>
  493. </tr>
  494. {% endfor %}
  495. </table>
  496. {% else %}
  497. <div class="panel-body text-muted">None found</div>
  498. {% endif %}
  499. </div>
  500. {% plugin_right_page device %}
  501. </div>
  502. </div>
  503. <div class="row">
  504. <div class="col-md-12">
  505. {% plugin_full_width_page device %}
  506. </div>
  507. </div>
  508. <div class="row">
  509. <div class="col-md-12">
  510. {% if device_bays or device.device_type.is_parent_device %}
  511. {% if perms.dcim.delete_devicebay %}
  512. <form method="post">
  513. {% csrf_token %}
  514. {% endif %}
  515. <div class="panel panel-default">
  516. <div class="panel-heading">
  517. <strong>Device Bays</strong>
  518. </div>
  519. <table class="table table-hover table-headings panel-body component-list">
  520. <thead>
  521. <tr>
  522. {% if perms.dcim.change_devicebay or perms.dcim.delete_devicebay %}
  523. <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
  524. {% endif %}
  525. <th>Name</th>
  526. <th>Status</th>
  527. <th>Description</th>
  528. <th colspan="2">Installed Device</th>
  529. <th></th>
  530. </tr>
  531. </thead>
  532. <tbody>
  533. {% for devicebay in device_bays %}
  534. {% include 'dcim/inc/devicebay.html' %}
  535. {% empty %}
  536. <tr>
  537. <td colspan="5" class="text-center text-muted">&mdash; No device bays defined &mdash;</td>
  538. </tr>
  539. {% endfor %}
  540. </tbody>
  541. </table>
  542. <div class="panel-footer noprint">
  543. {% if device_bays and perms.dcim.change_devicebay %}
  544. <button type="submit" name="_rename" formaction="{% url 'dcim:devicebay_bulk_rename' %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  545. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Rename
  546. </button>
  547. {% endif %}
  548. {% if device_bays and perms.dcim.delete_devicebay %}
  549. <button type="submit" formaction="{% url 'dcim:devicebay_bulk_delete' %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  550. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete selected
  551. </button>
  552. {% endif %}
  553. {% if perms.dcim.add_devicebay %}
  554. <div class="pull-right">
  555. <a href="{% url 'dcim:devicebay_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
  556. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add device bays
  557. </a>
  558. </div>
  559. <div class="clearfix"></div>
  560. {% endif %}
  561. </div>
  562. </div>
  563. {% if perms.dcim.delete_devicebay %}
  564. </form>
  565. {% endif %}
  566. {% endif %}
  567. {% if interfaces %}
  568. {% if perms.dcim.change_interface or perms.dcim.delete_interface %}
  569. <form method="post">
  570. {% csrf_token %}
  571. <input type="hidden" name="device" value="{{ device.pk }}" />
  572. {% endif %}
  573. <div class="panel panel-default">
  574. <div class="panel-heading">
  575. <strong>Interfaces</strong>
  576. <div class="pull-right noprint">
  577. <button class="btn btn-default btn-xs toggle-ips" selected="selected">
  578. <span class="glyphicon glyphicon-check" aria-hidden="true"></span> Show IPs
  579. </button>
  580. </div>
  581. <div class="col-md-2 pull-right noprint">
  582. <input class="form-control interface-filter" type="text" placeholder="Filter" title="RegEx-enabled" style="height: 23px" />
  583. </div>
  584. </div>
  585. <table id="interfaces_table" class="table table-hover table-headings panel-body component-list">
  586. <thead>
  587. <tr>
  588. {% if perms.dcim.change_interface or perms.dcim.delete_interface %}
  589. <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
  590. {% endif %}
  591. <th>Name</th>
  592. <th>LAG</th>
  593. <th>Description</th>
  594. <th>MTU</th>
  595. <th>Mode</th>
  596. <th>Cable</th>
  597. <th colspan="2">Connection</th>
  598. <th></th>
  599. </tr>
  600. </thead>
  601. <tbody>
  602. {% for iface in interfaces %}
  603. {% include 'dcim/inc/interface.html' %}
  604. {% endfor %}
  605. </tbody>
  606. </table>
  607. <div class="panel-footer noprint">
  608. {% if interfaces and perms.dcim.change_interface %}
  609. <button type="submit" name="_rename" formaction="{% url 'dcim:interface_bulk_rename' %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  610. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Rename
  611. </button>
  612. <button type="submit" name="_edit" formaction="{% url 'dcim:interface_bulk_edit' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  613. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit
  614. </button>
  615. {% endif %}
  616. {% if interfaces and perms.dcim.change_interface %}
  617. <button type="submit" name="_disconnect" formaction="{% url 'dcim:interface_bulk_disconnect' %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  618. <span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span> Disconnect
  619. </button>
  620. {% endif %}
  621. {% if interfaces and perms.dcim.delete_interface %}
  622. <button type="submit" name="_delete" formaction="{% url 'dcim:interface_bulk_delete' %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  623. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
  624. </button>
  625. {% endif %}
  626. {% if perms.dcim.add_interface %}
  627. <div class="pull-right">
  628. <a href="{% url 'dcim:interface_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
  629. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add interfaces
  630. </a>
  631. </div>
  632. <div class="clearfix"></div>
  633. {% endif %}
  634. </div>
  635. </div>
  636. {% if perms.dcim.delete_interface %}
  637. </form>
  638. {% endif %}
  639. {% endif %}
  640. {% if consoleserverports %}
  641. {% if perms.dcim.delete_consoleserverport %}
  642. <form method="post">
  643. {% csrf_token %}
  644. <input type="hidden" name="device" value="{{ device.pk }}" />
  645. {% endif %}
  646. <div class="panel panel-default">
  647. <div class="panel-heading">
  648. <strong>Console Server Ports</strong>
  649. </div>
  650. <table class="table table-hover table-headings panel-body component-list">
  651. <thead>
  652. <tr>
  653. {% if perms.dcim.change_consoleserverport or perms.dcim.delete_consoleserverport %}
  654. <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
  655. {% endif %}
  656. <th>Name</th>
  657. <th>Type</th>
  658. <th>Description</th>
  659. <th>Cable</th>
  660. <th colspan="2">Connection</th>
  661. <th></th>
  662. </tr>
  663. </thead>
  664. <tbody>
  665. {% for csp in consoleserverports %}
  666. {% include 'dcim/inc/consoleserverport.html' %}
  667. {% endfor %}
  668. </tbody>
  669. </table>
  670. <div class="panel-footer noprint">
  671. {% if consoleserverports and perms.dcim.change_consoleport %}
  672. <button type="submit" name="_rename" formaction="{% url 'dcim:consoleserverport_bulk_rename' %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  673. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Rename
  674. </button>
  675. <button type="submit" name="_edit" formaction="{% url 'dcim:consoleserverport_bulk_edit' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  676. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit
  677. </button>
  678. <button type="submit" name="_disconnect" formaction="{% url 'dcim:consoleserverport_bulk_disconnect' %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  679. <span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span> Disconnect
  680. </button>
  681. {% endif %}
  682. {% if consoleserverports and perms.dcim.delete_consoleserverport %}
  683. <button type="submit" formaction="{% url 'dcim:consoleserverport_bulk_delete' %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  684. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
  685. </button>
  686. {% endif %}
  687. {% if perms.dcim.add_consoleserverport %}
  688. <div class="pull-right">
  689. <a href="{% url 'dcim:consoleserverport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
  690. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add console server ports
  691. </a>
  692. </div>
  693. <div class="clearfix"></div>
  694. {% endif %}
  695. </div>
  696. </div>
  697. {% if perms.dcim.delete_consoleserverport %}
  698. </form>
  699. {% endif %}
  700. {% endif %}
  701. {% if poweroutlets %}
  702. {% if perms.dcim.delete_poweroutlet %}
  703. <form method="post">
  704. {% csrf_token %}
  705. <input type="hidden" name="device" value="{{ device.pk }}" />
  706. {% endif %}
  707. <div class="panel panel-default">
  708. <div class="panel-heading">
  709. <strong>Power Outlets</strong>
  710. </div>
  711. <table class="table table-hover table-headings panel-body component-list">
  712. <thead>
  713. <tr>
  714. {% if perms.dcim.change_poweroutlet or perms.dcim.delete_poweroutlet %}
  715. <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
  716. {% endif %}
  717. <th>Name</th>
  718. <th>Type</th>
  719. <th>Input/Leg</th>
  720. <th>Description</th>
  721. <th>Cable</th>
  722. <th colspan="3">Connection</th>
  723. <th></th>
  724. </tr>
  725. </thead>
  726. <tbody>
  727. {% for po in poweroutlets %}
  728. {% include 'dcim/inc/poweroutlet.html' %}
  729. {% endfor %}
  730. </tbody>
  731. </table>
  732. <div class="panel-footer noprint">
  733. {% if poweroutlets and perms.dcim.change_powerport %}
  734. <button type="submit" name="_rename" formaction="{% url 'dcim:poweroutlet_bulk_rename' %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  735. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Rename
  736. </button>
  737. <button type="submit" name="_edit" formaction="{% url 'dcim:poweroutlet_bulk_edit' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  738. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit
  739. </button>
  740. <button type="submit" name="_disconnect" formaction="{% url 'dcim:poweroutlet_bulk_disconnect' %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  741. <span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span> Disconnect
  742. </button>
  743. {% endif %}
  744. {% if poweroutlets and perms.dcim.delete_poweroutlet %}
  745. <button type="submit" formaction="{% url 'dcim:poweroutlet_bulk_delete' %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  746. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
  747. </button>
  748. {% endif %}
  749. {% if perms.dcim.add_poweroutlet %}
  750. <div class="pull-right">
  751. <a href="{% url 'dcim:poweroutlet_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
  752. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add power outlets
  753. </a>
  754. </div>
  755. <div class="clearfix"></div>
  756. {% endif %}
  757. </div>
  758. </div>
  759. {% if perms.dcim.delete_poweroutlet %}
  760. </form>
  761. {% endif %}
  762. {% endif %}
  763. {% if front_ports %}
  764. <form method="post">
  765. {% csrf_token %}
  766. <input type="hidden" name="device" value="{{ device.pk }}" />
  767. <div class="panel panel-default">
  768. <div class="panel-heading">
  769. <strong>Front Ports</strong>
  770. </div>
  771. <table class="table table-hover table-headings panel-body component-list">
  772. <thead>
  773. <tr>
  774. {% if perms.dcim.change_frontport or perms.dcim.delete_frontport %}
  775. <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
  776. {% endif %}
  777. <th>Name</th>
  778. <th>Type</th>
  779. <th>Rear Port</th>
  780. <th>Position</th>
  781. <th>Description</th>
  782. <th>Cable</th>
  783. <th colspan="2">Connection</th>
  784. <th></th>
  785. </tr>
  786. </thead>
  787. <tbody>
  788. {% for frontport in front_ports %}
  789. {% include 'dcim/inc/frontport.html' %}
  790. {% endfor %}
  791. </tbody>
  792. </table>
  793. <div class="panel-footer noprint">
  794. {% if front_ports and perms.dcim.change_frontport %}
  795. <button type="submit" name="_rename" formaction="{% url 'dcim:frontport_bulk_rename' %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  796. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Rename
  797. </button>
  798. <button type="submit" name="_edit" formaction="{% url 'dcim:frontport_bulk_edit' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  799. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit
  800. </button>
  801. <button type="submit" name="_disconnect" formaction="{% url 'dcim:frontport_bulk_disconnect' %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  802. <span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span> Disconnect
  803. </button>
  804. {% endif %}
  805. {% if front_ports and perms.dcim.delete_frontport %}
  806. <button type="submit" formaction="{% url 'dcim:frontport_bulk_delete' %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  807. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
  808. </button>
  809. {% endif %}
  810. {% if perms.dcim.add_frontport %}
  811. <div class="pull-right">
  812. <a href="{% url 'dcim:frontport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
  813. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add front ports
  814. </a>
  815. </div>
  816. <div class="clearfix"></div>
  817. {% endif %}
  818. </div>
  819. </div>
  820. </form>
  821. {% endif %}
  822. {% if rear_ports %}
  823. <form method="post">
  824. {% csrf_token %}
  825. <input type="hidden" name="device" value="{{ device.pk }}" />
  826. <div class="panel panel-default">
  827. <div class="panel-heading">
  828. <strong>Rear Ports</strong>
  829. </div>
  830. <table class="table table-hover table-headings panel-body component-list">
  831. <thead>
  832. <tr>
  833. {% if perms.dcim.change_rearport or perms.dcim.delete_rearport %}
  834. <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
  835. {% endif %}
  836. <th>Name</th>
  837. <th>Type</th>
  838. <th>Positions</th>
  839. <th>Description</th>
  840. <th>Cable</th>
  841. <th colspan="2">Connection</th>
  842. <th></th>
  843. </tr>
  844. </thead>
  845. <tbody>
  846. {% for rearport in rear_ports %}
  847. {% include 'dcim/inc/rearport.html' %}
  848. {% endfor %}
  849. </tbody>
  850. </table>
  851. <div class="panel-footer noprint">
  852. {% if rear_ports and perms.dcim.change_rearport %}
  853. <button type="submit" name="_rename" formaction="{% url 'dcim:rearport_bulk_rename' %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  854. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Rename
  855. </button>
  856. <button type="submit" name="_edit" formaction="{% url 'dcim:rearport_bulk_edit' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
  857. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit
  858. </button>
  859. <button type="submit" name="_disconnect" formaction="{% url 'dcim:rearport_bulk_disconnect' %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  860. <span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span> Disconnect
  861. </button>
  862. {% endif %}
  863. {% if rear_ports and perms.dcim.delete_rearport %}
  864. <button type="submit" formaction="{% url 'dcim:rearport_bulk_delete' %}?return_url={{ device.get_absolute_url }}" class="btn btn-danger btn-xs">
  865. <span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
  866. </button>
  867. {% endif %}
  868. {% if perms.dcim.add_rearport %}
  869. <div class="pull-right">
  870. <a href="{% url 'dcim:rearport_add' %}?device={{ device.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
  871. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add rear ports
  872. </a>
  873. </div>
  874. <div class="clearfix"></div>
  875. {% endif %}
  876. </div>
  877. </div>
  878. </form>
  879. {% endif %}
  880. </div>
  881. </div>
  882. {% include 'inc/modal.html' with name='graphs' title='Graphs' %}
  883. {% include 'secrets/inc/private_key_modal.html' %}
  884. {% endblock %}
  885. {% block javascript %}
  886. <script type="text/javascript">
  887. function toggleConnection(elem) {
  888. var url = netbox_api_path + "dcim/cables/" + elem.attr('data') + "/";
  889. if (elem.hasClass('connected')) {
  890. $.ajax({
  891. url: url,
  892. method: 'PATCH',
  893. dataType: 'json',
  894. beforeSend: function(xhr, settings) {
  895. xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
  896. },
  897. data: {
  898. 'status': 'False'
  899. },
  900. context: this,
  901. success: function() {
  902. elem.parents('tr').removeClass('success').addClass('info');
  903. elem.removeClass('connected btn-warning').addClass('btn-success');
  904. elem.attr('title', 'Mark installed');
  905. elem.children('i').removeClass('glyphicon glyphicon-ban-circle').addClass('fa fa-plug')
  906. }
  907. });
  908. } else {
  909. $.ajax({
  910. url: url,
  911. method: 'PATCH',
  912. dataType: 'json',
  913. beforeSend: function(xhr, settings) {
  914. xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
  915. },
  916. data: {
  917. 'status': 'True'
  918. },
  919. context: this,
  920. success: function() {
  921. elem.parents('tr').removeClass('info').addClass('success');
  922. elem.removeClass('btn-success').addClass('connected btn-warning');
  923. elem.attr('title', 'Mark planned');
  924. elem.children('i').removeClass('fa fa-plug').addClass('glyphicon glyphicon-ban-circle')
  925. }
  926. });
  927. }
  928. return false;
  929. }
  930. $(".cable-toggle").click(function() {
  931. return toggleConnection($(this));
  932. });
  933. </script>
  934. <script src="{% static 'js/interface_toggles.js' %}?v{{ settings.VERSION }}"></script>
  935. <script src="{% static 'js/graphs.js' %}?v{{ settings.VERSION }}"></script>
  936. <script src="{% static 'js/secrets.js' %}?v{{ settings.VERSION }}"></script>
  937. {% endblock %}