nautobot 2.2.0b1__py3-none-any.whl → 2.2.1__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 (425) 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 +44 -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 +20 -6
  47. nautobot/core/views/mixins.py +7 -1
  48. nautobot/core/views/renderers.py +11 -6
  49. nautobot/dcim/api/serializers.py +4 -4
  50. nautobot/dcim/api/urls.py +2 -3
  51. nautobot/dcim/api/views.py +7 -18
  52. nautobot/dcim/apps.py +8 -4
  53. nautobot/dcim/elevations.py +5 -1
  54. nautobot/dcim/factory.py +7 -7
  55. nautobot/dcim/filters/__init__.py +16 -17
  56. nautobot/dcim/forms.py +61 -45
  57. nautobot/dcim/homepage.py +11 -3
  58. nautobot/dcim/management/commands/migrate_location_contacts.py +218 -0
  59. nautobot/dcim/migrations/0057_controller_models.py +11 -70
  60. nautobot/dcim/models/__init__.py +2 -2
  61. nautobot/dcim/models/devices.py +14 -16
  62. nautobot/dcim/models/racks.py +1 -3
  63. nautobot/dcim/navigation.py +23 -31
  64. nautobot/dcim/signals.py +6 -6
  65. nautobot/dcim/tables/__init__.py +2 -2
  66. nautobot/dcim/tables/devices.py +13 -16
  67. nautobot/dcim/tables/template_code.py +1 -1
  68. nautobot/dcim/templates/dcim/controller_create.html +70 -0
  69. nautobot/dcim/templates/dcim/controller_retrieve.html +35 -18
  70. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +88 -0
  71. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +75 -43
  72. nautobot/dcim/templates/dcim/device.html +11 -3
  73. nautobot/dcim/templates/dcim/device_edit.html +1 -1
  74. nautobot/dcim/templates/dcim/devicefamily_retrieve.html +4 -0
  75. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +1 -1
  76. nautobot/dcim/tests/test_api.py +47 -6
  77. nautobot/dcim/tests/test_filters.py +92 -81
  78. nautobot/dcim/tests/test_graphql.py +11 -1
  79. nautobot/dcim/tests/test_models.py +15 -15
  80. nautobot/dcim/tests/test_signals.py +3 -1
  81. nautobot/dcim/tests/test_views.py +24 -12
  82. nautobot/dcim/urls.py +1 -1
  83. nautobot/dcim/views.py +25 -15
  84. nautobot/extras/api/serializers.py +20 -1
  85. nautobot/extras/api/urls.py +1 -2
  86. nautobot/extras/api/views.py +0 -10
  87. nautobot/extras/apps.py +7 -0
  88. nautobot/extras/context_managers.py +15 -4
  89. nautobot/extras/filters/__init__.py +53 -2
  90. nautobot/extras/filters/customfields.py +14 -9
  91. nautobot/extras/filters/mixins.py +6 -1
  92. nautobot/extras/forms/contacts.py +7 -0
  93. nautobot/extras/health_checks.py +1 -0
  94. nautobot/extras/jobs.py +1 -0
  95. nautobot/extras/managers.py +15 -2
  96. nautobot/extras/models/contacts.py +1 -0
  97. nautobot/extras/models/customfields.py +25 -2
  98. nautobot/extras/models/datasources.py +1 -0
  99. nautobot/extras/models/mixins.py +1 -0
  100. nautobot/extras/navigation.py +71 -65
  101. nautobot/extras/plugins/__init__.py +2 -1
  102. nautobot/extras/plugins/views.py +7 -11
  103. nautobot/extras/querysets.py +1 -2
  104. nautobot/extras/secrets/providers.py +1 -0
  105. nautobot/extras/signals.py +15 -5
  106. nautobot/extras/tasks.py +70 -17
  107. nautobot/extras/tests/test_api.py +2 -4
  108. nautobot/extras/tests/test_customfields.py +72 -9
  109. nautobot/extras/tests/test_dynamicgroups.py +2 -0
  110. nautobot/extras/tests/test_filters.py +89 -4
  111. nautobot/extras/tests/test_models.py +9 -0
  112. nautobot/extras/tests/test_relationships.py +10 -1
  113. nautobot/extras/tests/test_views.py +112 -1
  114. nautobot/extras/views.py +18 -17
  115. nautobot/ipam/api/serializers.py +10 -0
  116. nautobot/ipam/api/urls.py +1 -2
  117. nautobot/ipam/api/views.py +0 -11
  118. nautobot/ipam/apps.py +3 -2
  119. nautobot/ipam/tables.py +2 -22
  120. nautobot/ipam/tests/test_graphql.py +2 -3
  121. nautobot/ipam/tests/test_tables.py +42 -0
  122. nautobot/ipam/tests/test_views.py +1 -0
  123. nautobot/ipam/views.py +9 -9
  124. nautobot/project-static/css/base.css +1 -0
  125. nautobot/project-static/docs/404.html +126 -73
  126. nautobot/project-static/docs/apps/index.html +127 -71
  127. nautobot/project-static/docs/apps/nautobot-apps.html +127 -71
  128. nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js → bundle.bd41221c.min.js} +2 -2
  129. nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js.map → bundle.bd41221c.min.js.map} +3 -3
  130. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +1 -0
  131. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +1 -0
  132. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +127 -71
  133. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +127 -71
  134. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +167 -73
  135. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +165 -72
  136. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +127 -71
  137. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +127 -71
  138. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +127 -71
  139. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +127 -71
  140. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +127 -71
  141. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +127 -71
  142. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +127 -71
  143. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +127 -71
  144. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +127 -71
  145. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +127 -71
  146. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +127 -71
  147. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +127 -71
  148. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +127 -71
  149. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +127 -71
  150. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +128 -72
  151. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +127 -71
  152. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +127 -71
  153. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +345 -71
  154. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +172 -73
  155. nautobot/project-static/docs/development/apps/api/configuration-view.html +127 -71
  156. nautobot/project-static/docs/development/apps/api/database-backend-config.html +127 -71
  157. nautobot/project-static/docs/development/apps/api/models/django-admin.html +127 -71
  158. nautobot/project-static/docs/development/apps/api/models/global-search.html +127 -71
  159. nautobot/project-static/docs/development/apps/api/models/graphql.html +127 -71
  160. nautobot/project-static/docs/development/apps/api/models/index.html +127 -71
  161. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +127 -71
  162. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +127 -71
  163. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +127 -71
  164. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +127 -71
  165. nautobot/project-static/docs/development/apps/api/platform-features/index.html +127 -71
  166. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +127 -71
  167. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +127 -71
  168. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +127 -71
  169. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +127 -71
  170. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +127 -71
  171. nautobot/project-static/docs/development/apps/api/prometheus.html +127 -71
  172. nautobot/project-static/docs/development/apps/api/setup.html +127 -71
  173. nautobot/project-static/docs/development/apps/api/testing.html +127 -71
  174. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +127 -71
  175. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +127 -71
  176. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +127 -71
  177. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +127 -71
  178. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +127 -71
  179. nautobot/project-static/docs/development/apps/api/views/base-template.html +127 -71
  180. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +141 -80
  181. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +144 -83
  182. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +127 -71
  183. nautobot/project-static/docs/development/apps/api/views/index.html +127 -71
  184. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +127 -71
  185. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +127 -71
  186. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +127 -71
  187. nautobot/project-static/docs/development/apps/api/views/notes.html +127 -71
  188. nautobot/project-static/docs/development/apps/api/views/rest-api.html +127 -71
  189. nautobot/project-static/docs/development/apps/api/views/urls.html +127 -71
  190. nautobot/project-static/docs/development/apps/index.html +127 -71
  191. nautobot/project-static/docs/development/apps/migration/code-updates.html +127 -71
  192. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +127 -71
  193. nautobot/project-static/docs/development/apps/migration/from-v1.html +127 -71
  194. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +127 -71
  195. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +127 -71
  196. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +127 -71
  197. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +127 -71
  198. nautobot/project-static/docs/development/apps/porting-from-netbox.html +127 -71
  199. nautobot/project-static/docs/development/core/application-registry.html +127 -71
  200. nautobot/project-static/docs/development/core/best-practices.html +145 -79
  201. nautobot/project-static/docs/development/core/bootstrap-ui.html +127 -71
  202. nautobot/project-static/docs/development/core/caching.html +127 -71
  203. nautobot/project-static/docs/development/core/controllers.html +141 -275
  204. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +127 -71
  205. nautobot/project-static/docs/development/core/extending-models.html +13 -8166
  206. nautobot/project-static/docs/development/core/generic-views.html +142 -86
  207. nautobot/project-static/docs/development/core/getting-started.html +146 -81
  208. nautobot/project-static/docs/development/core/homepage.html +145 -89
  209. nautobot/project-static/docs/development/core/index.html +127 -71
  210. nautobot/project-static/docs/development/core/model-checklist.html +8354 -0
  211. nautobot/project-static/docs/development/core/model-features.html +130 -74
  212. nautobot/project-static/docs/development/core/natural-keys.html +127 -71
  213. nautobot/project-static/docs/development/core/navigation-menu.html +127 -71
  214. nautobot/project-static/docs/development/core/release-checklist.html +127 -71
  215. nautobot/project-static/docs/development/core/role-internals.html +127 -71
  216. nautobot/project-static/docs/development/core/settings.html +127 -71
  217. nautobot/project-static/docs/development/core/style-guide.html +127 -71
  218. nautobot/project-static/docs/development/core/templates.html +127 -71
  219. nautobot/project-static/docs/development/core/testing.html +127 -71
  220. nautobot/project-static/docs/development/core/user-preferences.html +127 -71
  221. nautobot/project-static/docs/development/extending-models.html +3 -3
  222. nautobot/project-static/docs/development/index.html +127 -71
  223. nautobot/project-static/docs/development/jobs/index.html +128 -72
  224. nautobot/project-static/docs/development/jobs/migration/from-v1.html +127 -71
  225. nautobot/project-static/docs/index.html +126 -73
  226. nautobot/project-static/docs/models/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +3 -3
  227. nautobot/project-static/docs/objects.inv +0 -0
  228. nautobot/project-static/docs/release-notes/index.html +127 -71
  229. nautobot/project-static/docs/release-notes/version-1.0.html +127 -71
  230. nautobot/project-static/docs/release-notes/version-1.1.html +127 -71
  231. nautobot/project-static/docs/release-notes/version-1.2.html +127 -71
  232. nautobot/project-static/docs/release-notes/version-1.3.html +127 -71
  233. nautobot/project-static/docs/release-notes/version-1.4.html +127 -71
  234. nautobot/project-static/docs/release-notes/version-1.5.html +127 -71
  235. nautobot/project-static/docs/release-notes/version-1.6.html +127 -71
  236. nautobot/project-static/docs/release-notes/version-2.0.html +127 -71
  237. nautobot/project-static/docs/release-notes/version-2.1.html +538 -254
  238. nautobot/project-static/docs/release-notes/version-2.2.html +520 -101
  239. nautobot/project-static/docs/requirements.txt +3 -3
  240. nautobot/project-static/docs/search/search_index.json +1 -1
  241. nautobot/project-static/docs/sitemap.xml +264 -259
  242. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  243. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +127 -71
  244. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +127 -71
  245. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +127 -71
  246. nautobot/project-static/docs/user-guide/administration/configuration/index.html +127 -71
  247. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +192 -71
  248. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +127 -71
  249. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +127 -71
  250. nautobot/project-static/docs/user-guide/administration/guides/caching.html +127 -71
  251. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +127 -71
  252. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +127 -71
  253. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +127 -71
  254. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +131 -71
  255. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +127 -71
  256. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +127 -71
  257. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +130 -74
  258. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +127 -71
  259. nautobot/project-static/docs/user-guide/administration/installation/docker.html +134 -74
  260. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +127 -71
  261. nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +8616 -0
  262. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +127 -71
  263. nautobot/project-static/docs/user-guide/administration/installation/index.html +127 -71
  264. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +127 -71
  265. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +127 -71
  266. nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +130 -74
  267. nautobot/project-static/docs/user-guide/administration/installation/services.html +127 -71
  268. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +127 -71
  269. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +127 -71
  270. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +127 -71
  271. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +127 -71
  272. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +127 -71
  273. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +127 -71
  274. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +127 -71
  275. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +127 -71
  276. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +127 -71
  277. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +127 -71
  278. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +127 -71
  279. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +127 -71
  280. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +127 -71
  281. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +127 -71
  282. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +127 -71
  283. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +127 -71
  284. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +127 -71
  285. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +127 -71
  286. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +127 -71
  287. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +127 -71
  288. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +127 -71
  289. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +127 -71
  290. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +127 -71
  291. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +362 -79
  292. nautobot/project-static/docs/user-guide/core-data-model/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +210 -85
  293. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +127 -71
  294. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +127 -71
  295. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +127 -71
  296. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +127 -71
  297. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +127 -71
  298. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +127 -71
  299. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +127 -71
  300. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +127 -71
  301. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +127 -71
  302. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +127 -71
  303. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +127 -71
  304. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +127 -71
  305. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +127 -71
  306. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +127 -71
  307. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +127 -71
  308. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +127 -71
  309. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +127 -71
  310. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +127 -71
  311. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +127 -71
  312. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +127 -71
  313. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +127 -71
  314. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +127 -71
  315. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +127 -71
  316. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +127 -71
  317. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +127 -71
  318. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +127 -71
  319. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +127 -71
  320. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +127 -71
  321. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +127 -71
  322. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +127 -71
  323. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +130 -74
  324. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +127 -71
  325. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +138 -71
  326. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +138 -71
  327. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +127 -71
  328. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +127 -71
  329. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +127 -71
  330. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +127 -71
  331. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +127 -71
  332. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +127 -71
  333. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +127 -71
  334. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +127 -71
  335. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +127 -71
  336. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +127 -71
  337. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +127 -71
  338. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +127 -71
  339. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +127 -71
  340. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +127 -71
  341. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +127 -71
  342. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +127 -71
  343. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +127 -71
  344. nautobot/project-static/docs/user-guide/feature-guides/{contact-and-team.html → contacts-and-teams.html} +128 -72
  345. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +129 -73
  346. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +127 -71
  347. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +127 -71
  348. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +127 -71
  349. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +127 -71
  350. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +127 -71
  351. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +127 -71
  352. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +129 -73
  353. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +127 -71
  354. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +127 -71
  355. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +127 -71
  356. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +127 -71
  357. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +127 -71
  358. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +127 -71
  359. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +127 -71
  360. nautobot/project-static/docs/user-guide/index.html +127 -71
  361. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +127 -71
  362. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +127 -71
  363. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +127 -71
  364. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +127 -71
  365. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +127 -71
  366. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +127 -71
  367. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +127 -71
  368. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +127 -71
  369. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +127 -71
  370. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +127 -71
  371. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +127 -71
  372. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +127 -71
  373. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +127 -71
  374. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +127 -71
  375. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +127 -71
  376. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +127 -71
  377. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +127 -71
  378. nautobot/project-static/docs/user-guide/platform-functionality/note.html +127 -71
  379. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +127 -71
  380. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +127 -71
  381. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +127 -71
  382. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +127 -71
  383. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +127 -71
  384. nautobot/project-static/docs/user-guide/platform-functionality/role.html +127 -71
  385. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +127 -71
  386. nautobot/project-static/docs/user-guide/platform-functionality/status.html +127 -71
  387. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +127 -71
  388. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +127 -71
  389. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +127 -71
  390. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +127 -71
  391. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +127 -71
  392. nautobot/project-static/jquery/jquery-3.7.1.min.js +2 -0
  393. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_444444_256x240.png +0 -0
  394. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_555555_256x240.png +0 -0
  395. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777620_256x240.png +0 -0
  396. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777777_256x240.png +0 -0
  397. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_cc0000_256x240.png +0 -0
  398. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_ffffff_256x240.png +0 -0
  399. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.css +7 -0
  400. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.js +6 -0
  401. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.structure.min.css +5 -0
  402. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/jquery-ui.theme.min.css +1 -1
  403. nautobot/tenancy/api/urls.py +1 -2
  404. nautobot/tenancy/api/views.py +0 -12
  405. nautobot/tenancy/tables.py +1 -1
  406. nautobot/tenancy/tests/test_views.py +1 -0
  407. nautobot/users/api/urls.py +1 -2
  408. nautobot/users/api/views.py +2 -65
  409. nautobot/users/views.py +8 -8
  410. nautobot/virtualization/api/urls.py +1 -2
  411. nautobot/virtualization/api/views.py +0 -12
  412. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/METADATA +24 -24
  413. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/RECORD +418 -412
  414. nautobot/dcim/templates/dcim/controllerdevicegroup_create.html +0 -43
  415. nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css +0 -1
  416. nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css.map +0 -1
  417. nautobot/project-static/jquery/jquery-3.6.0.min.js +0 -2
  418. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.css +0 -7
  419. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.js +0 -6
  420. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.structure.min.css +0 -5
  421. /nautobot/dcim/templates/dcim/{controllerdevicegroup_retrieve.html → controllermanageddevicegroup_retrieve.html} +0 -0
  422. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/LICENSE.txt +0 -0
  423. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/NOTICE +0 -0
  424. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/WHEEL +0 -0
  425. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/entry_points.txt +0 -0
