nautobot 2.2.9__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 (697) 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 +95 -13
  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/schema.py +26 -4
  61. nautobot/core/jobs/__init__.py +16 -2
  62. nautobot/core/jobs/cleanup.py +100 -0
  63. nautobot/core/jobs/groups.py +38 -0
  64. nautobot/core/management/commands/generate_test_data.py +116 -3
  65. nautobot/core/models/__init__.py +34 -9
  66. nautobot/core/models/generics.py +19 -3
  67. nautobot/core/models/name_color_content_types.py +7 -28
  68. nautobot/core/models/querysets.py +4 -3
  69. nautobot/core/models/tree_queries.py +1 -1
  70. nautobot/core/models/utils.py +21 -5
  71. nautobot/core/settings.py +2 -17
  72. nautobot/core/settings.yaml +34 -13
  73. nautobot/core/settings_funcs.py +103 -0
  74. nautobot/core/tables.py +130 -56
  75. nautobot/core/templates/admin/search_form.html +1 -1
  76. nautobot/core/templates/buttons/add.html +11 -3
  77. nautobot/core/templates/buttons/consolidated_bulk_action_buttons.html +13 -0
  78. nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +13 -0
  79. nautobot/core/templates/buttons/export.html +101 -53
  80. nautobot/core/templates/buttons/job_import.html +11 -3
  81. nautobot/core/templates/generic/object_bulk_destroy.html +3 -1
  82. nautobot/core/templates/generic/object_bulk_update.html +3 -1
  83. nautobot/core/templates/generic/object_changelog.html +0 -9
  84. nautobot/core/templates/generic/object_list.html +156 -17
  85. nautobot/core/templates/generic/object_retrieve.html +80 -16
  86. nautobot/core/templates/inc/extras_features_edit_form_fields.html +8 -0
  87. nautobot/core/templates/inc/javascript.html +2 -0
  88. nautobot/core/templates/inc/media.html +2 -2
  89. nautobot/core/templates/inc/nav_menu.html +1 -0
  90. nautobot/core/templates/inc/paginator.html +7 -7
  91. nautobot/core/templates/inc/search_panel.html +2 -2
  92. nautobot/core/templates/inc/table.html +2 -2
  93. nautobot/core/templates/nautobot_config.py.j2 +13 -8
  94. nautobot/core/templates/utilities/templatetags/dynamic_group_assignment_modal.html +37 -0
  95. nautobot/core/templates/utilities/templatetags/filter_form_modal.html +2 -2
  96. nautobot/core/templates/utilities/templatetags/saved_view_modal.html +38 -0
  97. nautobot/core/templates/utilities/theme_preview.html +25 -8
  98. nautobot/core/templates/utilities/worker_status.html +152 -0
  99. nautobot/core/templatetags/buttons.py +335 -38
  100. nautobot/core/templatetags/form_helpers.py +1 -1
  101. nautobot/core/templatetags/helpers.py +181 -11
  102. nautobot/core/testing/api.py +5 -4
  103. nautobot/core/testing/filters.py +63 -14
  104. nautobot/core/testing/mixins.py +46 -0
  105. nautobot/core/testing/models.py +22 -0
  106. nautobot/core/testing/schema.py +4 -8
  107. nautobot/core/testing/views.py +31 -14
  108. nautobot/core/tests/integration/test_import_objects_ui.py +1 -0
  109. nautobot/core/tests/integration/test_swagger.py +1 -1
  110. nautobot/core/tests/nautobot_config.py +0 -1
  111. nautobot/core/tests/runner.py +2 -2
  112. nautobot/core/tests/test_api.py +1 -0
  113. nautobot/core/tests/test_authentication.py +7 -2
  114. nautobot/core/tests/test_filters.py +11 -9
  115. nautobot/core/tests/test_forms.py +9 -0
  116. nautobot/core/tests/test_graphql.py +27 -16
  117. nautobot/core/tests/test_jobs.py +122 -0
  118. nautobot/core/tests/test_tables.py +3 -1
  119. nautobot/core/tests/test_templatetags_helpers.py +12 -5
  120. nautobot/core/tests/test_utils.py +31 -20
  121. nautobot/core/tests/test_views.py +6 -6
  122. nautobot/core/urls.py +8 -3
  123. nautobot/core/utils/deprecation.py +29 -0
  124. nautobot/core/utils/filtering.py +12 -9
  125. nautobot/core/utils/lookup.py +37 -2
  126. nautobot/core/utils/requests.py +4 -1
  127. nautobot/core/views/__init__.py +137 -24
  128. nautobot/core/views/generic.py +119 -67
  129. nautobot/core/views/mixins.py +105 -36
  130. nautobot/core/views/paginator.py +9 -3
  131. nautobot/core/views/renderers.py +121 -56
  132. nautobot/core/views/utils.py +81 -1
  133. nautobot/dcim/__init__.py +0 -1
  134. nautobot/dcim/api/serializers.py +180 -44
  135. nautobot/dcim/api/urls.py +7 -3
  136. nautobot/dcim/api/views.py +53 -7
  137. nautobot/dcim/apps.py +3 -0
  138. nautobot/dcim/choices.py +25 -0
  139. nautobot/dcim/constants.py +7 -0
  140. nautobot/dcim/factory.py +252 -18
  141. nautobot/dcim/filters/__init__.py +373 -193
  142. nautobot/dcim/filters/mixins.py +274 -1
  143. nautobot/dcim/forms.py +834 -121
  144. nautobot/dcim/graphql/types.py +2 -2
  145. nautobot/dcim/homepage.py +1 -1
  146. nautobot/dcim/migrations/0059_add_role_field_to_interface_models.py +27 -0
  147. nautobot/dcim/migrations/0060_alter_cable_status_alter_consoleport__path_and_more.py +303 -0
  148. nautobot/dcim/migrations/0061_module_models.py +862 -0
  149. nautobot/dcim/migrations/0062_module_data_migration.py +25 -0
  150. nautobot/dcim/models/__init__.py +8 -0
  151. nautobot/dcim/models/cables.py +15 -0
  152. nautobot/dcim/models/device_component_templates.py +207 -53
  153. nautobot/dcim/models/device_components.py +275 -99
  154. nautobot/dcim/models/devices.py +468 -13
  155. nautobot/dcim/models/racks.py +0 -1
  156. nautobot/dcim/navigation.py +47 -0
  157. nautobot/dcim/signals.py +3 -3
  158. nautobot/dcim/tables/__init__.py +35 -23
  159. nautobot/dcim/tables/devices.py +229 -43
  160. nautobot/dcim/tables/devicetypes.py +65 -9
  161. nautobot/dcim/tables/racks.py +5 -1
  162. nautobot/dcim/tables/template_code.py +46 -26
  163. nautobot/dcim/templates/dcim/cable_connect.html +76 -3
  164. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -5
  165. nautobot/dcim/templates/dcim/device/base.html +14 -6
  166. nautobot/dcim/templates/dcim/device/consoleports.html +2 -3
  167. nautobot/dcim/templates/dcim/device/consoleserverports.html +2 -3
  168. nautobot/dcim/templates/dcim/device/devicebays.html +6 -7
  169. nautobot/dcim/templates/dcim/device/frontports.html +2 -3
  170. nautobot/dcim/templates/dcim/device/interfaces.html +2 -3
  171. nautobot/dcim/templates/dcim/device/inventory.html +2 -3
  172. nautobot/dcim/templates/dcim/device/modulebays.html +49 -0
  173. nautobot/dcim/templates/dcim/device/poweroutlets.html +2 -3
  174. nautobot/dcim/templates/dcim/device/powerports.html +2 -3
  175. nautobot/dcim/templates/dcim/device/rearports.html +2 -3
  176. nautobot/dcim/templates/dcim/device.html +45 -1
  177. nautobot/dcim/templates/dcim/device_component.html +13 -5
  178. nautobot/dcim/templates/dcim/device_list.html +2 -1
  179. nautobot/dcim/templates/dcim/devicetype.html +99 -98
  180. nautobot/dcim/templates/dcim/devicetype_list.html +8 -16
  181. nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
  182. nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +39 -0
  183. nautobot/dcim/templates/dcim/interface.html +17 -2
  184. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -5
  185. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  186. nautobot/dcim/templates/dcim/manufacturer.html +24 -0
  187. nautobot/dcim/templates/dcim/module/base.html +97 -0
  188. nautobot/dcim/templates/dcim/module_bulk_destroy.html +5 -0
  189. nautobot/dcim/templates/dcim/module_consoleports.html +53 -0
  190. nautobot/dcim/templates/dcim/module_consoleserverports.html +53 -0
  191. nautobot/dcim/templates/dcim/module_destroy.html +5 -0
  192. nautobot/dcim/templates/dcim/module_frontports.html +53 -0
  193. nautobot/dcim/templates/dcim/module_interfaces.html +57 -0
  194. nautobot/dcim/templates/dcim/module_list.html +20 -0
  195. nautobot/dcim/templates/dcim/module_modulebays.html +49 -0
  196. nautobot/dcim/templates/dcim/module_poweroutlets.html +53 -0
  197. nautobot/dcim/templates/dcim/module_powerports.html +53 -0
  198. nautobot/dcim/templates/dcim/module_rearports.html +53 -0
  199. nautobot/dcim/templates/dcim/module_retrieve.html +63 -0
  200. nautobot/dcim/templates/dcim/module_update.html +71 -0
  201. nautobot/dcim/templates/dcim/modulebay_bulk_destroy.html +5 -0
  202. nautobot/dcim/templates/dcim/modulebay_destroy.html +8 -0
  203. nautobot/dcim/templates/dcim/modulebay_retrieve.html +101 -0
  204. nautobot/dcim/templates/dcim/moduletype_list.html +11 -0
  205. nautobot/dcim/templates/dcim/moduletype_retrieve.html +159 -0
  206. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -5
  207. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +65 -19
  208. nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
  209. nautobot/dcim/tests/test_api.py +693 -208
  210. nautobot/dcim/tests/test_filters.py +843 -217
  211. nautobot/dcim/tests/test_models.py +1072 -8
  212. nautobot/dcim/tests/test_views.py +1510 -341
  213. nautobot/dcim/urls.py +17 -2
  214. nautobot/dcim/utils.py +2 -3
  215. nautobot/dcim/views.py +1106 -116
  216. nautobot/extras/__init__.py +0 -1
  217. nautobot/extras/api/serializers.py +115 -3
  218. nautobot/extras/api/urls.py +12 -0
  219. nautobot/extras/api/views.py +66 -0
  220. nautobot/extras/apps.py +2 -2
  221. nautobot/extras/choices.py +43 -0
  222. nautobot/extras/context_managers.py +13 -8
  223. nautobot/extras/datasources/git.py +2 -0
  224. nautobot/extras/factory.py +460 -9
  225. nautobot/extras/filters/__init__.py +174 -3
  226. nautobot/extras/filters/mixins.py +46 -43
  227. nautobot/extras/forms/base.py +24 -5
  228. nautobot/extras/forms/forms.py +227 -8
  229. nautobot/extras/forms/mixins.py +93 -0
  230. nautobot/extras/graphql/types.py +23 -10
  231. nautobot/extras/homepage.py +14 -1
  232. nautobot/extras/management/__init__.py +1 -0
  233. nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +1 -16
  234. nautobot/extras/migrations/0021_customfield_changelog_data.py +1 -0
  235. nautobot/extras/migrations/0109_dynamicgroup_group_type_dynamicgroup_tags_and_more.py +108 -0
  236. nautobot/extras/migrations/0110_alter_configcontext_cluster_groups_and_more.py +111 -0
  237. nautobot/extras/migrations/0111_metadata.py +162 -0
  238. nautobot/extras/migrations/0112_dynamic_group_group_type_data_migration.py +28 -0
  239. nautobot/extras/migrations/0113_saved_views.py +77 -0
  240. nautobot/extras/models/__init__.py +15 -1
  241. nautobot/extras/models/change_logging.py +3 -3
  242. nautobot/extras/models/contacts.py +4 -0
  243. nautobot/extras/models/customfields.py +18 -3
  244. nautobot/extras/models/groups.py +389 -225
  245. nautobot/extras/models/jobs.py +6 -3
  246. nautobot/extras/models/metadata.py +441 -0
  247. nautobot/extras/models/mixins.py +72 -62
  248. nautobot/extras/models/models.py +118 -9
  249. nautobot/extras/models/relationships.py +9 -2
  250. nautobot/extras/models/tags.py +13 -2
  251. nautobot/extras/navigation.py +57 -0
  252. nautobot/extras/plugins/__init__.py +3 -1
  253. nautobot/extras/querysets.py +30 -66
  254. nautobot/extras/signals.py +95 -100
  255. nautobot/extras/tables.py +165 -12
  256. nautobot/extras/templates/extras/dynamicgroup.html +44 -15
  257. nautobot/extras/templates/extras/dynamicgroup_edit.html +2 -0
  258. nautobot/extras/templates/extras/job.html +1 -1
  259. nautobot/extras/templates/extras/jobresult.html +61 -74
  260. nautobot/extras/templates/extras/metadatatype_create.html +89 -0
  261. nautobot/extras/templates/extras/metadatatype_retrieve.html +67 -0
  262. nautobot/extras/templates/extras/object_dynamicgroups.html +7 -0
  263. nautobot/extras/templates/extras/objectchange_list.html +0 -12
  264. nautobot/extras/templates/extras/plugins_list.html +1 -3
  265. nautobot/extras/templates/extras/role_retrieve.html +48 -0
  266. nautobot/extras/templates/extras/staticgroupassociation_retrieve.html +20 -0
  267. nautobot/extras/tests/integration/test_customfields.py +1 -0
  268. nautobot/extras/tests/test_api.py +509 -23
  269. nautobot/extras/tests/test_changelog.py +20 -9
  270. nautobot/extras/tests/test_context_managers.py +22 -15
  271. nautobot/extras/tests/test_datasources.py +13 -1
  272. nautobot/extras/tests/test_dynamicgroups.py +201 -171
  273. nautobot/extras/tests/test_filters.py +211 -12
  274. nautobot/extras/tests/test_jobs.py +6 -6
  275. nautobot/extras/tests/test_models.py +501 -4
  276. nautobot/extras/tests/test_relationships.py +1 -0
  277. nautobot/extras/tests/test_views.py +565 -8
  278. nautobot/extras/tests/test_webhooks.py +1 -1
  279. nautobot/extras/urls.py +5 -0
  280. nautobot/extras/utils.py +51 -11
  281. nautobot/extras/views.py +542 -76
  282. nautobot/ipam/__init__.py +0 -1
  283. nautobot/ipam/apps.py +1 -0
  284. nautobot/ipam/factory.py +17 -19
  285. nautobot/ipam/filters.py +13 -0
  286. nautobot/ipam/forms.py +8 -4
  287. nautobot/ipam/graphql/types.py +2 -2
  288. nautobot/ipam/migrations/0047_alter_ipaddress_role_alter_ipaddress_status_and_more.py +59 -0
  289. nautobot/ipam/models.py +11 -8
  290. nautobot/ipam/querysets.py +1 -1
  291. nautobot/ipam/signals.py +4 -2
  292. nautobot/ipam/tables.py +5 -0
  293. nautobot/ipam/templates/ipam/ipaddress_interfaces.html +1 -1
  294. nautobot/ipam/templates/ipam/ipaddress_vm_interfaces.html +1 -1
  295. nautobot/ipam/templates/ipam/prefix.html +1 -0
  296. nautobot/ipam/tests/test_api.py +37 -18
  297. nautobot/ipam/tests/test_filters.py +26 -2
  298. nautobot/ipam/tests/test_models.py +6 -0
  299. nautobot/ipam/tests/test_querysets.py +1 -1
  300. nautobot/ipam/tests/test_views.py +3 -2
  301. nautobot/ipam/urls.py +2 -2
  302. nautobot/ipam/views.py +18 -26
  303. nautobot/project-static/css/base.css +20 -0
  304. nautobot/project-static/css/dark.css +11 -0
  305. nautobot/project-static/docs/404.html +892 -88
  306. nautobot/project-static/docs/apps/index.html +892 -88
  307. nautobot/project-static/docs/apps/nautobot-apps.html +892 -88
  308. nautobot/project-static/docs/assets/_mkdocstrings.css +5 -0
  309. nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css +1 -0
  310. nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css.map +1 -0
  311. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +919 -120
  312. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +904 -101
  313. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1618 -903
  314. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +935 -144
  315. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +977 -188
  316. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +901 -99
  317. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +897 -93
  318. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +991 -193
  319. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +974 -131
  320. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +1078 -272
  321. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1242 -334
  322. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1727 -875
  323. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +1164 -381
  324. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2088 -1374
  325. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2246 -1422
  326. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +912 -111
  327. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +963 -163
  328. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1010 -223
  329. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +1913 -1277
  330. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1846 -1102
  331. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +904 -101
  332. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +2331 -1699
  333. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +1802 -1024
  334. nautobot/project-static/docs/development/apps/api/configuration-view.html +892 -88
  335. nautobot/project-static/docs/development/apps/api/database-backend-config.html +892 -88
  336. nautobot/project-static/docs/development/apps/api/models/django-admin.html +892 -88
  337. nautobot/project-static/docs/development/apps/api/models/global-search.html +892 -88
  338. nautobot/project-static/docs/development/apps/api/models/graphql.html +892 -88
  339. nautobot/project-static/docs/development/apps/api/models/index.html +942 -90
  340. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +892 -88
  341. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +892 -88
  342. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +892 -88
  343. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +892 -88
  344. nautobot/project-static/docs/development/apps/api/platform-features/index.html +892 -88
  345. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +892 -88
  346. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +892 -88
  347. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +892 -88
  348. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +892 -88
  349. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +892 -88
  350. nautobot/project-static/docs/development/apps/api/prometheus.html +892 -88
  351. nautobot/project-static/docs/development/apps/api/setup.html +892 -88
  352. nautobot/project-static/docs/development/apps/api/testing.html +892 -88
  353. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +892 -88
  354. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +892 -88
  355. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +892 -88
  356. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +892 -88
  357. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +892 -88
  358. nautobot/project-static/docs/development/apps/api/views/base-template.html +892 -88
  359. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +892 -88
  360. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +892 -88
  361. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +892 -88
  362. nautobot/project-static/docs/development/apps/api/views/index.html +892 -88
  363. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +892 -88
  364. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +892 -88
  365. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +892 -88
  366. nautobot/project-static/docs/development/apps/api/views/notes.html +892 -88
  367. nautobot/project-static/docs/development/apps/api/views/rest-api.html +892 -88
  368. nautobot/project-static/docs/development/apps/api/views/urls.html +892 -88
  369. nautobot/project-static/docs/development/apps/index.html +892 -88
  370. nautobot/project-static/docs/development/apps/migration/code-updates.html +892 -88
  371. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +892 -88
  372. nautobot/project-static/docs/development/apps/migration/from-v1.html +892 -88
  373. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +892 -88
  374. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +892 -88
  375. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +892 -88
  376. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +892 -88
  377. nautobot/project-static/docs/development/apps/porting-from-netbox.html +892 -88
  378. nautobot/project-static/docs/development/core/application-registry.html +892 -88
  379. nautobot/project-static/docs/development/core/best-practices.html +893 -88
  380. nautobot/project-static/docs/development/core/bootstrap-ui.html +892 -88
  381. nautobot/project-static/docs/development/core/caching.html +892 -88
  382. nautobot/project-static/docs/development/core/controllers.html +892 -88
  383. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +892 -88
  384. nautobot/project-static/docs/development/core/generic-views.html +892 -88
  385. nautobot/project-static/docs/development/core/getting-started.html +892 -88
  386. nautobot/project-static/docs/development/core/homepage.html +892 -88
  387. nautobot/project-static/docs/development/core/index.html +892 -88
  388. nautobot/project-static/docs/development/core/model-checklist.html +901 -89
  389. nautobot/project-static/docs/development/core/model-features.html +892 -88
  390. nautobot/project-static/docs/development/core/natural-keys.html +892 -88
  391. nautobot/project-static/docs/development/core/navigation-menu.html +892 -88
  392. nautobot/project-static/docs/development/core/release-checklist.html +895 -91
  393. nautobot/project-static/docs/development/core/role-internals.html +892 -88
  394. nautobot/project-static/docs/development/core/settings.html +892 -88
  395. nautobot/project-static/docs/development/core/style-guide.html +893 -89
  396. nautobot/project-static/docs/development/core/templates.html +904 -89
  397. nautobot/project-static/docs/development/core/testing.html +892 -88
  398. nautobot/project-static/docs/development/core/user-preferences.html +892 -88
  399. nautobot/project-static/docs/development/index.html +892 -88
  400. nautobot/project-static/docs/development/jobs/index.html +893 -89
  401. nautobot/project-static/docs/development/jobs/migration/from-v1.html +892 -88
  402. nautobot/project-static/docs/index.html +892 -88
  403. nautobot/project-static/docs/media/models/cloud_aws_direct_connect_dark.png +0 -0
  404. nautobot/project-static/docs/media/models/cloud_aws_direct_connect_light.png +0 -0
  405. nautobot/project-static/docs/models/cloud/cloudaccount.html +15 -0
  406. nautobot/project-static/docs/models/cloud/cloudnetwork.html +15 -0
  407. nautobot/project-static/docs/models/cloud/cloudnetworkprefixassignment.html +15 -0
  408. nautobot/project-static/docs/models/cloud/cloudresourcetype.html +15 -0
  409. nautobot/project-static/docs/models/cloud/cloudservice.html +15 -0
  410. nautobot/project-static/docs/models/cloud/cloudservicenetworkassignment.html +15 -0
  411. nautobot/project-static/docs/models/dcim/module.html +15 -0
  412. nautobot/project-static/docs/models/dcim/modulebay.html +15 -0
  413. nautobot/project-static/docs/models/dcim/modulebaytemplate.html +15 -0
  414. nautobot/project-static/docs/models/dcim/moduletype.html +15 -0
  415. nautobot/project-static/docs/models/extras/metadatachoice.html +15 -0
  416. nautobot/project-static/docs/models/extras/metadatatype.html +15 -0
  417. nautobot/project-static/docs/models/extras/objectmetadata.html +15 -0
  418. nautobot/project-static/docs/models/extras/role.html +15 -0
  419. nautobot/project-static/docs/models/extras/savedview.html +15 -0
  420. nautobot/project-static/docs/models/extras/staticgroupassociation.html +15 -0
  421. nautobot/project-static/docs/models/extras/status.html +15 -0
  422. nautobot/project-static/docs/objects.inv +0 -0
  423. nautobot/project-static/docs/overview/application_stack.html +900 -89
  424. nautobot/project-static/docs/overview/design_philosophy.html +892 -88
  425. nautobot/project-static/docs/release-notes/index.html +1129 -92
  426. nautobot/project-static/docs/release-notes/version-1.0.html +892 -88
  427. nautobot/project-static/docs/release-notes/version-1.1.html +892 -88
  428. nautobot/project-static/docs/release-notes/version-1.2.html +892 -88
  429. nautobot/project-static/docs/release-notes/version-1.3.html +892 -88
  430. nautobot/project-static/docs/release-notes/version-1.4.html +892 -88
  431. nautobot/project-static/docs/release-notes/version-1.5.html +893 -89
  432. nautobot/project-static/docs/release-notes/version-1.6.html +893 -89
  433. nautobot/project-static/docs/release-notes/version-2.0.html +892 -88
  434. nautobot/project-static/docs/release-notes/version-2.1.html +892 -88
  435. nautobot/project-static/docs/release-notes/version-2.2.html +895 -91
  436. nautobot/project-static/docs/release-notes/version-2.3.html +9954 -0
  437. nautobot/project-static/docs/requirements.txt +5 -5
  438. nautobot/project-static/docs/search/search_index.json +1 -1
  439. nautobot/project-static/docs/sitemap.xml +331 -256
  440. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  441. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +892 -88
  442. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +892 -88
  443. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +892 -88
  444. nautobot/project-static/docs/user-guide/administration/configuration/index.html +892 -88
  445. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +992 -174
  446. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +892 -88
  447. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +892 -88
  448. nautobot/project-static/docs/user-guide/administration/guides/caching.html +892 -88
  449. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +896 -88
  450. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +892 -88
  451. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +892 -88
  452. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +892 -88
  453. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +892 -88
  454. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +892 -88
  455. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +892 -88
  456. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +892 -88
  457. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +892 -88
  458. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +944 -153
  459. nautobot/project-static/docs/user-guide/administration/installation/index.html +901 -93
  460. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +934 -122
  461. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +954 -157
  462. nautobot/project-static/docs/user-guide/administration/installation/services.html +913 -112
  463. nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +908 -99
  464. nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +892 -88
  465. nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +892 -88
  466. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +892 -88
  467. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +892 -88
  468. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +893 -89
  469. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +892 -88
  470. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +892 -88
  471. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +892 -88
  472. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +892 -88
  473. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +892 -88
  474. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +892 -88
  475. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +892 -88
  476. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +892 -88
  477. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +892 -88
  478. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +892 -88
  479. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +892 -88
  480. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +893 -89
  481. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +892 -88
  482. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +896 -88
  483. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +895 -91
  484. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +8984 -0
  485. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +8828 -0
  486. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +8829 -0
  487. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +8828 -0
  488. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +8829 -0
  489. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +8833 -0
  490. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +8828 -0
  491. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +906 -102
  492. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +923 -105
  493. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +923 -105
  494. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +918 -100
  495. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +923 -105
  496. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +906 -102
  497. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +906 -102
  498. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +913 -105
  499. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +920 -116
  500. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +921 -117
  501. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +918 -114
  502. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +906 -102
  503. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +914 -105
  504. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +926 -108
  505. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +936 -118
  506. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +928 -106
  507. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +906 -102
  508. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +937 -119
  509. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +928 -110
  510. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +918 -114
  511. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +921 -117
  512. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +923 -115
  513. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +8828 -0
  514. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +8846 -0
  515. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +8843 -0
  516. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +8823 -0
  517. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +916 -112
  518. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +906 -102
  519. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +940 -83
  520. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +924 -106
  521. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +906 -102
  522. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +943 -86
  523. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +921 -103
  524. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +929 -125
  525. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +918 -114
  526. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +906 -102
  527. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +922 -104
  528. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +924 -106
  529. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +906 -102
  530. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +906 -102
  531. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +906 -102
  532. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +936 -88
  533. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +892 -88
  534. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +897 -89
  535. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +897 -89
  536. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +892 -88
  537. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +892 -88
  538. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +892 -88
  539. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +892 -88
  540. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +892 -88
  541. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +892 -88
  542. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +892 -88
  543. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +892 -88
  544. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +892 -88
  545. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +892 -88
  546. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +901 -96
  547. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +892 -88
  548. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +892 -88
  549. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +892 -88
  550. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +892 -88
  551. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +892 -88
  552. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +897 -89
  553. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +892 -88
  554. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +892 -88
  555. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +892 -88
  556. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +892 -88
  557. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +892 -88
  558. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +892 -88
  559. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +892 -88
  560. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +892 -88
  561. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +892 -88
  562. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +892 -88
  563. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +892 -88
  564. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +892 -88
  565. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +892 -88
  566. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/clear-view-button.png +0 -0
  567. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/cleared-view.png +0 -0
  568. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/config-table-columns-to-locations.png +0 -0
  569. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/configure-button.png +0 -0
  570. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/create-saved-view-success.png +0 -0
  571. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/current-saved-view-drop-down-menu.png +0 -0
  572. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/default-location-list-view.png +0 -0
  573. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/dropdown-button-after-new-saved-view.png +0 -0
  574. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-application-to-locations.png +0 -0
  575. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-button.png +0 -0
  576. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/global-default-location-list-view.png +0 -0
  577. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/location-list-view-with-saved-views.png +0 -0
  578. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/navigation-menu.png +0 -0
  579. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-as-new-view-drop-down.png +0 -0
  580. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-view-modal.png +0 -0
  581. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-buttons.png +0 -0
  582. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-success.png +0 -0
  583. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view-unchecked.png +0 -0
  584. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view.png +0 -0
  585. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-different-user.png +0 -0
  586. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-modal-unchecked.png +0 -0
  587. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-button.png +0 -0
  588. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-success.png +0 -0
  589. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/unsaved-saved-view.png +0 -0
  590. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/updated-saved-view.png +0 -0
  591. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +892 -88
  592. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +892 -88
  593. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +892 -88
  594. nautobot/project-static/docs/user-guide/index.html +892 -88
  595. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +892 -88
  596. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +892 -88
  597. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +892 -88
  598. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +892 -88
  599. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +1258 -785
  600. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +895 -91
  601. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +892 -88
  602. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +892 -88
  603. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +892 -88
  604. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +892 -88
  605. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +892 -88
  606. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +892 -88
  607. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +892 -88
  608. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +892 -88
  609. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +892 -88
  610. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +896 -88
  611. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +892 -88
  612. nautobot/project-static/docs/user-guide/platform-functionality/note.html +895 -91
  613. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +9061 -0
  614. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +895 -91
  615. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +892 -88
  616. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +892 -88
  617. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +892 -88
  618. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +892 -88
  619. nautobot/project-static/docs/user-guide/platform-functionality/role.html +895 -91
  620. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +9137 -0
  621. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +895 -91
  622. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +8933 -0
  623. nautobot/project-static/docs/user-guide/platform-functionality/status.html +892 -88
  624. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +892 -88
  625. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +950 -121
  626. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +892 -88
  627. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +892 -88
  628. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +892 -88
  629. nautobot/project-static/js/forms.js +71 -0
  630. nautobot/project-static/js/table_sorting_indicator.js +46 -0
  631. nautobot/project-static/js/tableconfig.js +6 -1
  632. nautobot/project-static/materialdesignicons-7.4.47/css/materialdesignicons.min.css +3 -0
  633. nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.eot +0 -0
  634. nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.ttf +0 -0
  635. nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff +0 -0
  636. nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff2 +0 -0
  637. nautobot/tenancy/__init__.py +0 -1
  638. nautobot/tenancy/apps.py +1 -0
  639. nautobot/tenancy/factory.py +3 -2
  640. nautobot/tenancy/filters/__init__.py +1 -0
  641. nautobot/tenancy/forms.py +1 -1
  642. nautobot/tenancy/templates/tenancy/tenant.html +24 -20
  643. nautobot/tenancy/views.py +11 -10
  644. nautobot/users/__init__.py +0 -1
  645. nautobot/users/api/serializers.py +1 -1
  646. nautobot/users/api/views.py +4 -2
  647. nautobot/users/apps.py +3 -2
  648. nautobot/users/factory.py +3 -3
  649. nautobot/users/migrations/0010_user_default_saved_views.py +20 -0
  650. nautobot/users/models.py +12 -0
  651. nautobot/users/tests/test_filters.py +6 -3
  652. nautobot/users/urls.py +8 -0
  653. nautobot/virtualization/__init__.py +0 -1
  654. nautobot/virtualization/apps.py +1 -0
  655. nautobot/virtualization/filters.py +6 -1
  656. nautobot/virtualization/forms.py +11 -3
  657. nautobot/virtualization/graphql/types.py +2 -2
  658. nautobot/virtualization/migrations/0029_add_role_field_to_interface_models.py +27 -0
  659. nautobot/virtualization/migrations/0030_alter_virtualmachine_local_config_context_data_owner_content_type_and_more.py +67 -0
  660. nautobot/virtualization/models.py +0 -2
  661. nautobot/virtualization/tables.py +10 -3
  662. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
  663. nautobot/virtualization/templates/virtualization/vminterface.html +7 -1
  664. nautobot/virtualization/templates/virtualization/vminterface_edit.html +1 -0
  665. nautobot/virtualization/tests/test_api.py +9 -4
  666. nautobot/virtualization/tests/test_filters.py +22 -0
  667. nautobot/virtualization/tests/test_models.py +7 -3
  668. nautobot/virtualization/tests/test_views.py +19 -3
  669. nautobot/virtualization/urls.py +2 -2
  670. nautobot/virtualization/views.py +10 -32
  671. {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/METADATA +20 -18
  672. {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/RECORD +677 -557
  673. nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css +0 -1
  674. nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css.map +0 -1
  675. nautobot/project-static/materialdesignicons-6.5.95/.github/ISSUE_TEMPLATE.md +0 -3
  676. nautobot/project-static/materialdesignicons-6.5.95/README.md +0 -25
  677. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css +0 -26654
  678. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css.map +0 -16
  679. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css +0 -3
  680. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css.map +0 -16
  681. nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff +0 -0
  682. nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff2 +0 -0
  683. nautobot/project-static/materialdesignicons-6.5.95/package.json +0 -28
  684. nautobot/project-static/materialdesignicons-6.5.95/preview.html +0 -717
  685. nautobot/project-static/materialdesignicons-6.5.95/scss/_animated.scss +0 -27
  686. nautobot/project-static/materialdesignicons-6.5.95/scss/_core.scss +0 -10
  687. nautobot/project-static/materialdesignicons-6.5.95/scss/_extras.scss +0 -65
  688. nautobot/project-static/materialdesignicons-6.5.95/scss/_functions.scss +0 -20
  689. nautobot/project-static/materialdesignicons-6.5.95/scss/_icons.scss +0 -10
  690. nautobot/project-static/materialdesignicons-6.5.95/scss/_path.scss +0 -10
  691. nautobot/project-static/materialdesignicons-6.5.95/scss/_variables.scss +0 -6606
  692. nautobot/project-static/materialdesignicons-6.5.95/scss/materialdesignicons.scss +0 -8
  693. /nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/LICENSE +0 -0
  694. {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/LICENSE.txt +0 -0
  695. {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/NOTICE +0 -0
  696. {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/WHEEL +0 -0
  697. {nautobot-2.2.9.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",
@@ -1251,7 +1339,6 @@ class SoftwareVersion(PrimaryModel):
1251
1339
  @extras_features(
1252
1340
  "custom_links",
1253
1341
  "custom_validators",
1254
- "dynamic_groups",
1255
1342
  "export_templates",
1256
1343
  "graphql",
1257
1344
  "locations",
@@ -1335,7 +1422,6 @@ class Controller(PrimaryModel):
1335
1422
  @extras_features(
1336
1423
  "custom_links",
1337
1424
  "custom_validators",
1338
- "dynamic_groups",
1339
1425
  "export_templates",
1340
1426
  "graphql",
1341
1427
  "webhooks",
@@ -1386,3 +1472,372 @@ class ControllerManagedDeviceGroup(TreeModel, PrimaryModel):
1386
1472
  raise ValidationError(
1387
1473
  {"controller": "Controller device group must have the same controller as the parent group."}
1388
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