nautobot 2.2.8__py3-none-any.whl → 2.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nautobot might be problematic. Click here for more details.

Files changed (704) hide show
  1. nautobot/apps/forms.py +4 -0
  2. nautobot/apps/models.py +10 -1
  3. nautobot/circuits/__init__.py +0 -1
  4. nautobot/circuits/apps.py +1 -0
  5. nautobot/circuits/factory.py +15 -3
  6. nautobot/circuits/filters.py +13 -0
  7. nautobot/circuits/forms.py +13 -0
  8. nautobot/circuits/migrations/0021_alter_circuit_status_alter_circuittermination__path.py +32 -0
  9. nautobot/circuits/migrations/0022_circuittermination_cloud_network.py +25 -0
  10. nautobot/circuits/models.py +16 -3
  11. nautobot/circuits/tables.py +16 -2
  12. nautobot/circuits/templates/circuits/circuittermination_create.html +10 -2
  13. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +6 -0
  14. nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -1
  15. nautobot/circuits/tests/test_api.py +7 -5
  16. nautobot/circuits/tests/test_filters.py +12 -5
  17. nautobot/circuits/tests/test_models.py +33 -2
  18. nautobot/circuits/views.py +2 -3
  19. nautobot/cloud/__init__.py +0 -0
  20. nautobot/cloud/api/__init__.py +0 -0
  21. nautobot/cloud/api/serializers.py +54 -0
  22. nautobot/cloud/api/urls.py +16 -0
  23. nautobot/cloud/api/views.py +48 -0
  24. nautobot/cloud/apps.py +13 -0
  25. nautobot/cloud/factory.py +113 -0
  26. nautobot/cloud/filters.py +187 -0
  27. nautobot/cloud/forms.py +339 -0
  28. nautobot/cloud/homepage.py +43 -0
  29. nautobot/cloud/migrations/0001_initial.py +304 -0
  30. nautobot/cloud/migrations/__init__.py +0 -0
  31. nautobot/cloud/models.py +246 -0
  32. nautobot/cloud/navigation.py +85 -0
  33. nautobot/cloud/tables.py +157 -0
  34. nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +43 -0
  35. nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +122 -0
  36. nautobot/cloud/templates/cloud/cloudnetwork_update.html +33 -0
  37. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +111 -0
  38. nautobot/cloud/templates/cloud/cloudservice_retrieve.html +69 -0
  39. nautobot/cloud/templates/cloud/cloudservice_update.html +25 -0
  40. nautobot/cloud/tests/__init__.py +0 -0
  41. nautobot/cloud/tests/test_api.py +248 -0
  42. nautobot/cloud/tests/test_filters.py +125 -0
  43. nautobot/cloud/tests/test_models.py +43 -0
  44. nautobot/cloud/tests/test_views.py +153 -0
  45. nautobot/cloud/urls.py +14 -0
  46. nautobot/cloud/views.py +181 -0
  47. nautobot/core/__init__.py +0 -3
  48. nautobot/core/api/metadata.py +1 -0
  49. nautobot/core/api/parsers.py +7 -1
  50. nautobot/core/api/urls.py +1 -0
  51. nautobot/core/api/utils.py +1 -0
  52. nautobot/core/api/views.py +4 -0
  53. nautobot/core/apps/__init__.py +6 -3
  54. nautobot/core/constants.py +8 -0
  55. nautobot/core/factory.py +32 -1
  56. nautobot/core/filters.py +110 -14
  57. nautobot/core/forms/fields.py +10 -4
  58. nautobot/core/forms/forms.py +11 -3
  59. nautobot/core/forms/widgets.py +18 -1
  60. nautobot/core/graphql/generators.py +2 -2
  61. nautobot/core/graphql/schema.py +28 -7
  62. nautobot/core/jobs/__init__.py +20 -3
  63. nautobot/core/jobs/cleanup.py +100 -0
  64. nautobot/core/jobs/groups.py +38 -0
  65. nautobot/core/management/commands/generate_test_data.py +116 -3
  66. nautobot/core/models/__init__.py +34 -9
  67. nautobot/core/models/generics.py +19 -3
  68. nautobot/core/models/name_color_content_types.py +7 -28
  69. nautobot/core/models/querysets.py +4 -3
  70. nautobot/core/models/tree_queries.py +1 -1
  71. nautobot/core/models/utils.py +21 -5
  72. nautobot/core/settings.py +15 -19
  73. nautobot/core/settings.yaml +48 -13
  74. nautobot/core/settings_funcs.py +103 -0
  75. nautobot/core/tables.py +130 -56
  76. nautobot/core/templates/admin/search_form.html +1 -1
  77. nautobot/core/templates/buttons/add.html +11 -3
  78. nautobot/core/templates/buttons/consolidated_bulk_action_buttons.html +13 -0
  79. nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +13 -0
  80. nautobot/core/templates/buttons/export.html +101 -53
  81. nautobot/core/templates/buttons/job_import.html +11 -3
  82. nautobot/core/templates/generic/object_bulk_destroy.html +3 -1
  83. nautobot/core/templates/generic/object_bulk_update.html +3 -1
  84. nautobot/core/templates/generic/object_changelog.html +0 -9
  85. nautobot/core/templates/generic/object_list.html +156 -17
  86. nautobot/core/templates/generic/object_retrieve.html +80 -16
  87. nautobot/core/templates/inc/extras_features_edit_form_fields.html +8 -0
  88. nautobot/core/templates/inc/javascript.html +2 -0
  89. nautobot/core/templates/inc/media.html +2 -2
  90. nautobot/core/templates/inc/nav_menu.html +1 -0
  91. nautobot/core/templates/inc/paginator.html +7 -7
  92. nautobot/core/templates/inc/search_panel.html +2 -2
  93. nautobot/core/templates/inc/table.html +2 -2
  94. nautobot/core/templates/nautobot_config.py.j2 +28 -8
  95. nautobot/core/templates/utilities/templatetags/dynamic_group_assignment_modal.html +37 -0
  96. nautobot/core/templates/utilities/templatetags/filter_form_modal.html +2 -2
  97. nautobot/core/templates/utilities/templatetags/saved_view_modal.html +38 -0
  98. nautobot/core/templates/utilities/theme_preview.html +25 -8
  99. nautobot/core/templates/utilities/worker_status.html +152 -0
  100. nautobot/core/templatetags/buttons.py +335 -38
  101. nautobot/core/templatetags/form_helpers.py +1 -1
  102. nautobot/core/templatetags/helpers.py +181 -11
  103. nautobot/core/testing/api.py +5 -4
  104. nautobot/core/testing/filters.py +63 -14
  105. nautobot/core/testing/mixins.py +46 -0
  106. nautobot/core/testing/models.py +22 -0
  107. nautobot/core/testing/schema.py +4 -8
  108. nautobot/core/testing/views.py +31 -14
  109. nautobot/core/tests/integration/test_general_functionality.py +1 -1
  110. nautobot/core/tests/integration/test_import_objects_ui.py +1 -0
  111. nautobot/core/tests/integration/test_swagger.py +1 -1
  112. nautobot/core/tests/nautobot_config.py +0 -1
  113. nautobot/core/tests/runner.py +2 -2
  114. nautobot/core/tests/test_api.py +1 -0
  115. nautobot/core/tests/test_authentication.py +7 -2
  116. nautobot/core/tests/test_filters.py +11 -9
  117. nautobot/core/tests/test_forms.py +9 -0
  118. nautobot/core/tests/test_graphql.py +27 -16
  119. nautobot/core/tests/test_jobs.py +204 -2
  120. nautobot/core/tests/test_tables.py +3 -1
  121. nautobot/core/tests/test_templatetags_helpers.py +12 -5
  122. nautobot/core/tests/test_templatetags_netutils.py +3 -3
  123. nautobot/core/tests/test_utils.py +31 -20
  124. nautobot/core/tests/test_views.py +6 -6
  125. nautobot/core/urls.py +8 -3
  126. nautobot/core/utils/deprecation.py +29 -0
  127. nautobot/core/utils/filtering.py +12 -9
  128. nautobot/core/utils/lookup.py +37 -2
  129. nautobot/core/utils/requests.py +4 -1
  130. nautobot/core/views/__init__.py +137 -24
  131. nautobot/core/views/generic.py +119 -67
  132. nautobot/core/views/mixins.py +105 -36
  133. nautobot/core/views/paginator.py +9 -3
  134. nautobot/core/views/renderers.py +121 -56
  135. nautobot/core/views/utils.py +81 -1
  136. nautobot/dcim/__init__.py +0 -1
  137. nautobot/dcim/api/serializers.py +180 -44
  138. nautobot/dcim/api/urls.py +7 -3
  139. nautobot/dcim/api/views.py +53 -7
  140. nautobot/dcim/apps.py +3 -0
  141. nautobot/dcim/choices.py +25 -0
  142. nautobot/dcim/constants.py +7 -0
  143. nautobot/dcim/factory.py +252 -18
  144. nautobot/dcim/filters/__init__.py +373 -193
  145. nautobot/dcim/filters/mixins.py +274 -1
  146. nautobot/dcim/forms.py +834 -121
  147. nautobot/dcim/graphql/types.py +2 -2
  148. nautobot/dcim/homepage.py +1 -1
  149. nautobot/dcim/migrations/0059_add_role_field_to_interface_models.py +27 -0
  150. nautobot/dcim/migrations/0060_alter_cable_status_alter_consoleport__path_and_more.py +303 -0
  151. nautobot/dcim/migrations/0061_module_models.py +862 -0
  152. nautobot/dcim/migrations/0062_module_data_migration.py +25 -0
  153. nautobot/dcim/models/__init__.py +8 -0
  154. nautobot/dcim/models/cables.py +15 -0
  155. nautobot/dcim/models/device_component_templates.py +207 -53
  156. nautobot/dcim/models/device_components.py +282 -99
  157. nautobot/dcim/models/devices.py +472 -13
  158. nautobot/dcim/models/racks.py +0 -1
  159. nautobot/dcim/navigation.py +47 -0
  160. nautobot/dcim/signals.py +3 -3
  161. nautobot/dcim/tables/__init__.py +35 -23
  162. nautobot/dcim/tables/devices.py +248 -47
  163. nautobot/dcim/tables/devicetypes.py +65 -9
  164. nautobot/dcim/tables/racks.py +5 -1
  165. nautobot/dcim/tables/template_code.py +46 -26
  166. nautobot/dcim/templates/dcim/cable_connect.html +76 -3
  167. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -5
  168. nautobot/dcim/templates/dcim/device/base.html +14 -6
  169. nautobot/dcim/templates/dcim/device/consoleports.html +2 -3
  170. nautobot/dcim/templates/dcim/device/consoleserverports.html +2 -3
  171. nautobot/dcim/templates/dcim/device/devicebays.html +6 -7
  172. nautobot/dcim/templates/dcim/device/frontports.html +2 -3
  173. nautobot/dcim/templates/dcim/device/interfaces.html +2 -3
  174. nautobot/dcim/templates/dcim/device/inventory.html +2 -3
  175. nautobot/dcim/templates/dcim/device/modulebays.html +49 -0
  176. nautobot/dcim/templates/dcim/device/poweroutlets.html +2 -3
  177. nautobot/dcim/templates/dcim/device/powerports.html +2 -3
  178. nautobot/dcim/templates/dcim/device/rearports.html +2 -3
  179. nautobot/dcim/templates/dcim/device.html +45 -1
  180. nautobot/dcim/templates/dcim/device_component.html +13 -5
  181. nautobot/dcim/templates/dcim/device_list.html +2 -1
  182. nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +6 -0
  183. nautobot/dcim/templates/dcim/devicetype.html +99 -98
  184. nautobot/dcim/templates/dcim/devicetype_list.html +8 -16
  185. nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
  186. nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +39 -0
  187. nautobot/dcim/templates/dcim/interface.html +17 -2
  188. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -5
  189. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  190. nautobot/dcim/templates/dcim/manufacturer.html +24 -0
  191. nautobot/dcim/templates/dcim/module/base.html +97 -0
  192. nautobot/dcim/templates/dcim/module_bulk_destroy.html +5 -0
  193. nautobot/dcim/templates/dcim/module_consoleports.html +53 -0
  194. nautobot/dcim/templates/dcim/module_consoleserverports.html +53 -0
  195. nautobot/dcim/templates/dcim/module_destroy.html +5 -0
  196. nautobot/dcim/templates/dcim/module_frontports.html +53 -0
  197. nautobot/dcim/templates/dcim/module_interfaces.html +57 -0
  198. nautobot/dcim/templates/dcim/module_list.html +20 -0
  199. nautobot/dcim/templates/dcim/module_modulebays.html +49 -0
  200. nautobot/dcim/templates/dcim/module_poweroutlets.html +53 -0
  201. nautobot/dcim/templates/dcim/module_powerports.html +53 -0
  202. nautobot/dcim/templates/dcim/module_rearports.html +53 -0
  203. nautobot/dcim/templates/dcim/module_retrieve.html +63 -0
  204. nautobot/dcim/templates/dcim/module_update.html +71 -0
  205. nautobot/dcim/templates/dcim/modulebay_bulk_destroy.html +5 -0
  206. nautobot/dcim/templates/dcim/modulebay_destroy.html +8 -0
  207. nautobot/dcim/templates/dcim/modulebay_retrieve.html +101 -0
  208. nautobot/dcim/templates/dcim/moduletype_list.html +11 -0
  209. nautobot/dcim/templates/dcim/moduletype_retrieve.html +159 -0
  210. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -5
  211. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +65 -19
  212. nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
  213. nautobot/dcim/tests/test_api.py +693 -208
  214. nautobot/dcim/tests/test_filters.py +843 -217
  215. nautobot/dcim/tests/test_models.py +1103 -8
  216. nautobot/dcim/tests/test_views.py +1525 -343
  217. nautobot/dcim/urls.py +17 -2
  218. nautobot/dcim/utils.py +2 -3
  219. nautobot/dcim/views.py +1109 -113
  220. nautobot/extras/__init__.py +0 -1
  221. nautobot/extras/api/serializers.py +115 -3
  222. nautobot/extras/api/urls.py +12 -0
  223. nautobot/extras/api/views.py +73 -59
  224. nautobot/extras/apps.py +2 -2
  225. nautobot/extras/choices.py +43 -0
  226. nautobot/extras/context_managers.py +13 -8
  227. nautobot/extras/datasources/git.py +2 -0
  228. nautobot/extras/factory.py +460 -9
  229. nautobot/extras/filters/__init__.py +174 -3
  230. nautobot/extras/filters/mixins.py +46 -43
  231. nautobot/extras/forms/base.py +24 -5
  232. nautobot/extras/forms/forms.py +227 -8
  233. nautobot/extras/forms/mixins.py +93 -0
  234. nautobot/extras/graphql/types.py +23 -10
  235. nautobot/extras/homepage.py +26 -3
  236. nautobot/extras/jobs.py +2 -2
  237. nautobot/extras/management/__init__.py +1 -0
  238. nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +1 -16
  239. nautobot/extras/migrations/0021_customfield_changelog_data.py +1 -0
  240. nautobot/extras/migrations/0109_dynamicgroup_group_type_dynamicgroup_tags_and_more.py +108 -0
  241. nautobot/extras/migrations/0110_alter_configcontext_cluster_groups_and_more.py +111 -0
  242. nautobot/extras/migrations/0111_metadata.py +162 -0
  243. nautobot/extras/migrations/0112_dynamic_group_group_type_data_migration.py +28 -0
  244. nautobot/extras/migrations/0113_saved_views.py +77 -0
  245. nautobot/extras/models/__init__.py +15 -1
  246. nautobot/extras/models/change_logging.py +3 -3
  247. nautobot/extras/models/contacts.py +4 -0
  248. nautobot/extras/models/customfields.py +18 -3
  249. nautobot/extras/models/groups.py +389 -225
  250. nautobot/extras/models/jobs.py +87 -3
  251. nautobot/extras/models/metadata.py +441 -0
  252. nautobot/extras/models/mixins.py +72 -62
  253. nautobot/extras/models/models.py +118 -9
  254. nautobot/extras/models/relationships.py +9 -2
  255. nautobot/extras/models/tags.py +13 -2
  256. nautobot/extras/navigation.py +57 -0
  257. nautobot/extras/plugins/__init__.py +3 -1
  258. nautobot/extras/querysets.py +30 -66
  259. nautobot/extras/signals.py +109 -101
  260. nautobot/extras/tables.py +201 -17
  261. nautobot/extras/templates/extras/dynamicgroup.html +44 -15
  262. nautobot/extras/templates/extras/dynamicgroup_edit.html +2 -0
  263. nautobot/extras/templates/extras/job.html +1 -1
  264. nautobot/extras/templates/extras/job_detail.html +11 -0
  265. nautobot/extras/templates/extras/jobresult.html +61 -74
  266. nautobot/extras/templates/extras/metadatatype_create.html +89 -0
  267. nautobot/extras/templates/extras/metadatatype_retrieve.html +67 -0
  268. nautobot/extras/templates/extras/object_dynamicgroups.html +7 -0
  269. nautobot/extras/templates/extras/objectchange_list.html +0 -12
  270. nautobot/extras/templates/extras/plugins_list.html +1 -3
  271. nautobot/extras/templates/extras/role_retrieve.html +48 -0
  272. nautobot/extras/templates/extras/staticgroupassociation_retrieve.html +20 -0
  273. nautobot/extras/tests/integration/test_customfields.py +1 -0
  274. nautobot/extras/tests/test_api.py +509 -23
  275. nautobot/extras/tests/test_changelog.py +20 -9
  276. nautobot/extras/tests/test_context_managers.py +22 -15
  277. nautobot/extras/tests/test_datasources.py +13 -1
  278. nautobot/extras/tests/test_dynamicgroups.py +201 -171
  279. nautobot/extras/tests/test_filters.py +211 -12
  280. nautobot/extras/tests/test_jobs.py +6 -6
  281. nautobot/extras/tests/test_models.py +501 -4
  282. nautobot/extras/tests/test_relationships.py +1 -0
  283. nautobot/extras/tests/test_views.py +586 -8
  284. nautobot/extras/tests/test_webhooks.py +1 -1
  285. nautobot/extras/urls.py +5 -0
  286. nautobot/extras/utils.py +85 -16
  287. nautobot/extras/views.py +562 -122
  288. nautobot/ipam/__init__.py +0 -1
  289. nautobot/ipam/apps.py +1 -0
  290. nautobot/ipam/factory.py +17 -19
  291. nautobot/ipam/filters.py +13 -0
  292. nautobot/ipam/forms.py +8 -4
  293. nautobot/ipam/graphql/types.py +2 -2
  294. nautobot/ipam/migrations/0047_alter_ipaddress_role_alter_ipaddress_status_and_more.py +59 -0
  295. nautobot/ipam/models.py +20 -20
  296. nautobot/ipam/querysets.py +1 -1
  297. nautobot/ipam/signals.py +4 -2
  298. nautobot/ipam/tables.py +5 -0
  299. nautobot/ipam/templates/ipam/ipaddress_interfaces.html +1 -1
  300. nautobot/ipam/templates/ipam/ipaddress_vm_interfaces.html +1 -1
  301. nautobot/ipam/templates/ipam/prefix.html +1 -0
  302. nautobot/ipam/tests/test_api.py +37 -18
  303. nautobot/ipam/tests/test_filters.py +26 -2
  304. nautobot/ipam/tests/test_models.py +9 -2
  305. nautobot/ipam/tests/test_querysets.py +1 -1
  306. nautobot/ipam/tests/test_views.py +3 -2
  307. nautobot/ipam/urls.py +2 -2
  308. nautobot/ipam/views.py +20 -34
  309. nautobot/project-static/css/base.css +21 -0
  310. nautobot/project-static/css/dark.css +11 -0
  311. nautobot/project-static/docs/404.html +894 -90
  312. nautobot/project-static/docs/apps/index.html +894 -90
  313. nautobot/project-static/docs/apps/nautobot-apps.html +894 -90
  314. nautobot/project-static/docs/assets/_mkdocstrings.css +5 -0
  315. nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css +1 -0
  316. nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css.map +1 -0
  317. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +921 -122
  318. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +906 -103
  319. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1620 -905
  320. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +937 -146
  321. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +979 -190
  322. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +903 -101
  323. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +899 -95
  324. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +993 -195
  325. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +976 -133
  326. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +1080 -274
  327. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1244 -336
  328. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1729 -877
  329. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +1166 -383
  330. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2090 -1376
  331. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2248 -1424
  332. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +914 -113
  333. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +965 -165
  334. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1012 -225
  335. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +1915 -1279
  336. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1848 -1104
  337. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +906 -103
  338. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +2335 -1701
  339. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +1804 -1026
  340. nautobot/project-static/docs/development/apps/api/configuration-view.html +894 -90
  341. nautobot/project-static/docs/development/apps/api/database-backend-config.html +894 -90
  342. nautobot/project-static/docs/development/apps/api/models/django-admin.html +894 -90
  343. nautobot/project-static/docs/development/apps/api/models/global-search.html +894 -90
  344. nautobot/project-static/docs/development/apps/api/models/graphql.html +894 -90
  345. nautobot/project-static/docs/development/apps/api/models/index.html +944 -92
  346. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +894 -90
  347. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +894 -90
  348. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +894 -90
  349. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +894 -90
  350. nautobot/project-static/docs/development/apps/api/platform-features/index.html +894 -90
  351. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +894 -90
  352. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +894 -90
  353. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +894 -90
  354. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +894 -90
  355. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +894 -90
  356. nautobot/project-static/docs/development/apps/api/prometheus.html +894 -90
  357. nautobot/project-static/docs/development/apps/api/setup.html +894 -90
  358. nautobot/project-static/docs/development/apps/api/testing.html +894 -90
  359. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +894 -90
  360. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +894 -90
  361. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +894 -90
  362. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +894 -90
  363. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +894 -90
  364. nautobot/project-static/docs/development/apps/api/views/base-template.html +894 -90
  365. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +894 -90
  366. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +894 -90
  367. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +894 -90
  368. nautobot/project-static/docs/development/apps/api/views/index.html +894 -90
  369. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +894 -90
  370. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +894 -90
  371. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +894 -90
  372. nautobot/project-static/docs/development/apps/api/views/notes.html +894 -90
  373. nautobot/project-static/docs/development/apps/api/views/rest-api.html +894 -90
  374. nautobot/project-static/docs/development/apps/api/views/urls.html +894 -90
  375. nautobot/project-static/docs/development/apps/index.html +894 -90
  376. nautobot/project-static/docs/development/apps/migration/code-updates.html +894 -90
  377. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +894 -90
  378. nautobot/project-static/docs/development/apps/migration/from-v1.html +894 -90
  379. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +894 -90
  380. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +894 -90
  381. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +894 -90
  382. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +894 -90
  383. nautobot/project-static/docs/development/apps/porting-from-netbox.html +894 -90
  384. nautobot/project-static/docs/development/core/application-registry.html +894 -90
  385. nautobot/project-static/docs/development/core/best-practices.html +895 -90
  386. nautobot/project-static/docs/development/core/bootstrap-ui.html +894 -90
  387. nautobot/project-static/docs/development/core/caching.html +894 -90
  388. nautobot/project-static/docs/development/core/controllers.html +894 -90
  389. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +894 -90
  390. nautobot/project-static/docs/development/core/generic-views.html +894 -90
  391. nautobot/project-static/docs/development/core/getting-started.html +894 -90
  392. nautobot/project-static/docs/development/core/homepage.html +894 -90
  393. nautobot/project-static/docs/development/core/index.html +905 -90
  394. nautobot/project-static/docs/development/core/model-checklist.html +903 -91
  395. nautobot/project-static/docs/development/core/model-features.html +894 -90
  396. nautobot/project-static/docs/development/core/natural-keys.html +894 -90
  397. nautobot/project-static/docs/development/core/navigation-menu.html +894 -90
  398. nautobot/project-static/docs/development/core/release-checklist.html +897 -93
  399. nautobot/project-static/docs/development/core/role-internals.html +894 -90
  400. nautobot/project-static/docs/development/core/settings.html +894 -90
  401. nautobot/project-static/docs/development/core/style-guide.html +895 -91
  402. nautobot/project-static/docs/development/core/templates.html +906 -91
  403. nautobot/project-static/docs/development/core/testing.html +894 -90
  404. nautobot/project-static/docs/development/core/user-preferences.html +894 -90
  405. nautobot/project-static/docs/development/index.html +894 -90
  406. nautobot/project-static/docs/development/jobs/index.html +1271 -453
  407. nautobot/project-static/docs/development/jobs/migration/from-v1.html +894 -90
  408. nautobot/project-static/docs/index.html +9032 -13
  409. nautobot/project-static/docs/media/models/cloud_aws_direct_connect_dark.png +0 -0
  410. nautobot/project-static/docs/media/models/cloud_aws_direct_connect_light.png +0 -0
  411. nautobot/project-static/docs/models/cloud/cloudaccount.html +15 -0
  412. nautobot/project-static/docs/models/cloud/cloudnetwork.html +15 -0
  413. nautobot/project-static/docs/models/cloud/cloudnetworkprefixassignment.html +15 -0
  414. nautobot/project-static/docs/models/cloud/cloudresourcetype.html +15 -0
  415. nautobot/project-static/docs/models/cloud/cloudservice.html +15 -0
  416. nautobot/project-static/docs/models/cloud/cloudservicenetworkassignment.html +15 -0
  417. nautobot/project-static/docs/models/dcim/module.html +15 -0
  418. nautobot/project-static/docs/models/dcim/modulebay.html +15 -0
  419. nautobot/project-static/docs/models/dcim/modulebaytemplate.html +15 -0
  420. nautobot/project-static/docs/models/dcim/moduletype.html +15 -0
  421. nautobot/project-static/docs/models/extras/metadatachoice.html +15 -0
  422. nautobot/project-static/docs/models/extras/metadatatype.html +15 -0
  423. nautobot/project-static/docs/models/extras/objectmetadata.html +15 -0
  424. nautobot/project-static/docs/models/extras/role.html +15 -0
  425. nautobot/project-static/docs/models/extras/savedview.html +15 -0
  426. nautobot/project-static/docs/models/extras/staticgroupassociation.html +15 -0
  427. nautobot/project-static/docs/models/extras/status.html +15 -0
  428. nautobot/project-static/docs/objects.inv +0 -0
  429. nautobot/project-static/docs/overview/application_stack.html +902 -91
  430. nautobot/project-static/docs/overview/design_philosophy.html +896 -92
  431. nautobot/project-static/docs/overview/index.html +13 -8228
  432. nautobot/project-static/docs/release-notes/index.html +1131 -94
  433. nautobot/project-static/docs/release-notes/version-1.0.html +894 -90
  434. nautobot/project-static/docs/release-notes/version-1.1.html +894 -90
  435. nautobot/project-static/docs/release-notes/version-1.2.html +894 -90
  436. nautobot/project-static/docs/release-notes/version-1.3.html +894 -90
  437. nautobot/project-static/docs/release-notes/version-1.4.html +894 -90
  438. nautobot/project-static/docs/release-notes/version-1.5.html +895 -91
  439. nautobot/project-static/docs/release-notes/version-1.6.html +895 -91
  440. nautobot/project-static/docs/release-notes/version-2.0.html +894 -90
  441. nautobot/project-static/docs/release-notes/version-2.1.html +894 -90
  442. nautobot/project-static/docs/release-notes/version-2.2.html +1137 -196
  443. nautobot/project-static/docs/release-notes/version-2.3.html +9954 -0
  444. nautobot/project-static/docs/requirements.txt +5 -5
  445. nautobot/project-static/docs/search/search_index.json +1 -1
  446. nautobot/project-static/docs/sitemap.xml +335 -260
  447. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  448. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +894 -90
  449. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +894 -90
  450. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +894 -90
  451. nautobot/project-static/docs/user-guide/administration/configuration/index.html +894 -90
  452. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +1025 -175
  453. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +894 -90
  454. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +894 -90
  455. nautobot/project-static/docs/user-guide/administration/guides/caching.html +894 -90
  456. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +902 -90
  457. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +894 -90
  458. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +894 -90
  459. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +894 -90
  460. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +894 -90
  461. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +894 -90
  462. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +894 -90
  463. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +894 -90
  464. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +894 -90
  465. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +946 -155
  466. nautobot/project-static/docs/user-guide/administration/installation/index.html +903 -95
  467. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +936 -124
  468. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +956 -159
  469. nautobot/project-static/docs/user-guide/administration/installation/services.html +915 -114
  470. nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +910 -101
  471. nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +894 -90
  472. nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +894 -90
  473. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +894 -90
  474. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +894 -90
  475. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +977 -121
  476. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +894 -90
  477. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +894 -90
  478. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +894 -90
  479. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +894 -90
  480. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +894 -90
  481. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +894 -90
  482. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +894 -90
  483. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +894 -90
  484. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +894 -90
  485. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +894 -90
  486. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +894 -90
  487. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +895 -91
  488. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +894 -90
  489. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +898 -90
  490. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +897 -93
  491. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +8984 -0
  492. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +8828 -0
  493. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +8829 -0
  494. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +8828 -0
  495. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +8829 -0
  496. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +8833 -0
  497. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +8828 -0
  498. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +908 -104
  499. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +925 -107
  500. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +925 -107
  501. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +920 -102
  502. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +925 -107
  503. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +908 -104
  504. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +908 -104
  505. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +915 -107
  506. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +922 -118
  507. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +923 -119
  508. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +920 -116
  509. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +908 -104
  510. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +916 -107
  511. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +928 -110
  512. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +938 -120
  513. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +930 -108
  514. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +908 -104
  515. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +939 -121
  516. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +930 -112
  517. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +920 -116
  518. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +923 -119
  519. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +925 -117
  520. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +8828 -0
  521. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +8846 -0
  522. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +8843 -0
  523. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +8823 -0
  524. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +918 -114
  525. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +908 -104
  526. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +942 -85
  527. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +926 -108
  528. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +908 -104
  529. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +945 -88
  530. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +923 -105
  531. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +931 -127
  532. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +920 -116
  533. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +908 -104
  534. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +924 -106
  535. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +926 -108
  536. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +908 -104
  537. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +908 -104
  538. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +908 -104
  539. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +938 -90
  540. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +894 -90
  541. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +899 -91
  542. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +899 -91
  543. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +894 -90
  544. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +894 -90
  545. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +894 -90
  546. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +894 -90
  547. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +894 -90
  548. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +894 -90
  549. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +894 -90
  550. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +894 -90
  551. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +894 -90
  552. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +894 -90
  553. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +903 -98
  554. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +894 -90
  555. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +894 -90
  556. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +894 -90
  557. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +894 -90
  558. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +894 -90
  559. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +899 -91
  560. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +894 -90
  561. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +894 -90
  562. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +894 -90
  563. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +894 -90
  564. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +894 -90
  565. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +894 -90
  566. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +894 -90
  567. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +894 -90
  568. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +894 -90
  569. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +894 -90
  570. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +894 -90
  571. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +894 -90
  572. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +894 -90
  573. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/clear-view-button.png +0 -0
  574. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/cleared-view.png +0 -0
  575. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/config-table-columns-to-locations.png +0 -0
  576. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/configure-button.png +0 -0
  577. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/create-saved-view-success.png +0 -0
  578. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/current-saved-view-drop-down-menu.png +0 -0
  579. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/default-location-list-view.png +0 -0
  580. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/dropdown-button-after-new-saved-view.png +0 -0
  581. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-application-to-locations.png +0 -0
  582. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-button.png +0 -0
  583. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/global-default-location-list-view.png +0 -0
  584. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/location-list-view-with-saved-views.png +0 -0
  585. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/navigation-menu.png +0 -0
  586. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-as-new-view-drop-down.png +0 -0
  587. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-view-modal.png +0 -0
  588. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-buttons.png +0 -0
  589. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-success.png +0 -0
  590. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view-unchecked.png +0 -0
  591. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view.png +0 -0
  592. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-different-user.png +0 -0
  593. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-modal-unchecked.png +0 -0
  594. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-button.png +0 -0
  595. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-success.png +0 -0
  596. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/unsaved-saved-view.png +0 -0
  597. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/updated-saved-view.png +0 -0
  598. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +894 -90
  599. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +894 -90
  600. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +894 -90
  601. nautobot/project-static/docs/user-guide/index.html +894 -90
  602. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +894 -90
  603. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +894 -90
  604. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +894 -90
  605. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +894 -90
  606. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +1260 -787
  607. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +897 -93
  608. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +894 -90
  609. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +894 -90
  610. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +894 -90
  611. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +894 -90
  612. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +894 -90
  613. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +894 -90
  614. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +894 -90
  615. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +894 -90
  616. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +894 -90
  617. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +898 -90
  618. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +894 -90
  619. nautobot/project-static/docs/user-guide/platform-functionality/note.html +897 -93
  620. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +9061 -0
  621. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +897 -93
  622. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +894 -90
  623. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +894 -90
  624. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +894 -90
  625. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +894 -90
  626. nautobot/project-static/docs/user-guide/platform-functionality/role.html +897 -93
  627. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +9137 -0
  628. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +897 -93
  629. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +8933 -0
  630. nautobot/project-static/docs/user-guide/platform-functionality/status.html +894 -90
  631. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +894 -90
  632. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +952 -123
  633. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +894 -90
  634. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +894 -90
  635. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +894 -90
  636. nautobot/project-static/js/forms.js +71 -0
  637. nautobot/project-static/js/table_sorting_indicator.js +46 -0
  638. nautobot/project-static/js/tableconfig.js +6 -1
  639. nautobot/project-static/materialdesignicons-7.4.47/css/materialdesignicons.min.css +3 -0
  640. nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.eot +0 -0
  641. nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.ttf +0 -0
  642. nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff +0 -0
  643. nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff2 +0 -0
  644. nautobot/tenancy/__init__.py +0 -1
  645. nautobot/tenancy/apps.py +1 -0
  646. nautobot/tenancy/factory.py +3 -2
  647. nautobot/tenancy/filters/__init__.py +1 -0
  648. nautobot/tenancy/forms.py +1 -1
  649. nautobot/tenancy/templates/tenancy/tenant.html +24 -20
  650. nautobot/tenancy/views.py +11 -10
  651. nautobot/users/__init__.py +0 -1
  652. nautobot/users/api/serializers.py +1 -1
  653. nautobot/users/api/views.py +4 -2
  654. nautobot/users/apps.py +3 -2
  655. nautobot/users/factory.py +3 -3
  656. nautobot/users/migrations/0010_user_default_saved_views.py +20 -0
  657. nautobot/users/models.py +12 -0
  658. nautobot/users/tests/test_filters.py +6 -3
  659. nautobot/users/urls.py +8 -0
  660. nautobot/virtualization/__init__.py +0 -1
  661. nautobot/virtualization/apps.py +1 -0
  662. nautobot/virtualization/filters.py +6 -1
  663. nautobot/virtualization/forms.py +11 -3
  664. nautobot/virtualization/graphql/types.py +2 -2
  665. nautobot/virtualization/migrations/0029_add_role_field_to_interface_models.py +27 -0
  666. nautobot/virtualization/migrations/0030_alter_virtualmachine_local_config_context_data_owner_content_type_and_more.py +67 -0
  667. nautobot/virtualization/models.py +0 -2
  668. nautobot/virtualization/tables.py +12 -8
  669. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
  670. nautobot/virtualization/templates/virtualization/vminterface.html +7 -1
  671. nautobot/virtualization/templates/virtualization/vminterface_edit.html +1 -0
  672. nautobot/virtualization/tests/test_api.py +9 -4
  673. nautobot/virtualization/tests/test_filters.py +22 -0
  674. nautobot/virtualization/tests/test_models.py +7 -3
  675. nautobot/virtualization/tests/test_views.py +19 -3
  676. nautobot/virtualization/urls.py +2 -2
  677. nautobot/virtualization/views.py +10 -32
  678. {nautobot-2.2.8.dist-info → nautobot-2.3.0.dist-info}/METADATA +21 -19
  679. {nautobot-2.2.8.dist-info → nautobot-2.3.0.dist-info}/RECORD +684 -564
  680. nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css +0 -1
  681. nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css.map +0 -1
  682. nautobot/project-static/materialdesignicons-6.5.95/.github/ISSUE_TEMPLATE.md +0 -3
  683. nautobot/project-static/materialdesignicons-6.5.95/README.md +0 -25
  684. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css +0 -26654
  685. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css.map +0 -16
  686. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css +0 -3
  687. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css.map +0 -16
  688. nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff +0 -0
  689. nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff2 +0 -0
  690. nautobot/project-static/materialdesignicons-6.5.95/package.json +0 -28
  691. nautobot/project-static/materialdesignicons-6.5.95/preview.html +0 -717
  692. nautobot/project-static/materialdesignicons-6.5.95/scss/_animated.scss +0 -27
  693. nautobot/project-static/materialdesignicons-6.5.95/scss/_core.scss +0 -10
  694. nautobot/project-static/materialdesignicons-6.5.95/scss/_extras.scss +0 -65
  695. nautobot/project-static/materialdesignicons-6.5.95/scss/_functions.scss +0 -20
  696. nautobot/project-static/materialdesignicons-6.5.95/scss/_icons.scss +0 -10
  697. nautobot/project-static/materialdesignicons-6.5.95/scss/_path.scss +0 -10
  698. nautobot/project-static/materialdesignicons-6.5.95/scss/_variables.scss +0 -6606
  699. nautobot/project-static/materialdesignicons-6.5.95/scss/materialdesignicons.scss +0 -8
  700. /nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/LICENSE +0 -0
  701. {nautobot-2.2.8.dist-info → nautobot-2.3.0.dist-info}/LICENSE.txt +0 -0
  702. {nautobot-2.2.8.dist-info → nautobot-2.3.0.dist-info}/NOTICE +0 -0
  703. {nautobot-2.2.8.dist-info → nautobot-2.3.0.dist-info}/WHEEL +0 -0
  704. {nautobot-2.2.8.dist-info → nautobot-2.3.0.dist-info}/entry_points.txt +0 -0