@@ -26,7 +26,7 @@ from nautobot.dcim.models import (
26
26
  ConsoleServerPort,
27
27
  ConsoleServerPortTemplate,
28
28
  Controller,
29
- ControllerDeviceGroup,
29
+ ControllerManagedDeviceGroup,
30
30
  Device,
31
31
  DeviceBay,
32
32
  DeviceBayTemplate,
@@ -618,6 +618,42 @@ class RackTest(APIViewTestCases.APIViewTestCase):
618
618
  self.assertEqual(response.get("Content-Type"), "image/svg+xml")
619
619
  self.assertIn(b'class="slot" height="19" width="190"', response.content)
620
620
 
621
+ @override_settings(
622
+ RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT=False,
623
+ RACK_ELEVATION_DEFAULT_UNIT_HEIGHT=22,
624
+ RACK_ELEVATION_DEFAULT_UNIT_WIDTH=230,
625
+ )
626
+ @override_config(RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT=True)
627
+ def test_get_rack_elevation_unit_svg_settings_overridden(self):
628
+ """
629
+ GET a single rack elevation in SVG format, with Django settings specifying the default RU display format
630
+ """
631
+ rack = Rack.objects.first()
632
+ self.add_permissions("dcim.view_rack")
633
+ reverse_url = reverse("dcim-api:rack-elevation", kwargs={"pk": rack.pk})
634
+ url = f"{reverse_url}?render=svg"
635
+
636
+ response = self.client.get(url, **self.header)
637
+ self.assertHttpStatus(response, status.HTTP_200_OK)
638
+ self.assertEqual(response.get("Content-Type"), "image/svg+xml")
639
+ self.assertIn(b'<text class="unit" x="15.0" y="915.0">1</text>', response.content)
640
+
641
+ @override_settings(RACK_ELEVATION_DEFAULT_UNIT_HEIGHT=22, RACK_ELEVATION_DEFAULT_UNIT_WIDTH=230)
642
+ @override_config(RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT=True)
643
+ def test_get_rack_elevation_unit_svg_config_overridden(self):
644
+ """
645
+ GET a single rack elevation in SVG format, with Constance config specifying the 2-digit RU display format
646
+ """
647
+ rack = Rack.objects.first()
648
+ self.add_permissions("dcim.view_rack")
649
+ reverse_url = reverse("dcim-api:rack-elevation", kwargs={"pk": rack.pk})
650
+ url = f"{reverse_url}?render=svg"
651
+
652
+ response = self.client.get(url, **self.header)
653
+ self.assertHttpStatus(response, status.HTTP_200_OK)
654
+ self.assertEqual(response.get("Content-Type"), "image/svg+xml")
655
+ self.assertIn(b'<text class="unit" x="15.0" y="915.0">01</text>', response.content)
656
+
621
657
  def test_detail_view_schema(self):
622
658
  url = self._get_detail_url(self._get_queryset().first())
623
659
  response = self.client.options(url, **self.header)
@@ -771,6 +807,7 @@ class ManufacturerTest(APIViewTestCases.APIViewTestCase):
771
807
  # FIXME: This has to be replaced with# `get_deletable_object` and
772
808
  # `get_deletable_object_pks` but this is a workaround just so all of these objects are
773
809
  # deletable for now.
810
+ Controller.objects.filter(controller_device__isnull=False).delete()
774
811
  Device.objects.all().delete()
775
812
  DeviceType.objects.all().delete()
776
813
  Platform.objects.all().delete()
@@ -1166,6 +1203,7 @@ class DeviceTest(APIViewTestCases.APIViewTestCase):
1166
1203
 
1167
1204
  @classmethod
1168
1205
  def setUpTestData(cls):
1206
+ Controller.objects.filter(controller_device__isnull=False).delete()
1169
1207
  Device.objects.all().delete()
1170
1208
  locations = Location.objects.filter(location_type=LocationType.objects.get(name="Campus"))[:2]
1171
1209
 
@@ -2168,7 +2206,10 @@ class ConnectedDeviceTest(APITestCase):
2168
2206
  def test_get_connected_device(self):
2169
2207
  url = reverse("dcim-api:connected-device-list")
2170
2208
  response = self.client.get(url + "?peer_device=TestDevice2&peer_interface=eth0", **self.header)
2209
+ self.assertHttpStatus(response, status.HTTP_404_NOT_FOUND)
2171
2210
 
2211
+ self.add_permissions("dcim.view_interface")
2212
+ response = self.client.get(url + "?peer_device=TestDevice2&peer_interface=eth0", **self.header)
2172
2213
  self.assertHttpStatus(response, status.HTTP_200_OK)
2173
2214
  self.assertEqual(response.data["name"], self.device1.name)
2174
2215
 
@@ -2813,8 +2854,8 @@ class ControllerTestCase(APIViewTestCases.APIViewTestCase):
2813
2854
  }
