nautobot 2.2.0b1__py3-none-any.whl → 2.2.2__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 (429) hide show
  1. nautobot/__init__.py +31 -0
  2. nautobot/apps/api.py +1 -2
  3. nautobot/apps/utils.py +4 -0
  4. nautobot/apps/views.py +2 -0
  5. nautobot/circuits/api/urls.py +1 -2
  6. nautobot/circuits/api/views.py +0 -12
  7. nautobot/circuits/apps.py +1 -1
  8. nautobot/circuits/tests/test_filters.py +1 -1
  9. nautobot/core/api/routers.py +50 -3
  10. nautobot/core/api/utils.py +4 -0
  11. nautobot/core/api/views.py +21 -15
  12. nautobot/core/cli/__init__.py +18 -11
  13. nautobot/core/constants.py +85 -0
  14. nautobot/core/filters.py +7 -1
  15. nautobot/core/forms/widgets.py +1 -2
  16. nautobot/core/graphql/schema.py +1 -0
  17. nautobot/core/management/commands/generate_test_data.py +4 -4
  18. nautobot/core/models/__init__.py +1 -0
  19. nautobot/core/settings.py +24 -3
  20. nautobot/core/settings.yaml +20 -0
  21. nautobot/core/signals.py +1 -0
  22. nautobot/core/tables.py +2 -1
  23. nautobot/core/templates/admin/base.html +23 -94
  24. nautobot/core/templates/generic/object_retrieve.html +2 -2
  25. nautobot/core/templates/graphene/graphiql.html +18 -47
  26. nautobot/core/templates/inc/footer.html +5 -5
  27. nautobot/core/templates/inc/javascript.html +4 -4
  28. nautobot/core/templates/inc/media.html +2 -2
  29. nautobot/core/templates/inc/nav_menu.html +0 -7
  30. nautobot/core/templates/nautobot_config.py.j2 +14 -1
  31. nautobot/core/templates/rest_framework/api.html +12 -5
  32. nautobot/core/templatetags/helpers.py +2 -2
  33. nautobot/core/testing/__init__.py +1 -1
  34. nautobot/core/testing/filters.py +1 -1
  35. nautobot/core/testing/views.py +30 -0
  36. nautobot/core/tests/integration/test_view_authentication.py +68 -0
  37. nautobot/core/tests/test_api.py +13 -6
  38. nautobot/core/tests/test_csv.py +5 -4
  39. nautobot/core/tests/test_filters.py +2 -1
  40. nautobot/core/tests/test_graphql.py +4 -14
  41. nautobot/core/tests/test_navigations.py +3 -0
  42. nautobot/core/tests/test_views.py +45 -16
  43. nautobot/core/utils/data.py +1 -2
  44. nautobot/core/utils/lookup.py +126 -0
  45. nautobot/core/views/__init__.py +3 -7
  46. nautobot/core/views/generic.py +24 -10
  47. nautobot/core/views/mixins.py +11 -4
  48. nautobot/core/views/renderers.py +11 -6
  49. nautobot/core/wsgi.py +9 -2
  50. nautobot/dcim/api/serializers.py +4 -4
  51. nautobot/dcim/api/urls.py +2 -3
  52. nautobot/dcim/api/views.py +7 -18
  53. nautobot/dcim/apps.py +8 -4
  54. nautobot/dcim/elevations.py +5 -1
  55. nautobot/dcim/factory.py +7 -7
  56. nautobot/dcim/filters/__init__.py +16 -17
  57. nautobot/dcim/forms.py +69 -48
  58. nautobot/dcim/homepage.py +11 -3
  59. nautobot/dcim/management/commands/migrate_location_contacts.py +218 -0
  60. nautobot/dcim/migrations/0057_controller_models.py +11 -70
  61. nautobot/dcim/models/__init__.py +2 -2
  62. nautobot/dcim/models/devices.py +14 -16
  63. nautobot/dcim/models/racks.py +1 -3
  64. nautobot/dcim/navigation.py +23 -31
  65. nautobot/dcim/signals.py +6 -6
  66. nautobot/dcim/tables/__init__.py +2 -2
  67. nautobot/dcim/tables/devices.py +13 -16
  68. nautobot/dcim/tables/template_code.py +1 -1
  69. nautobot/dcim/templates/dcim/controller_create.html +70 -0
  70. nautobot/dcim/templates/dcim/controller_retrieve.html +35 -18
  71. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +88 -0
  72. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +74 -42
  73. nautobot/dcim/templates/dcim/device.html +11 -3
  74. nautobot/dcim/templates/dcim/device_edit.html +1 -1
  75. nautobot/dcim/templates/dcim/devicefamily_retrieve.html +4 -0
  76. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +1 -1
  77. nautobot/dcim/tests/test_api.py +47 -6
  78. nautobot/dcim/tests/test_filters.py +92 -81
  79. nautobot/dcim/tests/test_forms.py +49 -2
  80. nautobot/dcim/tests/test_graphql.py +11 -1
  81. nautobot/dcim/tests/test_models.py +15 -15
  82. nautobot/dcim/tests/test_signals.py +3 -1
  83. nautobot/dcim/tests/test_views.py +24 -12
  84. nautobot/dcim/urls.py +1 -1
  85. nautobot/dcim/views.py +25 -15
  86. nautobot/extras/api/serializers.py +20 -1
  87. nautobot/extras/api/urls.py +1 -2
  88. nautobot/extras/api/views.py +0 -10
  89. nautobot/extras/apps.py +7 -0
  90. nautobot/extras/context_managers.py +71 -4
  91. nautobot/extras/filters/__init__.py +53 -2
  92. nautobot/extras/filters/customfields.py +14 -9
  93. nautobot/extras/filters/mixins.py +6 -1
  94. nautobot/extras/forms/contacts.py +7 -0
  95. nautobot/extras/health_checks.py +1 -0
  96. nautobot/extras/jobs.py +1 -0
  97. nautobot/extras/managers.py +15 -2
  98. nautobot/extras/models/contacts.py +1 -0
  99. nautobot/extras/models/customfields.py +25 -2
  100. nautobot/extras/models/datasources.py +1 -0
  101. nautobot/extras/models/mixins.py +1 -0
  102. nautobot/extras/navigation.py +71 -65
  103. nautobot/extras/plugins/__init__.py +2 -1
  104. nautobot/extras/plugins/views.py +7 -11
  105. nautobot/extras/querysets.py +1 -2
  106. nautobot/extras/secrets/providers.py +1 -0
  107. nautobot/extras/signals.py +95 -51
  108. nautobot/extras/tasks.py +70 -17
  109. nautobot/extras/tests/test_api.py +2 -4
  110. nautobot/extras/tests/test_context_managers.py +98 -1
  111. nautobot/extras/tests/test_customfields.py +72 -9
  112. nautobot/extras/tests/test_dynamicgroups.py +2 -0
  113. nautobot/extras/tests/test_filters.py +89 -4
  114. nautobot/extras/tests/test_models.py +9 -0
  115. nautobot/extras/tests/test_relationships.py +10 -1
  116. nautobot/extras/tests/test_views.py +112 -1
  117. nautobot/extras/utils.py +37 -0
  118. nautobot/extras/views.py +18 -17
  119. nautobot/ipam/api/serializers.py +10 -0
  120. nautobot/ipam/api/urls.py +1 -2
  121. nautobot/ipam/api/views.py +0 -11
  122. nautobot/ipam/apps.py +3 -2
  123. nautobot/ipam/tables.py +3 -23
  124. nautobot/ipam/tests/test_graphql.py +2 -3
  125. nautobot/ipam/tests/test_tables.py +42 -0
  126. nautobot/ipam/tests/test_views.py +1 -0
  127. nautobot/ipam/views.py +9 -9
  128. nautobot/project-static/css/base.css +1 -0
  129. nautobot/project-static/docs/404.html +126 -73
  130. nautobot/project-static/docs/apps/index.html +127 -71
  131. nautobot/project-static/docs/apps/nautobot-apps.html +127 -71
  132. nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js → bundle.bd41221c.min.js} +2 -2
  133. nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js.map → bundle.bd41221c.min.js.map} +3 -3
  134. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +1 -0
  135. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +1 -0
  136. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +127 -71
  137. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +127 -71
  138. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +167 -73
  139. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +165 -72
  140. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +127 -71
  141. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +127 -71
  142. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +127 -71
  143. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +127 -71
  144. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +127 -71
  145. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +127 -71
  146. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +127 -71
  147. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +127 -71
  148. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +127 -71
  149. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +127 -71
  150. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +127 -71
  151. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +127 -71
  152. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +127 -71
  153. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +127 -71
  154. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +128 -72
  155. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +127 -71
  156. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +127 -71
  157. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +345 -71
  158. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +172 -73
  159. nautobot/project-static/docs/development/apps/api/configuration-view.html +127 -71
  160. nautobot/project-static/docs/development/apps/api/database-backend-config.html +127 -71
  161. nautobot/project-static/docs/development/apps/api/models/django-admin.html +127 -71
  162. nautobot/project-static/docs/development/apps/api/models/global-search.html +127 -71
  163. nautobot/project-static/docs/development/apps/api/models/graphql.html +127 -71
  164. nautobot/project-static/docs/development/apps/api/models/index.html +127 -71
  165. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +127 -71
  166. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +127 -71
  167. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +127 -71
  168. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +127 -71
  169. nautobot/project-static/docs/development/apps/api/platform-features/index.html +127 -71
  170. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +127 -71
  171. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +127 -71
  172. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +127 -71
  173. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +127 -71
  174. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +127 -71
  175. nautobot/project-static/docs/development/apps/api/prometheus.html +127 -71
  176. nautobot/project-static/docs/development/apps/api/setup.html +127 -71
  177. nautobot/project-static/docs/development/apps/api/testing.html +127 -71
  178. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +127 -71
  179. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +127 -71
  180. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +127 -71
  181. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +127 -71
  182. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +127 -71
  183. nautobot/project-static/docs/development/apps/api/views/base-template.html +127 -71
  184. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +141 -80
  185. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +144 -83
  186. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +127 -71
  187. nautobot/project-static/docs/development/apps/api/views/index.html +127 -71
  188. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +127 -71
  189. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +127 -71
  190. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +127 -71
  191. nautobot/project-static/docs/development/apps/api/views/notes.html +127 -71
  192. nautobot/project-static/docs/development/apps/api/views/rest-api.html +127 -71
  193. nautobot/project-static/docs/development/apps/api/views/urls.html +127 -71
  194. nautobot/project-static/docs/development/apps/index.html +127 -71
  195. nautobot/project-static/docs/development/apps/migration/code-updates.html +127 -71
  196. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +127 -71
  197. nautobot/project-static/docs/development/apps/migration/from-v1.html +127 -71
  198. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +127 -71
  199. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +127 -71
  200. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +127 -71
  201. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +127 -71
  202. nautobot/project-static/docs/development/apps/porting-from-netbox.html +127 -71
  203. nautobot/project-static/docs/development/core/application-registry.html +127 -71
  204. nautobot/project-static/docs/development/core/best-practices.html +145 -79
  205. nautobot/project-static/docs/development/core/bootstrap-ui.html +127 -71
  206. nautobot/project-static/docs/development/core/caching.html +127 -71
  207. nautobot/project-static/docs/development/core/controllers.html +141 -275
  208. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +127 -71
  209. nautobot/project-static/docs/development/core/extending-models.html +13 -8166
  210. nautobot/project-static/docs/development/core/generic-views.html +142 -86
  211. nautobot/project-static/docs/development/core/getting-started.html +146 -81
  212. nautobot/project-static/docs/development/core/homepage.html +145 -89
  213. nautobot/project-static/docs/development/core/index.html +127 -71
  214. nautobot/project-static/docs/development/core/model-checklist.html +8354 -0
  215. nautobot/project-static/docs/development/core/model-features.html +130 -74
  216. nautobot/project-static/docs/development/core/natural-keys.html +127 -71
  217. nautobot/project-static/docs/development/core/navigation-menu.html +127 -71
  218. nautobot/project-static/docs/development/core/release-checklist.html +127 -71
  219. nautobot/project-static/docs/development/core/role-internals.html +127 -71
  220. nautobot/project-static/docs/development/core/settings.html +127 -71
  221. nautobot/project-static/docs/development/core/style-guide.html +127 -71
  222. nautobot/project-static/docs/development/core/templates.html +127 -71
  223. nautobot/project-static/docs/development/core/testing.html +127 -71
  224. nautobot/project-static/docs/development/core/user-preferences.html +127 -71
  225. nautobot/project-static/docs/development/extending-models.html +3 -3
  226. nautobot/project-static/docs/development/index.html +127 -71
  227. nautobot/project-static/docs/development/jobs/index.html +128 -72
  228. nautobot/project-static/docs/development/jobs/migration/from-v1.html +127 -71
  229. nautobot/project-static/docs/index.html +126 -73
  230. nautobot/project-static/docs/models/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +3 -3
  231. nautobot/project-static/docs/objects.inv +0 -0
  232. nautobot/project-static/docs/release-notes/index.html +127 -71
  233. nautobot/project-static/docs/release-notes/version-1.0.html +127 -71
  234. nautobot/project-static/docs/release-notes/version-1.1.html +127 -71
  235. nautobot/project-static/docs/release-notes/version-1.2.html +127 -71
  236. nautobot/project-static/docs/release-notes/version-1.3.html +127 -71
  237. nautobot/project-static/docs/release-notes/version-1.4.html +127 -71
  238. nautobot/project-static/docs/release-notes/version-1.5.html +127 -71
  239. nautobot/project-static/docs/release-notes/version-1.6.html +663 -304
  240. nautobot/project-static/docs/release-notes/version-2.0.html +127 -71
  241. nautobot/project-static/docs/release-notes/version-2.1.html +538 -254
  242. nautobot/project-static/docs/release-notes/version-2.2.html +711 -125
  243. nautobot/project-static/docs/requirements.txt +3 -3
  244. nautobot/project-static/docs/search/search_index.json +1 -1
  245. nautobot/project-static/docs/sitemap.xml +264 -259
  246. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  247. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +127 -71
  248. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +127 -71
  249. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +127 -71
  250. nautobot/project-static/docs/user-guide/administration/configuration/index.html +127 -71
  251. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +192 -71
  252. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +127 -71
  253. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +127 -71
  254. nautobot/project-static/docs/user-guide/administration/guides/caching.html +127 -71
  255. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +127 -71
  256. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +127 -71
  257. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +127 -71
  258. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +131 -71
  259. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +127 -71
  260. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +127 -71
  261. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +130 -74
  262. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +127 -71
  263. nautobot/project-static/docs/user-guide/administration/installation/docker.html +134 -74
  264. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +127 -71
  265. nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +8616 -0
  266. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +127 -71
  267. nautobot/project-static/docs/user-guide/administration/installation/index.html +127 -71
  268. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +127 -71
  269. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +127 -71
  270. nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +130 -74
  271. nautobot/project-static/docs/user-guide/administration/installation/services.html +127 -71
  272. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +127 -71
  273. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +127 -71
  274. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +127 -71
  275. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +127 -71
  276. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +127 -71
  277. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +127 -71
  278. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +127 -71
  279. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +127 -71
  280. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +127 -71
  281. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +127 -71
  282. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +127 -71
  283. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +127 -71
  284. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +127 -71
  285. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +127 -71
  286. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +127 -71
  287. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +127 -71
  288. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +127 -71
  289. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +127 -71
  290. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +127 -71
  291. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +127 -71
  292. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +127 -71
  293. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +127 -71
  294. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +127 -71
  295. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +362 -79
  296. nautobot/project-static/docs/user-guide/core-data-model/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +210 -85
  297. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +127 -71
  298. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +127 -71
  299. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +127 -71
  300. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +127 -71
  301. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +127 -71
  302. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +127 -71
  303. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +127 -71
  304. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +127 -71
  305. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +127 -71
  306. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +127 -71
  307. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +127 -71
  308. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +127 -71
  309. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +127 -71
  310. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +127 -71
  311. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +127 -71
  312. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +127 -71
  313. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +127 -71
  314. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +127 -71
  315. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +127 -71
  316. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +127 -71
  317. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +127 -71
  318. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +127 -71
  319. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +127 -71
  320. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +127 -71
  321. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +127 -71
  322. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +127 -71
  323. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +127 -71
  324. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +127 -71
  325. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +127 -71
  326. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +127 -71
  327. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +130 -74
  328. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +127 -71
  329. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +138 -71
  330. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +138 -71
  331. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +127 -71
  332. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +127 -71
  333. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +127 -71
  334. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +127 -71
  335. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +127 -71
  336. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +127 -71
  337. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +127 -71
  338. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +127 -71
  339. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +127 -71
  340. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +127 -71
  341. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +127 -71
  342. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +127 -71
  343. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +127 -71
  344. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +127 -71
  345. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +127 -71
  346. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +127 -71
  347. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +127 -71
  348. nautobot/project-static/docs/user-guide/feature-guides/{contact-and-team.html → contacts-and-teams.html} +128 -72
  349. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +129 -73
  350. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +127 -71
  351. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +127 -71
  352. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +127 -71
  353. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +127 -71
  354. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +127 -71
  355. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +127 -71
  356. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +129 -73
  357. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +127 -71
  358. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +127 -71
  359. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +127 -71
  360. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +127 -71
  361. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +127 -71
  362. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +127 -71
  363. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +127 -71
  364. nautobot/project-static/docs/user-guide/index.html +127 -71
  365. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +127 -71
  366. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +127 -71
  367. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +127 -71
  368. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +127 -71
  369. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +127 -71
  370. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +127 -71
  371. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +127 -71
  372. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +127 -71
  373. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +127 -71
  374. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +127 -71
  375. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +127 -71
  376. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +127 -71
  377. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +127 -71
  378. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +127 -71
  379. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +127 -71
  380. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +127 -71
  381. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +127 -71
  382. nautobot/project-static/docs/user-guide/platform-functionality/note.html +127 -71
  383. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +127 -71
  384. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +127 -71
  385. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +127 -71
  386. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +127 -71
  387. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +127 -71
  388. nautobot/project-static/docs/user-guide/platform-functionality/role.html +127 -71
  389. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +127 -71
  390. nautobot/project-static/docs/user-guide/platform-functionality/status.html +127 -71
  391. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +127 -71
  392. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +127 -71
  393. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +127 -71
  394. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +127 -71
  395. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +127 -71
  396. nautobot/project-static/jquery/jquery-3.7.1.min.js +2 -0
  397. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_444444_256x240.png +0 -0
  398. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_555555_256x240.png +0 -0
  399. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777620_256x240.png +0 -0
  400. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777777_256x240.png +0 -0
  401. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_cc0000_256x240.png +0 -0
  402. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_ffffff_256x240.png +0 -0
  403. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.css +7 -0
  404. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.js +6 -0
  405. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.structure.min.css +5 -0
  406. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/jquery-ui.theme.min.css +1 -1
  407. nautobot/tenancy/api/urls.py +1 -2
  408. nautobot/tenancy/api/views.py +0 -12
  409. nautobot/tenancy/tables.py +1 -1
  410. nautobot/tenancy/tests/test_views.py +1 -0
  411. nautobot/users/api/urls.py +1 -2
  412. nautobot/users/api/views.py +2 -65
  413. nautobot/users/views.py +8 -8
  414. nautobot/virtualization/api/urls.py +1 -2
  415. nautobot/virtualization/api/views.py +0 -12
  416. {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/METADATA +24 -24
  417. {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/RECORD +422 -416
  418. nautobot/dcim/templates/dcim/controllerdevicegroup_create.html +0 -43
  419. nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css +0 -1
  420. nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css.map +0 -1
  421. nautobot/project-static/jquery/jquery-3.6.0.min.js +0 -2
  422. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.css +0 -7
  423. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.js +0 -6
  424. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.structure.min.css +0 -5
  425. /nautobot/dcim/templates/dcim/{controllerdevicegroup_retrieve.html → controllermanageddevicegroup_retrieve.html} +0 -0
  426. {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/LICENSE.txt +0 -0
  427. {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/NOTICE +0 -0
  428. {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/WHEEL +0 -0
  429. {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/entry_points.txt +0 -0
nautobot/core/wsgi.py CHANGED
@@ -1,11 +1,18 @@
1
1
  import logging
2
- import os
3
2
 
4
3
  from django.core import cache
5
4
  from django.core.wsgi import get_wsgi_application
6
5
  from django.db import connections
7
6
 
8
- os.environ["DJANGO_SETTINGS_MODULE"] = "nautobot_config"
7
+ import nautobot
8
+
9
+ # This is the Django default left here for visibility on how the Nautobot pattern
10
+ # differs.
11
+ # os.environ.setdefault("DJANGO_SETTINGS_MODULE", "nautobot.core.settings")
12
+
13
+ # Instead of just pointing to `DJANGO_SETTINGS_MODULE` and letting Django run with it,
14
+ # we're using the custom Nautobot loader code to read environment or config path for us.
15
+ nautobot.setup()
9
16
 
10
17
  # Use try/except because we might not be running uWSGI. If `settings.WEBSERVER_WARMUP` is `True`,
11
18
  # will first call `get_internal_wsgi_application` which does not have `uwsgi` module loaded
@@ -55,7 +55,7 @@ from nautobot.dcim.models import (
55
55
  ConsoleServerPort,
56
56
  ConsoleServerPortTemplate,
57
57
  Controller,
58
- ControllerDeviceGroup,
58
+ ControllerManagedDeviceGroup,
59
59
  Device,
60
60
  DeviceBay,
61
61
  DeviceBayTemplate,
@@ -598,7 +598,7 @@ class DeviceSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
598
598
  "secrets_group",
599
599
  "device_redundancy_group",
600
600
  "device_redundancy_group_priority",
601
- "controller_device_group",
601
+ "controller_managed_device_group",
602
602
  ]
603
603
  },
604
604
  },
@@ -1049,7 +1049,7 @@ class ControllerSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
1049
1049
  fields = "__all__"
1050
1050
 
1051
1051
 
1052
- class ControllerDeviceGroupSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
1052
+ class ControllerManagedDeviceGroupSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
1053
1053
  class Meta:
1054
- model = ControllerDeviceGroup
1054
+ model = ControllerManagedDeviceGroup
1055
1055
  fields = "__all__"
nautobot/dcim/api/urls.py CHANGED
@@ -2,8 +2,7 @@ from nautobot.core.api.routers import OrderedDefaultRouter
2
2
 
3
3
  from . import views
4
4
 
5
- router = OrderedDefaultRouter()
6
- router.APIRootView = views.DCIMRootView
5
+ router = OrderedDefaultRouter(view_name="DCIM")
7
6
 
8
7
  # Locations
9
8
  router.register("location-types", views.LocationTypeViewSet)
@@ -80,7 +79,7 @@ router.register("connected-device", views.ConnectedDeviceViewSet, basename="conn
80
79
 
81
80
  # Controllers
82
81
  router.register("controllers", views.ControllerViewSet)
83
- router.register("controller-device-groups", views.ControllerDeviceGroupViewSet)
82
+ router.register("controller-managed-device-groups", views.ControllerManagedDeviceGroupViewSet)
84
83
 
85
84
  app_name = "dcim-api"
86
85
  urlpatterns = router.urls
@@ -13,7 +13,6 @@ from rest_framework.decorators import action
13
13
  from rest_framework.mixins import ListModelMixin
14
14
  from rest_framework.permissions import IsAuthenticated
15
15
  from rest_framework.response import Response
16
- from rest_framework.routers import APIRootView
17
16
  from rest_framework.viewsets import GenericViewSet, ViewSet
18
17
 
19
18
  from nautobot.circuits.models import Circuit
@@ -30,7 +29,7 @@ from nautobot.dcim.models import (
30
29
  ConsoleServerPort,
31
30
  ConsoleServerPortTemplate,
32
31
  Controller,
33
- ControllerDeviceGroup,
32
+ ControllerManagedDeviceGroup,
34
33
  Device,
35
34
  DeviceBay,
36
35
  DeviceBayTemplate,
@@ -76,16 +75,6 @@ from nautobot.virtualization.models import VirtualMachine
76
75
  from . import serializers
77
76
  from .exceptions import MissingFilterException
78
77
 
79
-
80
- class DCIMRootView(APIRootView):
81
- """
82
- DCIM API root view
83
- """
84
-
85
- def get_view_name(self):
86
- return "DCIM"
87
-
88
-
89
78
  # Mixins
90
79
 
91
80
 
@@ -391,7 +380,7 @@ class DeviceViewSet(ConfigContextQuerySetMixin, NautobotModelViewSet):
391
380
  "software_version",
392
381
  "virtual_chassis__master",
393
382
  "device_redundancy_group",
394
- "controller_device_group",
383
+ "controller_managed_device_group",
395
384
  "secrets_group",
396
385
  "status",
397
386
  ).prefetch_related("tags", "primary_ip4__nat_outside_list", "primary_ip6__nat_outside_list", "software_image_files")
@@ -786,7 +775,7 @@ class ConnectedDeviceViewSet(ViewSet):
786
775
 
787
776
  # Determine local interface from peer interface's connection
788
777
  peer_interface = get_object_or_404(
789
- Interface.objects.all(),
778
+ Interface.objects.restrict(request.user, "view"),
790
779
  device__name=peer_device_name,
791
780
  name=peer_interface_name,
792
781
  )
@@ -840,11 +829,11 @@ class ControllerViewSet(NautobotModelViewSet):
840
829
  filterset_class = filters.ControllerFilterSet
841
830
 
842
831
 
843
- class ControllerDeviceGroupViewSet(NautobotModelViewSet):
844
- queryset = ControllerDeviceGroup.objects.select_related(
832
+ class ControllerManagedDeviceGroupViewSet(NautobotModelViewSet):
833
+ queryset = ControllerManagedDeviceGroup.objects.select_related(
845
834
  "controller",
846
835
  "parent",
847
836
  ).prefetch_related("tags")
848
837
 
849
- serializer_class = serializers.ControllerDeviceGroupSerializer
850
- filterset_class = filters.ControllerDeviceGroupFilterSet
838
+ serializer_class = serializers.ControllerManagedDeviceGroupSerializer
839
+ filterset_class = filters.ControllerManagedDeviceGroupFilterSet
nautobot/dcim/apps.py CHANGED
@@ -5,14 +5,18 @@ class DCIMConfig(NautobotConfig):
5
5
  name = "nautobot.dcim"
6
6
  verbose_name = "DCIM"
7
7
  searchable_models = [
8
+ "cable",
9
+ "controller",
10
+ "device",
11
+ "devicefamily",
12
+ "deviceredundancygroup",
13
+ "devicetype",
8
14
  "location",
15
+ "powerfeed",
9
16
  "rack",
10
17
  "rackgroup",
11
- "devicetype",
12
- "device",
18
+ "softwareversion",
13
19
  "virtualchassis",
14
- "cable",
15
- "powerfeed",
16
20
  ]
17
21
 
18
22
  def ready(self):
@@ -3,6 +3,8 @@ from django.urls import reverse
3
3
  from django.utils.http import urlencode
4
4
  import svgwrite
5
5
 
6
+ from nautobot.core.utils.config import get_settings_or_config
7
+
6
8
  from .choices import DeviceFaceChoices
7
9
  from .constants import RACK_ELEVATION_BORDER_WIDTH
8
10
 
@@ -233,7 +235,9 @@ class RackElevationSVG:
233
235
  start_y + unit_height / 2 + RACK_ELEVATION_BORDER_WIDTH,
234
236
  )
235
237
  unit = ru + 1 if self.rack.desc_units else self.rack.u_height - ru
236
- drawing.add(drawing.text(str(unit), position_coordinates, class_="unit"))
238
+ unit_two_digit_format = get_settings_or_config("RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT")
239
+ unit_display = f"{unit:02d}" if unit_two_digit_format else str(unit)
240
+ drawing.add(drawing.text(unit_display, position_coordinates, class_="unit"))
237
241
 
238
242
  for unit in self.merge_elevations(face):
239
243
  # Loop through all units in the elevation
nautobot/dcim/factory.py CHANGED
@@ -26,7 +26,7 @@ from nautobot.dcim.choices import (
26
26
  )
27
27
  from nautobot.dcim.models import (
28
28
  Controller,
29
- ControllerDeviceGroup,
29
+ ControllerManagedDeviceGroup,
30
30
  Device,
31
31
  DeviceFamily,
32
32
  DeviceRedundancyGroup,
@@ -167,7 +167,7 @@ class DeviceFactory(PrimaryModelFactory):
167
167
  factory.Faker("pyint", min_value=1, max_value=500),
168
168
  )
169
169
 
170
- controller_device_group = random_instance(ControllerDeviceGroup)
170
+ controller_managed_device_group = random_instance(ControllerManagedDeviceGroup)
171
171
 
172
172
  has_comments = NautobotBoolIterator()
173
173
  comments = factory.Maybe("has_comments", factory.Faker("bs"))
@@ -694,19 +694,19 @@ class ControllerFactory(PrimaryModelFactory):
694
694
  location = random_instance(lambda: Location.objects.get_for_model(Controller), allow_null=False)
695
695
  tenant = random_instance(Tenant)
696
696
  external_integration = random_instance(ExternalIntegration)
697
- deployed_controller_device = factory.Maybe("has_device", random_instance(Device), None)
698
- deployed_controller_group = factory.Maybe("has_device", None, random_instance(DeviceRedundancyGroup))
697
+ controller_device = factory.Maybe("has_device", random_instance(Device), None)
698
+ controller_device_redundancy_group = factory.Maybe("has_device", None, random_instance(DeviceRedundancyGroup))
699
699
 
700
700
 
701
- class ControllerDeviceGroupFactory(PrimaryModelFactory):
701
+ class ControllerManagedDeviceGroupFactory(PrimaryModelFactory):
702
702
  class Meta:
703
- model = ControllerDeviceGroup
703
+ model = ControllerManagedDeviceGroup
704
704
 
705
705
  class Params:
706
706
  has_parent = NautobotBoolIterator()
707
707
 
708
708
  name = UniqueFaker("word")
709
- parent = factory.Maybe("has_parent", random_instance(ControllerDeviceGroup), None)
709
+ parent = factory.Maybe("has_parent", random_instance(ControllerManagedDeviceGroup), None)
710
710
  controller = factory.LazyAttribute(
711
711
  lambda o: o.parent.controller if o.parent else Controller.objects.order_by("?").first()
712
712
  )
@@ -42,7 +42,7 @@ from nautobot.dcim.models import (
42
42
  ConsoleServerPort,
43
43
  ConsoleServerPortTemplate,
44
44
  Controller,
45
- ControllerDeviceGroup,
45
+ ControllerManagedDeviceGroup,
46
46
  Device,
47
47
  DeviceBay,
48
48
  DeviceBayTemplate,
@@ -99,7 +99,7 @@ __all__ = (
99
99
  "ConsoleServerPortFilterSet",
100
100
  "ConsoleServerPortTemplateFilterSet",
101
101
  "ControllerFilterSet",
102
- "ControllerDeviceGroupFilterSet",
102
+ "ControllerManagedDeviceGroupFilterSet",
103
103
  "DeviceBayFilterSet",
104
104
  "DeviceBayTemplateFilterSet",
105
105
  "DeviceFilterSet",
@@ -918,11 +918,11 @@ class DeviceFilterSet(
918
918
  to_field_name="name",
919
919
  label="Device Redundancy Groups (name or ID)",
920
920
  )
921
- controller_device_group = NaturalKeyOrPKMultipleChoiceFilter(
922
- field_name="controller_device_group",
923
- queryset=ControllerDeviceGroup.objects.all(),
921
+ controller_managed_device_group = NaturalKeyOrPKMultipleChoiceFilter(
922
+ field_name="controller_managed_device_group",
923
+ queryset=ControllerManagedDeviceGroup.objects.all(),
924
924
  to_field_name="name",
925
- label="Controller Device Groups (name or ID)",
925
+ label="Controller Managed Device Groups (name or ID)",
926
926
  )
927
927
  virtual_chassis_member = is_virtual_chassis_member
928
928
  has_console_ports = RelatedMembershipBooleanFilter(
@@ -1842,7 +1842,6 @@ class ControllerFilterSet(
1842
1842
  NautobotFilterSet,
1843
1843
  LocatableModelFilterSetMixin,
1844
1844
  TenancyModelFilterSetMixin,
1845
- LocalContextModelFilterSetMixin,
1846
1845
  StatusModelFilterSetMixin,
1847
1846
  RoleModelFilterSetMixin,
1848
1847
  ):
@@ -1864,15 +1863,15 @@ class ControllerFilterSet(
1864
1863
  to_field_name="name",
1865
1864
  label="External integration (name or ID)",
1866
1865
  )
1867
- deployed_controller_device = NaturalKeyOrPKMultipleChoiceFilter(
1866
+ controller_device = NaturalKeyOrPKMultipleChoiceFilter(
1868
1867
  queryset=Device.objects.all(),
1869
1868
  to_field_name="name",
1870
- label="Deployed controller device (name or ID)",
1869
+ label="Controller device (name or ID)",
1871
1870
  )
1872
- deployed_controller_group = NaturalKeyOrPKMultipleChoiceFilter(
1871
+ controller_device_redundancy_group = NaturalKeyOrPKMultipleChoiceFilter(
1873
1872
  queryset=DeviceRedundancyGroup.objects.all(),
1874
1873
  to_field_name="name",
1875
- label="Deployed controller group (name or ID)",
1874
+ label="Controller device redundancy group (name or ID)",
1876
1875
  )
1877
1876
 
1878
1877
  class Meta:
@@ -1880,8 +1879,8 @@ class ControllerFilterSet(
1880
1879
  fields = "__all__"
1881
1880
 
1882
1881
 
1883
- class ControllerDeviceGroupFilterSet(NautobotFilterSet):
1884
- """Filters for ControllerDeviceGroup model."""
1882
+ class ControllerManagedDeviceGroupFilterSet(NautobotFilterSet):
1883
+ """Filters for ControllerManagedDeviceGroup model."""
1885
1884
 
1886
1885
  q = SearchFilter(
1887
1886
  filter_predicates={
@@ -1894,7 +1893,7 @@ class ControllerDeviceGroupFilterSet(NautobotFilterSet):
1894
1893
  label="Controller (name or ID)",
1895
1894
  )
1896
1895
  parent = NaturalKeyOrPKMultipleChoiceFilter(
1897
- queryset=ControllerDeviceGroup.objects.all(),
1896
+ queryset=ControllerManagedDeviceGroup.objects.all(),
1898
1897
  to_field_name="name",
1899
1898
  label="Parent group (name or ID)",
1900
1899
  )
@@ -1906,7 +1905,7 @@ class ControllerDeviceGroupFilterSet(NautobotFilterSet):
1906
1905
  )
1907
1906
 
1908
1907
  class Meta:
1909
- model = ControllerDeviceGroup
1908
+ model = ControllerManagedDeviceGroup
1910
1909
  fields = "__all__"
1911
1910
 
1912
1911
  def generate_query__subtree(self, value):
@@ -1914,7 +1913,7 @@ class ControllerDeviceGroupFilterSet(NautobotFilterSet):
1914
1913
  if value:
1915
1914
  params = Q(pk__in=[v.pk for v in value])
1916
1915
  filter_name = "in"
1917
- for _ in range(ControllerDeviceGroup.objects.max_depth + 1):
1916
+ for _ in range(ControllerManagedDeviceGroup.objects.max_depth + 1):
1918
1917
  filter_name = f"parent__{filter_name}"
1919
1918
  params |= Q(**{filter_name: value})
1920
1919
  return params
@@ -1922,6 +1921,6 @@ class ControllerDeviceGroupFilterSet(NautobotFilterSet):
1922
1921
 
1923
1922
  @extend_schema_field({"type": "string"})
1924
1923
  def _subtree(self, queryset, name, value):
1925
- """FilterSet method for getting Groups that are or are descended from a given ControllerDeviceGroup(s)."""
1924
+ """FilterSet method for getting Groups that are or are descended from a given ControllerManagedDeviceGroup(s)."""
1926
1925
  params = self.generate_query__subtree(value)
1927
1926
  return queryset.filter(params)
nautobot/dcim/forms.py CHANGED
@@ -55,7 +55,7 @@ from nautobot.extras.forms import (
55
55
  )
56
56
  from nautobot.extras.models import ExternalIntegration, SecretsGroup, Status
57
57
  from nautobot.ipam.constants import BGP_ASN_MAX, BGP_ASN_MIN
58
- from nautobot.ipam.models import IPAddress, IPAddressToInterface, VLAN, VRF
58
+ from nautobot.ipam.models import IPAddress, IPAddressToInterface, VLAN, VLANLocationAssignment, VRF
59
59
  from nautobot.tenancy.forms import TenancyFilterForm, TenancyForm
60
60
  from nautobot.tenancy.models import Tenant, TenantGroup
61
61
  from nautobot.virtualization.models import Cluster, ClusterGroup, VirtualMachine
@@ -95,7 +95,7 @@ from .models import (
95
95
  ConsoleServerPort,
96
96
  ConsoleServerPortTemplate,
97
97
  Controller,
98
- ControllerDeviceGroup,
98
+ ControllerManagedDeviceGroup,
99
99
  Device,
100
100
  DeviceBay,
101
101
  DeviceBayTemplate,
@@ -194,8 +194,13 @@ class InterfaceCommonForm(forms.Form):
194
194
  # TODO: after Location model replaced Site, which was not a hierarchical model, should we allow users to add a VLAN
195
195
  # belongs to the parent Location or the child location of the parent device to the `tagged_vlan` field of the interface?
196
196
  elif mode == InterfaceModeChoices.MODE_TAGGED:
197
- valid_locations = [None, self.cleaned_data[parent_field].location]
198
- invalid_vlans = [str(v) for v in tagged_vlans if v.location not in valid_locations]
197
+ valid_location = self.cleaned_data[parent_field].location
198
+ invalid_vlans = [
199
+ str(v)
200
+ for v in tagged_vlans
201
+ if v.locations.without_tree_fields().exists()
202
+ and not VLANLocationAssignment.objects.filter(location=valid_location, vlan=v).exists()
203
+ ]
199
204
 
200
205
  if invalid_vlans:
201
206
  raise forms.ValidationError(
@@ -1548,7 +1553,9 @@ class DeviceForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalC
1548
1553
  },
1549
1554
  )
1550
1555
  device_redundancy_group = DynamicModelChoiceField(queryset=DeviceRedundancyGroup.objects.all(), required=False)
1551
- controller_device_group = DynamicModelChoiceField(queryset=ControllerDeviceGroup.objects.all(), required=False)
1556
+ controller_managed_device_group = DynamicModelChoiceField(
1557
+ queryset=ControllerManagedDeviceGroup.objects.all(), required=False
1558
+ )
1552
1559
  position = forms.IntegerField(
1553
1560
  required=False,
1554
1561
  help_text="The lowest-numbered unit occupied by the device",
@@ -1618,7 +1625,7 @@ class DeviceForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalC
1618
1625
  "rack",
1619
1626
  "device_redundancy_group",
1620
1627
  "device_redundancy_group_priority",
1621
- "controller_device_group",
1628
+ "controller_managed_device_group",
1622
1629
  "position",
1623
1630
  "face",
1624
1631
  "status",
@@ -1760,7 +1767,9 @@ class DeviceBulkEditForm(
1760
1767
  secrets_group = DynamicModelChoiceField(queryset=SecretsGroup.objects.all(), required=False)
1761
1768
  device_redundancy_group = DynamicModelChoiceField(queryset=DeviceRedundancyGroup.objects.all(), required=False)
1762
1769
  device_redundancy_group_priority = forms.IntegerField(required=False, min_value=1)
1763
- controller_device_group = DynamicModelChoiceField(queryset=ControllerDeviceGroup.objects.all(), required=False)
1770
+ controller_managed_device_group = DynamicModelChoiceField(
1771
+ queryset=ControllerManagedDeviceGroup.objects.all(), required=False
1772
+ )
1764
1773
  software_version = DynamicModelChoiceField(queryset=SoftwareVersion.objects.all(), required=False)
1765
1774
  software_image_files = DynamicModelMultipleChoiceField(queryset=SoftwareImageFile.objects.all(), required=False)
1766
1775
 
@@ -1778,7 +1787,7 @@ class DeviceBulkEditForm(
1778
1787
  "secrets_group",
1779
1788
  "device_redundancy_group",
1780
1789
  "device_redundancy_group_priority",
1781
- "controller_device_group",
1790
+ "controller_managed_device_group",
1782
1791
  "software_image_files",
1783
1792
  "software_version",
1784
1793
  ]
@@ -1858,8 +1867,8 @@ class DeviceFilterForm(
1858
1867
  null_option="None",
1859
1868
  )
1860
1869
  device_redundancy_group_priority = NumericArrayField(base_field=forms.IntegerField(min_value=1), required=False)
1861
- controller_device_group = DynamicModelMultipleChoiceField(
1862
- queryset=ControllerDeviceGroup.objects.all(),
1870
+ controller_managed_device_group = DynamicModelMultipleChoiceField(
1871
+ queryset=ControllerManagedDeviceGroup.objects.all(),
1863
1872
  to_field_name="name",
1864
1873
  required=False,
1865
1874
  null_option="None",
@@ -4123,9 +4132,30 @@ class SoftwareVersionForm(NautobotModelForm):
4123
4132
  fields = "__all__"
4124
4133
 
4125
4134
 
4126
- class ControllerForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalContextModelForm):
4135
+ class ControllerForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm):
4127
4136
  """Controller create/edit form."""
4128
4137
 
4138
+ platform = DynamicModelChoiceField(
4139
+ queryset=Platform.objects.all(),
4140
+ required=False,
4141
+ )
4142
+ tenant = DynamicModelChoiceField(
4143
+ queryset=Tenant.objects.all(),
4144
+ required=False,
4145
+ )
4146
+ external_integration = DynamicModelChoiceField(
4147
+ queryset=ExternalIntegration.objects.all(),
4148
+ required=False,
4149
+ )
4150
+ controller_device = DynamicModelChoiceField(
4151
+ queryset=Device.objects.all(),
4152
+ required=False,
4153
+ )
4154
+ controller_device_redundancy_group = DynamicModelChoiceField(
4155
+ queryset=DeviceRedundancyGroup.objects.all(),
4156
+ required=False,
4157
+ )
4158
+
4129
4159
  class Meta:
4130
4160
  model = Controller
4131
4161
  fields = (
@@ -4137,15 +4167,14 @@ class ControllerForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, Lo
4137
4167
  "tenant",
4138
4168
  "location",
4139
4169
  "external_integration",
4140
- "deployed_controller_device",
4141
- "deployed_controller_group",
4170
+ "controller_device",
4171
+ "controller_device_redundancy_group",
4142
4172
  "tags",
4143
4173
  )
4144
4174
 
4145
4175
 
4146
4176
  class ControllerFilterForm(
4147
4177
  NautobotFilterForm,
4148
- LocalContextFilterForm,
4149
4178
  LocatableModelFilterFormMixin,
4150
4179
  TenancyFilterForm,
4151
4180
  StatusModelFilterFormMixin,
@@ -4167,15 +4196,15 @@ class ControllerFilterForm(
4167
4196
  required=False,
4168
4197
  label="External integration",
4169
4198
  )
4170
- deployed_controller_device = DynamicModelMultipleChoiceField(
4199
+ controller_device = DynamicModelMultipleChoiceField(
4171
4200
  queryset=Device.objects.all(),
4172
4201
  required=False,
4173
- label="Deployed controller device",
4202
+ label="Controller device",
4174
4203
  )
4175
- deployed_controller_group = DynamicModelMultipleChoiceField(
4204
+ controller_device_redundancy_group = DynamicModelMultipleChoiceField(
4176
4205
  queryset=DeviceRedundancyGroup.objects.all(),
4177
4206
  required=False,
4178
- label="Deployed controller group",
4207
+ label="Controller device redundancy group",
4179
4208
  )
4180
4209
  tags = TagFilterField(model)
4181
4210
  field_order = (
@@ -4188,8 +4217,8 @@ class ControllerFilterForm(
4188
4217
  "platform",
4189
4218
  "tenant",
4190
4219
  "external_integration",
4191
- "deployed_controller_device",
4192
- "deployed_controller_group",
4220
+ "controller_device",
4221
+ "controller_device_redundancy_group",
4193
4222
  "tags",
4194
4223
  )
4195
4224
 
@@ -4200,7 +4229,6 @@ class ControllerBulkEditForm(
4200
4229
  StatusModelBulkEditFormMixin,
4201
4230
  RoleModelBulkEditFormMixin,
4202
4231
  NautobotBulkEditForm,
4203
- LocalContextModelBulkEditForm,
4204
4232
  ):
4205
4233
  """Controller bulk edit form."""
4206
4234
 
@@ -4220,11 +4248,11 @@ class ControllerBulkEditForm(
4220
4248
  queryset=ExternalIntegration.objects.all(),
4221
4249
  required=False,
4222
4250
  )
4223
- deployed_controller_device = DynamicModelChoiceField(
4251
+ controller_device = DynamicModelChoiceField(
4224
4252
  queryset=Device.objects.all(),
4225
4253
  required=False,
4226
4254
  )
4227
- deployed_controller_group = DynamicModelChoiceField(
4255
+ controller_device_redundancy_group = DynamicModelChoiceField(
4228
4256
  queryset=DeviceRedundancyGroup.objects.all(),
4229
4257
  required=False,
4230
4258
  )
@@ -4239,24 +4267,24 @@ class ControllerBulkEditForm(
4239
4267
  "platform",
4240
4268
  "tenant",
4241
4269
  "external_integration",
4242
- "deployed_controller_device",
4243
- "deployed_controller_group",
4270
+ "controller_device",
4271
+ "controller_device_redundancy_group",
4244
4272
  "tags",
4245
4273
  )
4246
4274
 
4247
4275
 
4248
- class ControllerDeviceGroupForm(NautobotModelForm):
4249
- """ControllerDeviceGroup create/edit form."""
4276
+ class ControllerManagedDeviceGroupForm(NautobotModelForm):
4277
+ """ControllerManagedDeviceGroup create/edit form."""
4250
4278
 
4251
- controller = DynamicModelChoiceField(queryset=Controller.objects.all(), required=False)
4279
+ controller = DynamicModelChoiceField(queryset=Controller.objects.all(), required=True)
4252
4280
  devices = DynamicModelMultipleChoiceField(queryset=Device.objects.all(), required=False)
4253
- parent = DynamicModelChoiceField(queryset=ControllerDeviceGroup.objects.all(), required=False)
4281
+ parent = DynamicModelChoiceField(queryset=ControllerManagedDeviceGroup.objects.all(), required=False)
4254
4282
 
4255
4283
  class Meta:
4256
- model = ControllerDeviceGroup
4284
+ model = ControllerManagedDeviceGroup
4257
4285
  fields = (
4258
- "name",
4259
4286
  "controller",
4287
+ "name",
4260
4288
  "devices",
4261
4289
  "parent",
4262
4290
  "weight",
@@ -4275,13 +4303,10 @@ class ControllerDeviceGroupForm(NautobotModelForm):
4275
4303
  return instance
4276
4304
 
4277
4305
 
4278
- class ControllerDeviceGroupFilterForm(
4279
- LocalContextFilterForm,
4280
- NautobotFilterForm,
4281
- ):
4282
- """ControllerDeviceGroup basic filter form."""
4306
+ class ControllerManagedDeviceGroupFilterForm(NautobotFilterForm):
4307
+ """ControllerManagedDeviceGroup basic filter form."""
4283
4308
 
4284
- model = ControllerDeviceGroup
4309
+ model = ControllerManagedDeviceGroup
4285
4310
  q = forms.CharField(required=False, label="Search")
4286
4311
  name = forms.CharField(required=False, label="Name")
4287
4312
  controller = DynamicModelChoiceField(
@@ -4290,13 +4315,13 @@ class ControllerDeviceGroupFilterForm(
4290
4315
  label="Controller",
4291
4316
  )
4292
4317
  parent = DynamicModelChoiceField(
4293
- queryset=ControllerDeviceGroup.objects.all(),
4318
+ queryset=ControllerManagedDeviceGroup.objects.all(),
4294
4319
  required=False,
4295
4320
  label="Parent",
4296
4321
  )
4297
4322
  weight = forms.IntegerField(required=False, label="Weight")
4298
4323
  subtree = DynamicModelMultipleChoiceField(
4299
- queryset=ControllerDeviceGroup.objects.all(),
4324
+ queryset=ControllerManagedDeviceGroup.objects.all(),
4300
4325
  to_field_name="name",
4301
4326
  required=False,
4302
4327
  )
@@ -4312,23 +4337,19 @@ class ControllerDeviceGroupFilterForm(
4312
4337
  )
4313
4338
 
4314
4339
 
4315
- class ControllerDeviceGroupBulkEditForm(
4316
- TagsBulkEditFormMixin,
4317
- NautobotBulkEditForm,
4318
- LocalContextModelBulkEditForm,
4319
- ):
4320
- """ControllerDeviceGroup bulk edit form."""
4340
+ class ControllerManagedDeviceGroupBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
4341
+ """ControllerManagedDeviceGroup bulk edit form."""
4321
4342
 
4322
4343
  pk = forms.ModelMultipleChoiceField(
4323
- queryset=ControllerDeviceGroup.objects.all(),
4344
+ queryset=ControllerManagedDeviceGroup.objects.all(),
4324
4345
  widget=forms.MultipleHiddenInput,
4325
4346
  )
4326
4347
  controller = DynamicModelChoiceField(queryset=Controller.objects.all(), required=False)
4327
- parent = DynamicModelChoiceField(queryset=ControllerDeviceGroup.objects.all(), required=False)
4348
+ parent = DynamicModelChoiceField(queryset=ControllerManagedDeviceGroup.objects.all(), required=False)
4328
4349
  weight = forms.IntegerField(required=False)
4329
4350
 
4330
4351
  class Meta:
4331
- model = ControllerDeviceGroup
4352
+ model = ControllerManagedDeviceGroup
4332
4353
  fields = (
4333
4354
  "controller",
4334
4355
  "parent",
nautobot/dcim/homepage.py CHANGED
@@ -79,13 +79,21 @@ layout = (
79
79
  description="Represents a set of devices which share a common control plane",
80
80
  weight=400,
81
81
  ),
82
+ HomePageItem(
83
+ name="Controllers",
84
+ link="dcim:controller_list",
85
+ model=models.Controller,
86
+ permissions=["dcim.view_controller"],
87
+ description="Represents a network or SDN (Software-Defined Networking) controllers",
88
+ weight=500,
89
+ ),
82
90
  HomePageItem(
83
91
  name="Device Redundancy Groups",
84
92
  link="dcim:deviceredundancygroup_list",
85
93
  model=models.DeviceRedundancyGroup,
86
94
  permissions=["dcim.view_deviceredundancygroup"],
87
95
  description="Represents a set of devices which operate in a failover/HA group",
88
- weight=500,
96
+ weight=600,
89
97
  ),
90
98
  HomePageItem(
91
99
  name="Interface Redundancy Groups",
@@ -93,11 +101,11 @@ layout = (
93
101
  model=models.InterfaceRedundancyGroup,
94
102
  permissions=["dcim.view_interfaceredundancygroup"],
95
103
  description="Represents a set of interfaces which operate in a failover/HA group",
96
- weight=550,
104
+ weight=700,
97
105
  ),
98
106
  HomePageGroup(
99
107
  name="Connections",
100
- weight=600,
108
+ weight=800,
101
109
  items=(
102
110
  HomePageItem(
103
111
  name="Cables",