@@ -24,6 +24,7 @@ from nautobot.dcim.choices import (
24
24
  SoftwareImageFileHashingAlgorithmChoices,
25
25
  SubdeviceRoleChoices,
26
26
  )
27
+ from nautobot.dcim.constants import MODULE_RECURSION_DEPTH_LIMIT
27
28
  from nautobot.dcim.utils import get_all_network_driver_mappings
28
29
  from nautobot.extras.models import ChangeLoggedModel, ConfigContextModel, RoleField, StatusField
29
30
  from nautobot.extras.querysets import ConfigContextModelQuerySet
@@ -36,6 +37,7 @@ from .device_components import (
36
37
  FrontPort,
37
38
  Interface,
38
39
  InventoryItem,
40
+ ModuleBay,
39
41
  PowerOutlet,
40
42
  PowerPort,
41
43
  RearPort,
@@ -110,6 +112,7 @@ class DeviceTypeToSoftwareImageFile(BaseModel, ChangeLoggedModel):
110
112
  software_image_file = models.ForeignKey(
111
113
  "dcim.SoftwareImageFile", on_delete=models.PROTECT, related_name="device_type_mappings"
112
114
  )
115
+ is_metadata_associable_model = False
113
116
 
114
117
  class Meta:
115
118
  unique_together = [
@@ -296,6 +299,16 @@ class DeviceType(PrimaryModel):
296
299
  }
297
300
  for c in self.device_bay_templates.all()
298
301
  ]