2814
2855
 
2815
2856
 
2816
- class ControllerDeviceGroupTestCase(APIViewTestCases.APIViewTestCase):
2817
- model = ControllerDeviceGroup
2857
+ class ControllerManagedDeviceGroupTestCase(APIViewTestCases.APIViewTestCase):
2858
+ model = ControllerManagedDeviceGroup
2818
2859
 
2819
2860
  @classmethod
2820
2861
  def setUpTestData(cls):
@@ -2822,17 +2863,17 @@ class ControllerDeviceGroupTestCase(APIViewTestCases.APIViewTestCase):
2822
2863
 
2823
2864
  cls.create_data = [
2824
2865
  {
2825
- "name": "ControllerDeviceGroup 1",
2866
+ "name": "ControllerManagedDeviceGroup 1",
2826
2867
  "controller": controllers[0].pk,
2827
2868
  "weight": 100,
2828
2869
  },
2829
2870
  {
2830
- "name": "ControllerDeviceGroup 2",
2871
+ "name": "ControllerManagedDeviceGroup 2",
2831
2872
  "controller": controllers[1].pk,
2832
2873
  "weight": 150,
2833
2874
  },
2834
2875
  {
2835
- "name": "ControllerDeviceGroup 3",
2876
+ "name": "ControllerManagedDeviceGroup 3",
2836
2877
  "controller": controllers[2].pk,
2837
2878
  "weight": 200,
2838
2879
  },
@@ -26,8 +26,8 @@ from nautobot.dcim.filters import (
26
26
  ConsolePortTemplateFilterSet,
27
27
  ConsoleServerPortFilterSet,
28
28
  ConsoleServerPortTemplateFilterSet,
29
- ControllerDeviceGroupFilterSet,
30
29
  ControllerFilterSet,
30
+ ControllerManagedDeviceGroupFilterSet,
31
31
  DeviceBayFilterSet,
32
32
  DeviceBayTemplateFilterSet,
33
33
  DeviceFamilyFilterSet,
@@ -68,7 +68,7 @@ from nautobot.dcim.models import (
68
68
  ConsoleServerPort,
69
69
  ConsoleServerPortTemplate,
70
70
  Controller,
71
- ControllerDeviceGroup,
71
+ ControllerManagedDeviceGroup,
72
72
  Device,
73
73
  DeviceBay,
74
74
  DeviceBayTemplate,
@@ -112,6 +112,7 @@ User = get_user_model()
112
112
 
113
113
 
114
114
  def common_test_data(cls):
115
+ Controller.objects.filter(controller_device__isnull=False).delete()
115
116
  Device.objects.all().delete()
116
117
  tenants = Tenant.objects.filter(tenant_group__isnull=False)
117
118
  cls.tenants = tenants
@@ -619,6 +620,82 @@ def common_test_data(cls):
619
620
  cls.devices[0].tags.set(Tag.objects.get_for_model(Device))
620
621
  cls.devices[1].tags.set(Tag.objects.get_for_model(Device)[:3])
621
622
 
623
+ controller_statuses = iter(Status.objects.get_for_model(Controller))
624
+ external_integrations = iter(ExternalIntegration.objects.all())
625
+ device_redundancy_groups = iter(DeviceRedundancyGroup.objects.all())
626
+
627
+ cls.controllers = (
628
+ Controller.objects.create(
629
+ name="Controller 1",
630
+ status=next(controller_statuses),
631
+ description="First",
632
+ location=loc0,
633
+ platform=platforms[0],
634
+ role=cls.device_roles[0],
635
+ tenant=tenants[0],
636
+ external_integration=next(external_integrations),
637
+ controller_device=cls.devices[0],
638
+ ),
639
+ Controller.objects.create(
640
+ name="Controller 2",
641
+ status=next(controller_statuses),
642
+ description="Second",
643
+ location=loc1,
644
+ platform=platforms[1],
645
+ role=cls.device_roles[1],
646
+ tenant=tenants[1],
647
+ external_integration=next(external_integrations),
648
+ controller_device=cls.devices[1],
649
+ ),
650
+ Controller.objects.create(
651
+ name="Controller 3",
652
+ status=next(controller_statuses),
653
+ description="Third",
654
+ location=loc2,
655
+ platform=platforms[2],
656
+ role=cls.device_roles[2],
657
+ tenant=tenants[2],
658
+ external_integration=next(external_integrations),
659
+ controller_device_redundancy_group=next(device_redundancy_groups),
660
+ ),
661
+ Controller.objects.create(
662
+ name="Controller 4",
663
+ status=next(controller_statuses),
664
+ description="Forth",
665
+ location=loc2,
666
+ platform=platforms[2],
667
+ role=cls.device_roles[2],
668
+ tenant=tenants[2],
669
+ external_integration=next(external_integrations),
670
+ controller_device_redundancy_group=next(device_redundancy_groups),
671
+ ),
672
+ )
673
+ cls.controllers[0].tags.set(Tag.objects.get_for_model(Controller))
674
+ cls.controllers[1].tags.set(Tag.objects.get_for_model(Controller)[:3])
675
+
676
+ parent_controller_managed_device_group = ControllerManagedDeviceGroup.objects.create(
677
+ name="Managed Device Group 11",
678
+ weight=1000,
679
+ controller=cls.controllers[0],
680
+ )
681
+ cls.controller_managed_device_groups = (
682
+ parent_controller_managed_device_group,
683
+ ControllerManagedDeviceGroup.objects.create(
684
+ name="Managed Device Group 12",
685
+ weight=2000,
686
+ controller=cls.controllers[1],
687
+ parent=parent_controller_managed_device_group,
688
+ ),
689
+ ControllerManagedDeviceGroup.objects.create(
690
+ name="Managed Device Group 13",
691
+ weight=3000,
692
+ controller=cls.controllers[2],
693
+ parent=parent_controller_managed_device_group,
694
+ ),
695
+ )
696
+ parent_controller_managed_device_group.tags.set(Tag.objects.get_for_model(ControllerManagedDeviceGroup))
697
+ cls.controller_managed_device_groups[1].tags.set(Tag.objects.get_for_model(ControllerManagedDeviceGroup)[:3])
698
+
622
699
 
623
700
  class LocationTypeFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase):
624
701
  queryset = LocationType.objects.all()
@@ -1341,8 +1418,8 @@ class DeviceTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilt
1341
1418
  ("device_redundancy_group", "device_redundancy_group__id"),
1342
1419
  ("device_redundancy_group", "device_redundancy_group__name"),
1343
1420
  ("device_redundancy_group_priority",),
1344
- ("controller_device_group", "controller_device_group__id"),
1345
- ("controller_device_group", "controller_device_group__name"),
1421
+ ("controller_managed_device_group", "controller_managed_device_group__id"),
1422
+ ("controller_managed_device_group", "controller_managed_device_group__name"),
1346
1423
  ("device_type", "device_type__id"),
1347
1424
  ("device_type", "device_type__model"),
1348
1425
  ("front_ports", "front_ports__id"),
@@ -1415,19 +1492,19 @@ class DeviceTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilt
1415
1492
  Service.objects.create(device=devices[0], name="ssh", protocol="tcp", ports=[22])
1416
1493
  Service.objects.create(device=devices[1], name="dns", protocol="udp", ports=[53])
1417
1494
 
1418
- cls.controller_device_groups = list(ControllerDeviceGroup.objects.all()[:2])
1495
+ cls.controller_managed_device_groups = list(ControllerManagedDeviceGroup.objects.all()[:2])
1419
1496
  cls.device_redundancy_groups = list(DeviceRedundancyGroup.objects.all()[:2])
1420
1497
  Device.objects.filter(pk=devices[0].pk).update(
1421
- controller_device_group=cls.controller_device_groups[0],
1498
+ controller_managed_device_group=cls.controller_managed_device_groups[0],
1422
1499
  device_redundancy_group=cls.device_redundancy_groups[0],
1423
1500
  )
1424
1501
  Device.objects.filter(pk=devices[1].pk).update(
1425
- controller_device_group=cls.controller_device_groups[0],
1502
+ controller_managed_device_group=cls.controller_managed_device_groups[0],
1426
1503
  device_redundancy_group=cls.device_redundancy_groups[0],
1427
1504
  device_redundancy_group_priority=1,
1428
1505
  )
1429
1506
  Device.objects.filter(pk=devices[2].pk).update(
1430
- controller_device_group=cls.controller_device_groups[1],
1507
+ controller_managed_device_group=cls.controller_managed_device_groups[1],
1431
1508
  device_redundancy_group=cls.device_redundancy_groups[1],
1432
1509
  device_redundancy_group_priority=100,
1433
1510
  )
@@ -3355,63 +3432,20 @@ class ControllerFilterSetTestCase(FilterTestCases.FilterTestCase):
3355
3432
  ("platform", "platform__name"),
3356
3433
  ("external_integration", "external_integration__id"),
3357
3434
  ("external_integration", "external_integration__name"),
3358
- ("deployed_controller_device", "deployed_controller_device__id"),
3359
- ("deployed_controller_device", "deployed_controller_device__name"),
3360
- ("deployed_controller_group", "deployed_controller_group__id"),
3361
- ("deployed_controller_group", "deployed_controller_group__name"),
3435
+ ("controller_device", "controller_device__id"),
3436
+ ("controller_device", "controller_device__name"),
3437
+ ("controller_device_redundancy_group", "controller_device_redundancy_group__id"),
3438
+ ("controller_device_redundancy_group", "controller_device_redundancy_group__name"),
3362
3439
  )
3363
3440
 
3364
3441
  @classmethod
3365
3442
  def setUpTestData(cls):
3366
3443
  common_test_data(cls)
3367
3444
 
3368
- external_integrations = iter(ExternalIntegration.objects.all())
3369
- locations = iter(Location.objects.filter(location_type__name="Campus"))
3370
- platforms = iter(Platform.objects.all())
3371
- roles = iter(Role.objects.get_for_model(Controller))
3372
- statuses = iter(Status.objects.get_for_model(Controller))
3373
- tenants = iter(Tenant.objects.all())
3374
-
3375
- cls.controllers = (
3376
- Controller.objects.create(
3377
- name="Controller 1",
3378
- status=next(statuses),
3379
- description="First",
3380
- location=next(locations),
3381
- platform=next(platforms),
3382
- role=next(roles),
3383
- tenant=next(tenants),
3384
- external_integration=next(external_integrations),
3385
- deployed_controller_device=cls.devices[0],
3386
- ),
3387
- Controller.objects.create(
3388
- name="Controller 2",
3389
- status=next(statuses),
3390
- description="Second",
3391
- location=next(locations),
3392
- platform=next(platforms),
3393
- role=next(roles),
3394
- tenant=next(tenants),
3395
- external_integration=next(external_integrations),
3396
- deployed_controller_device=cls.devices[1],
3397
- ),
3398
- Controller.objects.create(
3399
- name="Controller 3",
3400
- status=next(statuses),
3401
- description="Third",
3402
- location=next(locations),
3403
- platform=next(platforms),
3404
- role=next(roles),
3405
- tenant=next(tenants),
3406
- external_integration=next(external_integrations),
3407
- deployed_controller_group=DeviceRedundancyGroup.objects.first(),
3408
- ),
3409
- )
3410
-
3411
3445
 
3412
- class ControllerDeviceGroupFilterSetTestCase(FilterTestCases.FilterTestCase):
3413
- queryset = ControllerDeviceGroup.objects.all()
3414
- filterset = ControllerDeviceGroupFilterSet
3446
+ class ControllerManagedDeviceGroupFilterSetTestCase(FilterTestCases.FilterTestCase):
3447
+ queryset = ControllerManagedDeviceGroup.objects.all()
3448
+ filterset = ControllerManagedDeviceGroupFilterSet
3415
3449
  generic_filter_tests = (
3416
3450
  ("name",),
3417
3451
  ("weight",),
@@ -3424,26 +3458,3 @@ class ControllerDeviceGroupFilterSetTestCase(FilterTestCases.FilterTestCase):
3424
3458
  @classmethod
3425
3459
  def setUpTestData(cls):
3426
3460
  common_test_data(cls)
3427
-
3428
- cls.controllers = Controller.objects.all()[:3]
3429
-
3430
- group1 = ControllerDeviceGroup.objects.create(
3431
- name="Controller Device Group 11",
3432
- weight=1000,
3433
- controller=cls.controllers[0],
3434
- )
3435
- cls.controller_device_groups = (
3436
- group1,
3437
- ControllerDeviceGroup.objects.create(
3438
- name="Controller Device Group 12",
3439
- weight=2000,
3440
- controller=cls.controllers[1],
3441
- parent=group1,
3442
- ),
3443
- ControllerDeviceGroup.objects.create(
3444
- name="Controller Device Group 13",
3445
- weight=3000,
3446
- controller=cls.controllers[2],
3447
- parent=group1,
3448
- ),
3449
- )
@@ -4,12 +4,22 @@ from django.test import override_settings
4
4
  from nautobot.core.graphql import execute_query
5
5
  from nautobot.core.testing import create_test_user, TestCase
6
6
  from nautobot.dcim.choices import InterfaceTypeChoices
7
- from nautobot.dcim.models import Device, DeviceType, Interface, Location, LocationType, Manufacturer, Platform
7
+ from nautobot.dcim.models import (
8
+ Controller,
9
+ Device,
10
+ DeviceType,
11
+ Interface,
12
+ Location,
13
+ LocationType,
14
+ Manufacturer,
15
+ Platform,
16
+ )
8
17
  from nautobot.extras.models import DynamicGroup, Role, Status
9
18
 
10
19
 
11
20
  class GraphQLTestCase(TestCase):
12
21
  def setUp(self):
22
+ Controller.objects.filter(controller_device__isnull=False).delete()
13
23
  Device.objects.all().delete()
14
24
  self.user = create_test_user("graphql_testuser")
15
25
  self.location = Location.objects.filter(location_type=LocationType.objects.get(name="Campus")).first()
@@ -24,7 +24,7 @@ from nautobot.dcim.models import (
24
24
  ConsoleServerPort,
25
25
  ConsoleServerPortTemplate,
26
26
  Controller,
27
- ControllerDeviceGroup,
27
+ ControllerManagedDeviceGroup,
28
28
  Device,
29
29
  DeviceBay,
30
30
  DeviceBayTemplate,
@@ -1896,13 +1896,13 @@ class ControllerTestCase(ModelTestCases.BaseModelTestCase):
1896
1896
  status=Status.objects.get_for_model(Controller).first(),
1897
1897
  role=Role.objects.get_for_model(Controller).first(),
1898
1898
  location=Location.objects.first(),
1899
- deployed_controller_device=Device.objects.first(),
1900
- deployed_controller_group=DeviceRedundancyGroup.objects.first(),
1899
+ controller_device=Device.objects.first(),
1900
+ controller_device_redundancy_group=DeviceRedundancyGroup.objects.first(),
1901
1901
  )
1902
1902
  with self.assertRaises(ValidationError) as error:
1903
1903
  controller.validated_save()
1904
1904
  self.assertEqual(
1905
- error.exception.message_dict["deployed_controller_device"][0],
1905
+ error.exception.message_dict["controller_device"][0],
1906
1906
  "Cannot assign both a device and a device redundancy group to a controller.",
1907
1907
  )
1908
1908
 
@@ -1924,19 +1924,19 @@ class ControllerTestCase(ModelTestCases.BaseModelTestCase):
1924
1924
  )
1925
1925
 
1926
1926
 
1927
- class ControllerDeviceGroupTestCase(ModelTestCases.BaseModelTestCase):
1928
- model = ControllerDeviceGroup
1927
+ class ControllerManagedDeviceGroupTestCase(ModelTestCases.BaseModelTestCase):
1928
+ model = ControllerManagedDeviceGroup
1929
1929
 
1930
1930
  def test_controller_matches_parent(self):
1931
1931
  """Ensure a controller device group cannot be linked to a controller that does not match its parent."""
1932
1932
  controllers = iter(Controller.objects.all())
1933
- parent_group = ControllerDeviceGroup(
1933
+ parent_group = ControllerManagedDeviceGroup(
1934
1934
  name="Parent Group testing Controller match",
1935
1935
  controller=next(controllers),
1936
1936
  )
1937
1937
  parent_group.validated_save()
1938
1938
 
1939
- child_group = ControllerDeviceGroup(
1939
+ child_group = ControllerManagedDeviceGroup(
1940
1940
  name="Child Group testing Controller match",
1941
1941
  controller=next(controllers),
1942
1942
  parent=parent_group,
@@ -1955,37 +1955,37 @@ class ControllerDeviceGroupTestCase(ModelTestCases.BaseModelTestCase):
1955
1955
  controller1, controller2 = Controller.objects.all()[:2]
1956
1956
  self.assertNotEqual(controller1, controller2, "Controllers should be different")
1957
1957
 
1958
- parent_group = ControllerDeviceGroup.objects.create(
1958
+ parent_group = ControllerManagedDeviceGroup.objects.create(
1959
1959
  name="Parent Group testing Controller match",
1960
1960
  controller=controller1,
1961
1961
  )
1962
- child_group1 = ControllerDeviceGroup.objects.create(
1962
+ child_group1 = ControllerManagedDeviceGroup.objects.create(
1963
1963
  name="Child Group 1 testing Controller match",
1964
1964
  controller=controller1,
1965
1965
  parent=parent_group,
1966
1966
  )
1967
- child_group2 = ControllerDeviceGroup.objects.create(
1967
+ child_group2 = ControllerManagedDeviceGroup.objects.create(
1968
1968
  name="Child Group 2 testing Controller match",
1969
1969
  controller=controller1,
1970
1970
  parent=child_group1,
1971
1971
  )
1972
1972
 
1973
- parent_group = ControllerDeviceGroup.objects.get(pk=parent_group.pk)
1973
+ parent_group = ControllerManagedDeviceGroup.objects.get(pk=parent_group.pk)
1974
1974
  parent_group.controller = controller2
1975
1975
  parent_group.save()
1976
1976
 
1977
1977
  self.assertEqual(
1978
- ControllerDeviceGroup.objects.get(pk=parent_group.pk).controller,
1978
+ ControllerManagedDeviceGroup.objects.get(pk=parent_group.pk).controller,
1979
1979
  controller2,
1980
1980
  "Parent group controller should have been updated",
1981
1981
  )
1982
1982
  self.assertEqual(
1983
- ControllerDeviceGroup.objects.get(pk=child_group1.pk).controller,
1983
+ ControllerManagedDeviceGroup.objects.get(pk=child_group1.pk).controller,
1984
1984
  controller2,
1985
1985
  "Child group 1 controller should have been updated",
1986
1986
  )
1987
1987
  self.assertEqual(
1988
- ControllerDeviceGroup.objects.get(pk=child_group2.pk).controller,
1988
+ ControllerManagedDeviceGroup.objects.get(pk=child_group2.pk).controller,
1989
1989
  controller2,
1990
1990
  "Child group 2 controller should have been updated",
1991
1991
  )
@@ -1,8 +1,9 @@
1
- """Tests for DCIM Signals.py """
1
+ """Tests for DCIM Signals.py"""
2
2
 
3
3
  from django.test import TestCase
4
4
 
5
5
  from nautobot.dcim.models import (
6
+ Controller,
6
7
  Device,
7
8
  DeviceRedundancyGroup,
8
9
  DeviceType,
@@ -103,6 +104,7 @@ class DeviceRedundancyGroupTest(TestCase):
103
104
  self.device.device_redundancy_group_priority = 1
104
105
  self.device.validated_save()
105
106
 
107
+ Controller.objects.all().delete()
106
108
  deviceredundancygroup.delete()
107
109
 
108
110
  self.device.refresh_from_db()
@@ -40,8 +40,8 @@ from nautobot.dcim.choices import (
40
40
  )
41
41
  from nautobot.dcim.filters import (
42
42
  ConsoleConnectionFilterSet,
43
- ControllerDeviceGroupFilterSet,
44
43
  ControllerFilterSet,
44
+ ControllerManagedDeviceGroupFilterSet,
45
45
  InterfaceConnectionFilterSet,
46
46
  PowerConnectionFilterSet,
47
47
  SoftwareImageFileFilterSet,
@@ -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,
@@ -136,6 +136,7 @@ def create_test_device(name):
136
136
 
137
137
  class LocationTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
138
138
  model = LocationType
139
+ sort_on_field = "nestable"
139
140
 
140
141
  @classmethod
141
142
  def setUpTestData(cls):
@@ -254,15 +255,20 @@ class LocationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
254
255
 
255
256
  class RackGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
256
257
  model = RackGroup
258
+ sort_on_field = "name"
257
259
 
258
260
  @classmethod
259
261
  def setUpTestData(cls):
260
262
  location = Location.objects.filter(location_type=LocationType.objects.get(name="Campus")).first()
261
263
 
262
- RackGroup.objects.create(name="Rack Group 1", location=location)
263
- RackGroup.objects.create(name="Rack Group 2", location=location)
264
- RackGroup.objects.create(name="Rack Group 3", location=location)
265
- RackGroup.objects.create(name="Rack Group 8", location=location)
264
+ rack_groups = (
265
+ RackGroup.objects.create(name="Rack Group 1", location=location),
266
+ RackGroup.objects.create(name="Rack Group 2", location=location),
267
+ RackGroup.objects.create(name="Rack Group 3", location=location),
268
+ RackGroup.objects.create(name="Rack Group 8", location=location),
269
+ )
270
+ RackGroup.objects.create(name="Rack Group Child 1", location=location, parent=rack_groups[0])
271
+ RackGroup.objects.create(name="Rack Group Child 2", location=location, parent=rack_groups[0])
266
272
 
267
273
  cls.form_data = {
268
274
  "name": "Rack Group X",
@@ -567,6 +573,7 @@ class ManufacturerTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
567
573
  # FIXME(jathan): This has to be replaced with# `get_deletable_object` and
568
574
  # `get_deletable_object_pks` but this is a workaround just so all of these objects are
569
575
  # deletable for now.
576
+ Controller.objects.filter(controller_device__isnull=False).delete()
570
577
  Device.objects.all().delete()
571
578
  DeviceType.objects.all().delete()
572
579
  Platform.objects.all().delete()
@@ -593,6 +600,7 @@ class DeviceTypeTestCase(
593
600
 
594
601
  @classmethod
595
602
  def setUpTestData(cls):
603
+ Controller.objects.filter(controller_device__isnull=False).delete()
596
604
  Device.objects.all().delete()
597
605
  manufacturers = Manufacturer.objects.all()[:2]
598
606
 
@@ -1278,6 +1286,7 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1278
1286
 
1279
1287
  @classmethod
1280
1288
  def setUpTestData(cls):
1289
+ Controller.objects.filter(controller_device__isnull=False).delete()
1281
1290
  Device.objects.all().delete()
1282
1291
  locations = Location.objects.filter(location_type=LocationType.objects.get(name="Campus"))[:2]
1283
1292
 
@@ -1445,7 +1454,7 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1445
1454
  "face": DeviceFaceChoices.FACE_FRONT,
1446
1455
  "secrets_group": secrets_groups[1].pk,
1447
1456
  "software_version": software_versions[1].pk,
1448
- "controller_device_group": ControllerDeviceGroup.objects.first().pk,
1457
+ "controller_managed_device_group": ControllerManagedDeviceGroup.objects.first().pk,
1449
1458
  }
1450
1459
 
1451
1460
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
@@ -2227,6 +2236,9 @@ class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
2227
2236
  "software_version": software_versions[2].pk,
2228
2237
  }
2229
2238
 
2239
+ def test_table_with_indentation_is_removed_on_filter_or_sort(self):
2240
+ self.skipTest("InventoryItem table has no implementation of indentation.")
2241
+
2230
2242
 
2231
2243
  # TODO: Change base class to PrimaryObjectViewTestCase
2232
2244
  # Blocked by lack of common creation view for cables (termination A must be initialized)
@@ -3119,7 +3131,7 @@ class ControllerTestCase(ViewTestCases.PrimaryObjectViewTestCase):
3119
3131
  tenant = Tenant.objects.first()
3120
3132
 
3121
3133
  cls.form_data = {
3122
- "deployed_controller_device": device.pk,
3134
+ "controller_device": device.pk,
3123
3135
  "description": "Controller 1 description",
3124
3136
  "external_integration": external_integration.pk,
3125
3137
  "location": location.pk,
@@ -3140,16 +3152,16 @@ class ControllerTestCase(ViewTestCases.PrimaryObjectViewTestCase):
3140
3152
  }
3141
3153
 
3142
3154
 
3143
- class ControllerDeviceGroupTestCase(ViewTestCases.PrimaryObjectViewTestCase):
3144
- model = ControllerDeviceGroup
3145
- filterset = ControllerDeviceGroupFilterSet
3155
+ class ControllerManagedDeviceGroupTestCase(ViewTestCases.PrimaryObjectViewTestCase):
3156
+ model = ControllerManagedDeviceGroup
3157
+ filterset = ControllerManagedDeviceGroupFilterSet
3146
3158
 
3147
3159
  @classmethod
3148
3160
  def setUpTestData(cls):
3149
3161
  controllers = Controller.objects.all()
3150
3162
 
3151
3163
  cls.form_data = {
3152
- "name": "Controller Device Group 10",
3164
+ "name": "Managed Device Group 10",
3153
3165
  "controller": controllers[0].pk,
3154
3166
  "weight": 100,
3155
3167
  "devices": [item.pk for item in Device.objects.all()[:2]],
nautobot/dcim/urls.py CHANGED
@@ -40,7 +40,7 @@ router.register("interface-redundancy-groups-associations", views.InterfaceRedun
40
40
  router.register("software-image-files", views.SoftwareImageFileUIViewSet)
41
41
  router.register("software-versions", views.SoftwareVersionUIViewSet)
42
42
  router.register("controllers", views.ControllerUIViewSet)
43
- router.register("controller-device-groups", views.ControllerDeviceGroupUIViewSet)
43
+ router.register("controller-managed-device-groups", views.ControllerManagedDeviceGroupUIViewSet)
44
44
 
45
45
  urlpatterns = [
46
46
  # Location types