302
+ if self.module_bay_templates.exists():
303
+ data["module-bays"] = [
304
+ {
305
+ "name": c.name,
306
+ "position": c.position,
307
+ "label": c.label,
308
+ "description": c.description,
309
+ }
310
+ for c in self.module_bay_templates.all()
311
+ ]
299
312
 
300
313
  return yaml.dump(dict(data), sort_keys=False, allow_unicode=True)
301
314
 
@@ -439,7 +452,6 @@ class Platform(OrganizationalModel):
439
452
  @extras_features(
440
453
  "custom_links",
441
454
  "custom_validators",
442
- "dynamic_groups",
443
455
  "export_templates",
444
456
  "graphql",
445
457
  "locations",
@@ -733,7 +745,7 @@ class Device(PrimaryModel, ConfigContextModel):
733
745
  pass
734
746
 
735
747
  # Validate primary IP addresses
736
- vc_interfaces = self.vc_interfaces.all()
748
+ all_interfaces = self.all_interfaces.all()
737
749
  for field in ["primary_ip4", "primary_ip6"]:
738
750
  ip = getattr(self, field)
739
751
  if ip is not None:
@@ -743,12 +755,14 @@ class Device(PrimaryModel, ConfigContextModel):
743
755
  else:
744
756
  if ip.ip_version != 6:
745
757
  raise ValidationError({f"{field}": f"{ip} is not an IPv6 address."})
746
- if ipam_models.IPAddressToInterface.objects.filter(ip_address=ip, interface__in=vc_interfaces).exists():
758
+ if ipam_models.IPAddressToInterface.objects.filter(
759
+ ip_address=ip, interface__in=all_interfaces
760
+ ).exists():
747
761
  pass
748
762
  elif (
749
763
  ip.nat_inside is not None
750
764
  and ipam_models.IPAddressToInterface.objects.filter(
751
- ip_address=ip.nat_inside, interface__in=vc_interfaces
765
+ ip_address=ip.nat_inside, interface__in=all_interfaces
752
766
  ).exists()
753
767
  ):
754
768
  pass
@@ -847,7 +861,7 @@ class Device(PrimaryModel, ConfigContextModel):
847
861
  """Create device components from the device type definition."""
848
862
  # The order of these is significant as
849
863
  # - PowerOutlet depends on PowerPort
850
- # - FrontPort depends on FrontPort
864
+ # - FrontPort depends on RearPort
851
865
  component_models = [
852
866
  (ConsolePort, self.device_type.console_port_templates.all()),
853
867
  (ConsoleServerPort, self.device_type.console_server_port_templates.all()),
@@ -857,10 +871,11 @@ class Device(PrimaryModel, ConfigContextModel):
857
871
  (RearPort, self.device_type.rear_port_templates.all()),
858
872
  (FrontPort, self.device_type.front_port_templates.all()),
859
873
  (DeviceBay, self.device_type.device_bay_templates.all()),
874
+ (ModuleBay, self.device_type.module_bay_templates.all()),
860
875
  ]
861
876
  instantiated_components = []
862
877
  for model, templates in component_models:
863
- model.objects.bulk_create([x.instantiate(self) for x in templates])
878
+ model.objects.bulk_create([x.instantiate(device=self) for x in templates])
864
879
  return instantiated_components
865
880
 
866
881
  @property
@@ -906,10 +921,11 @@ class Device(PrimaryModel, ConfigContextModel):
906
921
  Return a QuerySet matching all Interfaces assigned to this Device or, if this Device is a VC master, to another
907
922
  Device belonging to the same VirtualChassis.
908
923
  """
909
- filter_q = Q(device=self)
924
+ qs = self.all_interfaces
910
925
  if self.virtual_chassis and self.virtual_chassis.master == self:
911
- filter_q |= Q(device__virtual_chassis=self.virtual_chassis, mgmt_only=False)
912
- return Interface.objects.filter(filter_q)
926
+ for member in self.virtual_chassis.members.exclude(id=self.id):
927
+ qs |= member.all_interfaces.filter(mgmt_only=False)
928
+ return qs
913
929
 
914
930
  @property
915
931
  def common_vc_interfaces(self):
@@ -919,7 +935,7 @@ class Device(PrimaryModel, ConfigContextModel):
919
935
  """
920
936
  if self.virtual_chassis:
921
937
  return self.virtual_chassis.member_interfaces
922
- return self.interfaces
938
+ return self.all_interfaces
923
939
 
924
940
  def get_cables(self, pk_list=False):
925
941
  """
@@ -950,6 +966,79 @@ class Device(PrimaryModel, ConfigContextModel):
950
966
  """
951
967
  return Device.objects.filter(parent_bay__device=self.pk)
952
968
 
969
+ @property
970
+ def all_modules(self):
971
+ """
972
+ Return all child Modules installed in ModuleBays within this Device.
973
+ """
974
+ # Supports Device->ModuleBay->Module->ModuleBay->Module->ModuleBay->Module->ModuleBay->Module
975
+ # This query looks for modules that are installed in a module_bay and attached to this device
976
+ # We artificially limit the recursion to 4 levels or we would be stuck in an infinite loop.
977
+ recursion_depth = MODULE_RECURSION_DEPTH_LIMIT
978
+ qs = Module.objects.all()
979
+ query = Q()
980
+ for level in range(recursion_depth):
981
+ recursive_query = "parent_module_bay__parent_module__" * level
982
+ query = query | Q(**{f"{recursive_query}parent_module_bay__parent_device": self})
983
+ return qs.filter(query)
984
+
985
+ @property
986
+ def all_console_ports(self):
987
+ """
988
+ Return all Console Ports that are installed in the device or in modules that are installed in the device.
989
+ """
990
+ # TODO: These could probably be optimized to reduce the number of joins
991
+ return ConsolePort.objects.filter(Q(device=self) | Q(module__in=self.all_modules))
992
+
993
+ @property
994
+ def all_console_server_ports(self):
995
+ """
996
+ Return all Console Server Ports that are installed in the device or in modules that are installed in the device.
997
+ """
998
+ return ConsoleServerPort.objects.filter(Q(device=self) | Q(module__in=self.all_modules))
999
+
1000
+ @property
1001
+ def all_front_ports(self):
1002
+ """
1003
+ Return all Front Ports that are installed in the device or in modules that are installed in the device.
1004
+ """
1005
+ return FrontPort.objects.filter(Q(device=self) | Q(module__in=self.all_modules))
1006
+
1007
+ @property
1008
+ def all_interfaces(self):
1009
+ """
1010
+ Return all Interfaces that are installed in the device or in modules that are installed in the device.
1011
+ """
1012
+ return Interface.objects.filter(Q(device=self) | Q(module__in=self.all_modules))
1013
+
1014
+ @property
1015
+ def all_module_bays(self):
1016
+ """
1017
+ Return all Module Bays that are installed in the device or in modules that are installed in the device.
1018
+ """
1019
+ return ModuleBay.objects.filter(Q(parent_device=self) | Q(parent_module__in=self.all_modules))
1020
+
1021
+ @property
1022
+ def all_power_ports(self):
1023
+ """
1024
+ Return all Power Ports that are installed in the device or in modules that are installed in the device.
1025
+ """
1026
+ return PowerPort.objects.filter(Q(device=self) | Q(module__in=self.all_modules))
1027
+
1028
+ @property
1029
+ def all_power_outlets(self):
1030
+ """
1031
+ Return all Power Outlets that are installed in the device or in modules that are installed in the device.
1032
+ """
1033
+ return PowerOutlet.objects.filter(Q(device=self) | Q(module__in=self.all_modules))
1034
+
1035
+ @property
1036
+ def all_rear_ports(self):
1037
+ """
1038
+ Return all Rear Ports that are installed in the device or in modules that are installed in the device.
1039
+ """
1040
+ return RearPort.objects.filter(Q(device=self) | Q(module__in=self.all_modules))
1041
+
953
1042
 
954
1043
  #
955
1044
  # Virtual chassis
@@ -1019,7 +1108,6 @@ class VirtualChassis(PrimaryModel):
1019
1108
  @extras_features(
1020
1109
  "custom_links",
1021
1110
  "custom_validators",
1022
- "dynamic_groups",
1023
1111
  "export_templates",
1024
1112
  "graphql",
1025
1113
  "statuses",
@@ -1065,6 +1153,10 @@ class DeviceRedundancyGroup(PrimaryModel):
1065
1153
  def devices_sorted(self):
1066
1154
  return self.devices.order_by("device_redundancy_group_priority")
1067
1155
 
1156
+ @property
1157
+ def controllers_sorted(self):
1158
+ return self.controllers.order_by("name")
1159
+
1068
1160
  def __str__(self):
1069
1161
  return self.name
1070
1162
 
@@ -1247,7 +1339,6 @@ class SoftwareVersion(PrimaryModel):
1247
1339
  @extras_features(
1248
1340
  "custom_links",
1249
1341
  "custom_validators",
1250
- "dynamic_groups",
1251
1342
  "export_templates",
1252
1343
  "graphql",
1253
1344
  "locations",
@@ -1331,7 +1422,6 @@ class Controller(PrimaryModel):
1331
1422
  @extras_features(
1332
1423
  "custom_links",
1333
1424
  "custom_validators",
1334
- "dynamic_groups",
1335
1425
  "export_templates",
1336
1426
  "graphql",
1337
1427
  "webhooks",
@@ -1382,3 +1472,372 @@ class ControllerManagedDeviceGroup(TreeModel, PrimaryModel):
1382
1472
  raise ValidationError(
1383
1473
  {"controller": "Controller device group must have the same controller as the parent group."}
1384
1474
  )
1475
+
1476
+
1477
+ #
1478
+ # Modules
1479
+ #
1480
+
1481
+
1482
+ # TODO: 5840 - Translate comments field from devicetype library, Nautobot doesn't use that field for ModuleType
1483
+ @extras_features(
1484
+ "custom_links",
1485
+ "custom_validators",
1486
+ "export_templates",
1487
+ "graphql",
1488
+ "webhooks",
1489
+ )
1490
+ class ModuleType(PrimaryModel):
1491
+ """
1492
+ A ModuleType represents a particular make (Manufacturer) and model of Module. A Module can represent
1493
+ a line card, supervisor, or other interchangeable hardware component within a ModuleBay.
1494
+
1495
+ ModuleType implements a subset of the features of DeviceType.
1496
+
1497
+ Each ModuleType can have an arbitrary number of component templates assigned to it,
1498
+ which define console, power, and interface objects. For example, a Cisco WS-SUP720-3B
1499
+ ModuleType would have:
1500
+
1501
+ * 1 ConsolePortTemplate
1502
+ * 2 InterfaceTemplates
1503
+
1504
+ When a new Module of this type is created, the appropriate console, power, and interface
1505
+ objects (as defined by the ModuleType) are automatically created as well.
1506
+ """
1507
+
1508
+ manufacturer = models.ForeignKey(to="dcim.Manufacturer", on_delete=models.PROTECT, related_name="module_types")
1509
+ model = models.CharField(max_length=CHARFIELD_MAX_LENGTH)
1510
+ part_number = models.CharField(
1511
+ max_length=CHARFIELD_MAX_LENGTH, blank=True, help_text="Discrete part number (optional)"
1512
+ )
1513
+ comments = models.TextField(blank=True)
1514
+
1515
+ clone_fields = [
1516
+ "manufacturer",
1517
+ ]
1518
+
1519
+ class Meta:
1520
+ ordering = ("manufacturer", "model")
1521
+ unique_together = [
1522
+ ("manufacturer", "model"),
1523
+ ]
1524
+
1525
+ def __str__(self):
1526
+ return self.model
1527
+
1528
+ def to_yaml(self):
1529
+ data = OrderedDict(
1530
+ (
1531
+ ("manufacturer", self.manufacturer.name),
1532
+ ("model", self.model),
1533
+ ("part_number", self.part_number),
1534
+ ("comments", self.comments),
1535
+ )
1536
+ )
1537
+
1538
+ # Component templates
1539
+ if self.console_port_templates.exists():
1540
+ data["console-ports"] = [
1541
+ {
1542
+ "name": c.name,
1543
+ "type": c.type,
1544
+ }
1545
+ for c in self.console_port_templates.all()
1546
+ ]
1547
+ if self.console_server_port_templates.exists():
1548
+ data["console-server-ports"] = [
1549
+ {
1550
+ "name": c.name,
1551
+ "type": c.type,
1552
+ }
1553
+ for c in self.console_server_port_templates.all()
1554
+ ]
1555
+ if self.power_port_templates.exists():
1556
+ data["power-ports"] = [
1557
+ {
1558
+ "name": c.name,
1559
+ "type": c.type,
1560
+ "maximum_draw": c.maximum_draw,
1561
+ "allocated_draw": c.allocated_draw,
1562
+ }
1563
+ for c in self.power_port_templates.all()
1564
+ ]
1565
+ if self.power_outlet_templates.exists():
1566
+ data["power-outlets"] = [
1567
+ {
1568
+ "name": c.name,
1569
+ "type": c.type,
1570
+ "power_port": c.power_port_template.name if c.power_port_template else None,
1571
+ "feed_leg": c.feed_leg,
1572
+ }
1573
+ for c in self.power_outlet_templates.all()
1574
+ ]
1575
+ if self.interface_templates.exists():
1576
+ data["interfaces"] = [
1577
+ {
1578
+ "name": c.name,
1579
+ "type": c.type,
1580
+ "mgmt_only": c.mgmt_only,
1581
+ }
1582
+ for c in self.interface_templates.all()
1583
+ ]
1584
+ if self.front_port_templates.exists():
1585
+ data["front-ports"] = [
1586
+ {
1587
+ "name": c.name,
1588
+ "type": c.type,
1589
+ "rear_port": c.rear_port_template.name,
1590
+ "rear_port_position": c.rear_port_position,
1591
+ }
1592
+ for c in self.front_port_templates.all()
1593
+ ]
1594
+ if self.rear_port_templates.exists():
1595
+ data["rear-ports"] = [
1596
+ {
1597
+ "name": c.name,
1598
+ "type": c.type,
1599
+ "positions": c.positions,
1600
+ }
1601
+ for c in self.rear_port_templates.all()
1602
+ ]
1603
+ if self.module_bay_templates.exists():
1604
+ data["module-bays"] = [
1605
+ {
1606
+ "name": c.name,
1607
+ "position": c.position,
1608
+ "label": c.label,
1609
+ "description": c.description,
1610
+ }
1611
+ for c in self.module_bay_templates.all()
1612
+ ]
1613
+
1614
+ return yaml.dump(dict(data), sort_keys=False, allow_unicode=True)
1615
+
1616
+ @property
1617
+ def display(self):
1618
+ return f"{self.manufacturer.name} {self.model}"
1619
+
1620
+
1621
+ @extras_features(
1622
+ "custom_links",
1623
+ "custom_validators",
1624
+ "export_templates",
1625
+ "graphql",
1626
+ "locations",
1627
+ "statuses",
1628
+ "webhooks",
1629
+ )
1630
+ class Module(PrimaryModel):
1631
+ """
1632
+ A Module represents a line card, supervisor, or other interchangeable hardware component within a ModuleBay.
1633
+ Each Module is assigned a ModuleType and Status, and optionally a Role and/or Tenant.
1634
+
1635
+ Each Module must be assigned to either a ModuleBay or a Location, but not both.
1636
+
1637
+ When a new Module is created, console, power and interface components are created along with it as dictated
1638
+ by the component templates assigned to its ModuleType. Components can also be added, modified, or deleted after
1639
+ the creation of a Module.
1640
+ """
1641
+
1642
+ module_type = models.ForeignKey(to="dcim.ModuleType", on_delete=models.PROTECT, related_name="modules")
1643
+ parent_module_bay = models.OneToOneField(
1644
+ to="dcim.ModuleBay",
1645
+ on_delete=models.CASCADE,
1646
+ related_name="installed_module",
1647
+ blank=True,
1648
+ null=True,
1649
+ )
1650
+ status = StatusField()
1651
+ role = RoleField(blank=True, null=True)
1652
+ tenant = models.ForeignKey(
1653
+ to="tenancy.Tenant",
1654
+ on_delete=models.PROTECT,
1655
+ related_name="modules",
1656
+ blank=True,
1657
+ null=True,
1658
+ )
1659
+ serial = models.CharField( # noqa: DJ001 # django-nullable-model-string-field -- intentional
1660
+ max_length=CHARFIELD_MAX_LENGTH,
1661
+ blank=True,
1662
+ null=True,
1663
+ verbose_name="Serial number",
1664
+ db_index=True,
1665
+ )
1666
+ asset_tag = models.CharField(
1667
+ max_length=CHARFIELD_MAX_LENGTH,
1668
+ blank=True,
1669
+ null=True,
1670
+ unique=True,
1671
+ verbose_name="Asset tag",
1672
+ help_text="A unique tag used to identify this module",
1673
+ )
1674
+ location = models.ForeignKey(
1675
+ to="dcim.Location",
1676
+ on_delete=models.PROTECT,
1677
+ related_name="modules",
1678
+ blank=True,
1679
+ null=True,
1680
+ )
1681
+ # TODO: add software support for Modules
1682
+
1683
+ clone_fields = [
1684
+ "module_type",
1685
+ "role",
1686
+ "tenant",
1687
+ "location",
1688
+ "status",
1689
+ ]
1690
+
1691
+ # The recursive nature of this model combined with the fact that it can be a child of a
1692
+ # device or location makes our natural key implementation unusable, so just use the pk
1693
+ natural_key_field_names = ["pk"]
1694
+
1695
+ class Meta:
1696
+ ordering = ("parent_module_bay", "location", "module_type", "asset_tag", "serial")
1697
+ constraints = [
1698
+ models.UniqueConstraint(
1699
+ fields=["module_type", "serial"],
1700
+ name="dcim_module_module_type_serial_unique",
1701
+ ),
1702
+ ]
1703
+
1704
+ def __str__(self):
1705
+ serial = f" (Serial: {self.serial})" if self.serial else ""
1706
+ asset_tag = f" (Asset Tag: {self.asset_tag})" if self.asset_tag else ""
1707
+ return str(self.module_type) + serial + asset_tag
1708
+
1709
+ @property
1710
+ def display(self):
1711
+ if self.location:
1712
+ return f"{self!s} at location {self.location}"
1713
+ elif self.parent_module_bay.parent_device is not None:
1714
+ return f"{self.module_type!s} installed in {self.parent_module_bay.parent_device.display}"
1715
+ else:
1716
+ return f"{self.module_type!s} installed in {self.parent_module_bay.parent_module.display}"
1717
+
1718
+ @property
1719
+ def device(self):
1720
+ """Walk up parent chain to find the Device that this Module is installed in, if one exists."""
1721
+ if self.parent_module_bay is None:
1722
+ return None
1723
+ return self.parent_module_bay.parent
1724
+
1725
+ def clean(self):
1726
+ super().clean()
1727
+
1728
+ # Validate that the Module is associated with a Location or a ModuleBay
1729
+ if self.parent_module_bay is None and self.location is None:
1730
+ raise ValidationError("One of location or parent_module_bay must be set")
1731
+
1732
+ # Validate location
1733
+ if self.location is not None:
1734
+ if self.parent_module_bay is not None:
1735
+ raise ValidationError("Only one of location or parent_module_bay must be set")
1736
+
1737
+ if ContentType.objects.get_for_model(self) not in self.location.location_type.content_types.all():
1738
+ raise ValidationError(
1739
+ {"location": f'Modules may not associate to locations of type "{self.location.location_type}".'}
1740
+ )
1741
+
1742
+ def save(self, *args, **kwargs):
1743
+ is_new = not self.present_in_database
1744
+
1745
+ if self.serial == "":
1746
+ self.serial = None
1747
+ if self.asset_tag == "":
1748
+ self.asset_tag = None
1749
+
1750
+ # Prevent creating a Module that is its own ancestor, creating an infinite loop
1751
+ parent_module = getattr(self.parent_module_bay, "parent_module", None)
1752
+ while parent_module is not None:
1753
+ if parent_module == self:
1754
+ raise ValidationError("Creating this instance would cause an infinite loop.")
1755
+ parent_module = getattr(parent_module.parent_module_bay, "parent_module", None)
1756
+
1757
+ # Keep track of whether the parent module bay has changed so we can update the component names
1758
+ parent_module_changed = (
1759
+ not is_new and not Module.objects.filter(pk=self.pk, parent_module_bay=self.parent_module_bay).exists()
1760
+ )
1761
+
1762
+ super().save(*args, **kwargs)
1763
+
1764
+ # If this is a new Module, instantiate all related components per the ModuleType definition
1765
+ if is_new:
1766
+ self.create_components()
1767
+
1768
+ # Render component names when this Module is first created or when the parent module bay has changed
1769
+ if is_new or parent_module_changed:
1770
+ self.render_component_names()
1771
+
1772
+ def create_components(self):
1773
+ """Create module components from the module type definition."""
1774
+ # The order of these is significant as
1775
+ # - PowerOutlet depends on PowerPort
1776
+ # - FrontPort depends on RearPort
1777
+ component_models = [
1778
+ (ConsolePort, self.module_type.console_port_templates.all()),
1779
+ (ConsoleServerPort, self.module_type.console_server_port_templates.all()),
1780
+ (PowerPort, self.module_type.power_port_templates.all()),
1781
+ (PowerOutlet, self.module_type.power_outlet_templates.all()),
1782
+ (Interface, self.module_type.interface_templates.all()),
1783
+ (RearPort, self.module_type.rear_port_templates.all()),
1784
+ (FrontPort, self.module_type.front_port_templates.all()),
1785
+ (ModuleBay, self.module_type.module_bay_templates.all()),
1786
+ ]
1787
+ instantiated_components = []
1788
+ for model, templates in component_models:
1789
+ model.objects.bulk_create([x.instantiate(device=None, module=self) for x in templates])
1790
+ return instantiated_components
1791
+
1792
+ def render_component_names(self):
1793
+ """
1794
+ Replace the {module}, {module.parent}, {module.parent.parent}, etc. template variables in descendant
1795
+ component names with the correct parent module bay positions.
1796
+ """
1797
+
1798
+ # disable sorting to improve performance, sorting isn't necessary here
1799
+ component_models = [
1800
+ self.console_ports.all().order_by(),
1801
+ self.console_server_ports.all().order_by(),
1802
+ self.power_ports.all().order_by(),
1803
+ self.power_outlets.all().order_by(),
1804
+ self.interfaces.all().order_by(),
1805
+ self.rear_ports.all().order_by(),
1806
+ self.front_ports.all().order_by(),
1807
+ ]
1808
+
1809
+ for component_qs in component_models:
1810
+ for component in component_qs.only("name", "module"):
1811
+ component.render_name_template(save=True)
1812
+
1813
+ for child in self.get_children():
1814
+ child.render_component_names()
1815
+
1816
+ def get_cables(self, pk_list=False):
1817
+ """
1818
+ Return a QuerySet or PK list matching all Cables connected to any component of this Module.
1819
+ """
1820
+ from .cables import Cable
1821
+
1822
+ cable_pks = []
1823
+ for component_model in [
1824
+ ConsolePort,
1825
+ ConsoleServerPort,
1826
+ PowerPort,
1827
+ PowerOutlet,
1828
+ Interface,
1829
+ FrontPort,
1830
+ RearPort,
1831
+ ]:
1832
+ cable_pks += component_model.objects.filter(module=self, cable__isnull=False).values_list(
1833
+ "cable", flat=True
1834
+ )
1835
+ if pk_list:
1836
+ return cable_pks
1837
+ return Cable.objects.filter(pk__in=cable_pks)
1838
+
1839
+ def get_children(self):
1840
+ """
1841
+ Return the set of child Modules installed in ModuleBays within this Module.
1842
+ """
1843
+ return Module.objects.filter(parent_module_bay__parent_module=self)
@@ -91,7 +91,6 @@ class RackGroup(TreeModel, OrganizationalModel):
91
91
  @extras_features(
92
92
  "custom_links",
93
93
  "custom_validators",
94
- "dynamic_groups",
95
94
  "export_templates",
96
95
  "graphql",
97
96
  "locations",
@@ -244,6 +244,44 @@ menu_items = (
244
244
  ),
245
245
  ),
246
246
  ),
247
+ NavMenuGroup(
248
+ name="Modules",
249
+ weight=250,
250
+ items=(
251
+ NavMenuItem(
252
+ link="dcim:module_list",
253
+ name="Modules",
254
+ weight=100,
255
+ permissions=[
256
+ "dcim.view_module",
257
+ ],
258
+ buttons=(
259
+ NavMenuAddButton(
260
+ link="dcim:module_add",
261
+ permissions=[
262
+ "dcim.add_module",
263
+ ],
264
+ ),
265
+ ),
266
+ ),
267
+ NavMenuItem(
268
+ link="dcim:moduletype_list",
269
+ name="Module Types",
270
+ weight=200,
271
+ permissions=[
272
+ "dcim.view_moduletype",
273
+ ],
274
+ buttons=(
275
+ NavMenuAddButton(
276
+ link="dcim:moduletype_add",
277
+ permissions=[
278
+ "dcim.add_moduletype",
279
+ ],
280
+ ),
281
+ ),
282
+ ),
283
+ ),
284
+ ),
247
285
  NavMenuGroup(
248
286
  name="Software",
249
287
  weight=300,
@@ -448,6 +486,15 @@ menu_items = (
448
486
  ],
449
487
  buttons=(),
450
488
  ),
489
+ NavMenuItem(
490
+ link="dcim:modulebay_list",
491
+ name="Module Bays",
492
+ weight=850,
493
+ permissions=[
494
+ "dcim.view_modulebay",
495
+ ],
496
+ buttons=(),
497
+ ),
451
498
  NavMenuItem(
452
499
  link="dcim:inventoryitem_list",
453
500
  name="Inventory Items",
nautobot/dcim/signals.py CHANGED
@@ -297,15 +297,15 @@ def prevent_adding_tagged_vlans_with_incorrect_mode_or_site(sender, instance, ac
297
297
  @receiver(post_save, sender=ControllerManagedDeviceGroup)
298
298
  def handle_controller_managed_device_group_controller_change(instance, raw=False, **_):
299
299
  """Update descendants when the top level `ControllerManagedDeviceGroup.controller` changes."""
300
- if instance.parent or instance._original_controller == instance.controller:
301
- return
302
-
303
300
  logger = logging.getLogger(__name__ + ".ControllerManagedDeviceGroup")
304
301
 
305
302
  if raw:
306
303
  logger.debug("Skipping controller update for imported controller device group %s", instance)
307
304
  return
308
305
 
306
+ if instance.parent or instance._original_controller == instance.controller:
307
+ return
308
+
309
309
  with transaction.atomic():
310
310
  for group in instance.descendants(include_self=False):
311
311
  group.controller = instance.controller