nautobot 2.4.5__py3-none-any.whl → 2.4.7__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 (410) hide show
  1. nautobot/apps/forms.py +2 -0
  2. nautobot/circuits/templates/circuits/providernetwork.html +1 -1
  3. nautobot/circuits/templates/circuits/providernetwork_retrieve.html +2 -55
  4. nautobot/circuits/views.py +20 -23
  5. nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +2 -40
  6. nautobot/cloud/views.py +12 -0
  7. nautobot/core/api/mixins.py +10 -0
  8. nautobot/core/api/urls.py +2 -2
  9. nautobot/core/api/views.py +39 -1
  10. nautobot/core/celery/encoders.py +2 -2
  11. nautobot/core/forms/__init__.py +2 -0
  12. nautobot/core/forms/fields.py +23 -7
  13. nautobot/core/forms/utils.py +1 -0
  14. nautobot/core/forms/widgets.py +18 -0
  15. nautobot/core/jobs/bulk_actions.py +1 -1
  16. nautobot/core/management/commands/generate_test_data.py +1 -1
  17. nautobot/core/models/name_color_content_types.py +9 -0
  18. nautobot/core/models/validators.py +7 -0
  19. nautobot/core/settings.py +0 -14
  20. nautobot/core/settings.yaml +0 -28
  21. nautobot/core/tables.py +6 -1
  22. nautobot/core/templates/generic/object_retrieve.html +1 -1
  23. nautobot/core/templates/widgets/sluginput.html +5 -1
  24. nautobot/core/templatetags/helpers.py +15 -1
  25. nautobot/core/testing/api.py +18 -0
  26. nautobot/core/testing/integration.py +6 -2
  27. nautobot/core/tests/nautobot_config.py +0 -2
  28. nautobot/core/tests/runner.py +17 -140
  29. nautobot/core/tests/test_api.py +4 -4
  30. nautobot/core/tests/test_authentication.py +83 -4
  31. nautobot/core/tests/test_forms.py +11 -8
  32. nautobot/core/tests/test_graphql.py +9 -0
  33. nautobot/core/tests/test_jobs.py +7 -0
  34. nautobot/core/ui/object_detail.py +47 -3
  35. nautobot/core/utils/lookup.py +2 -2
  36. nautobot/dcim/factory.py +2 -0
  37. nautobot/dcim/filters/__init__.py +5 -0
  38. nautobot/dcim/forms.py +27 -1
  39. nautobot/dcim/migrations/0068_alter_softwareimagefile_download_url.py +19 -0
  40. nautobot/dcim/migrations/0069_softwareimagefile_external_integration.py +25 -0
  41. nautobot/dcim/models/devices.py +9 -2
  42. nautobot/dcim/models/locations.py +9 -0
  43. nautobot/dcim/tables/devices.py +1 -0
  44. nautobot/dcim/templates/dcim/device_list.html +1 -1
  45. nautobot/dcim/templates/dcim/devicetype.html +1 -1
  46. nautobot/dcim/templates/dcim/manufacturer.html +1 -63
  47. nautobot/dcim/templates/dcim/module_list.html +1 -1
  48. nautobot/dcim/templates/dcim/moduletype_retrieve.html +1 -1
  49. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +4 -0
  50. nautobot/dcim/tests/integration/test_module_bay_position.py +125 -0
  51. nautobot/dcim/tests/test_api.py +74 -31
  52. nautobot/dcim/tests/test_filters.py +2 -0
  53. nautobot/dcim/tests/test_models.py +78 -0
  54. nautobot/dcim/tests/test_views.py +7 -1
  55. nautobot/dcim/urls.py +1 -45
  56. nautobot/dcim/views.py +35 -66
  57. nautobot/extras/choices.py +4 -0
  58. nautobot/extras/filters/__init__.py +6 -0
  59. nautobot/extras/forms/forms.py +83 -11
  60. nautobot/extras/models/customfields.py +10 -9
  61. nautobot/extras/plugins/marketplace_manifest.yml +18 -0
  62. nautobot/extras/signals.py +43 -4
  63. nautobot/extras/tables.py +4 -5
  64. nautobot/extras/tasks.py +4 -2
  65. nautobot/extras/templates/extras/contact_retrieve.html +1 -58
  66. nautobot/extras/templates/extras/exporttemplate.html +1 -53
  67. nautobot/extras/templates/extras/inc/panel_changelog.html +1 -1
  68. nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
  69. nautobot/extras/templates/extras/status.html +1 -37
  70. nautobot/extras/templates/extras/team_retrieve.html +1 -58
  71. nautobot/extras/tests/integration/test_notes.py +1 -1
  72. nautobot/extras/tests/test_api.py +22 -7
  73. nautobot/extras/tests/test_changelog.py +4 -4
  74. nautobot/extras/tests/test_customfields.py +27 -0
  75. nautobot/extras/tests/test_plugins.py +19 -13
  76. nautobot/extras/tests/test_relationships.py +9 -0
  77. nautobot/extras/tests/test_tags.py +2 -2
  78. nautobot/extras/tests/test_views.py +37 -6
  79. nautobot/extras/urls.py +3 -100
  80. nautobot/extras/views.py +111 -133
  81. nautobot/ipam/tables.py +7 -2
  82. nautobot/ipam/templates/ipam/namespace_retrieve.html +0 -41
  83. nautobot/ipam/templates/ipam/service.html +2 -46
  84. nautobot/ipam/templates/ipam/service_edit.html +1 -17
  85. nautobot/ipam/templates/ipam/service_retrieve.html +7 -0
  86. nautobot/ipam/tests/migration/__init__.py +0 -0
  87. nautobot/ipam/tests/migration/test_migrations.py +510 -0
  88. nautobot/ipam/tests/test_api.py +66 -36
  89. nautobot/ipam/tests/test_filters.py +0 -10
  90. nautobot/ipam/tests/test_views.py +44 -2
  91. nautobot/ipam/urls.py +2 -47
  92. nautobot/ipam/utils/migrations.py +185 -152
  93. nautobot/ipam/utils/testing.py +177 -0
  94. nautobot/ipam/views.py +95 -157
  95. nautobot/project-static/css/base.css +5 -0
  96. nautobot/project-static/docs/404.html +0 -2
  97. nautobot/project-static/docs/apps/index.html +0 -2
  98. nautobot/project-static/docs/apps/nautobot-apps.html +0 -2
  99. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +0 -2
  100. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +0 -2
  101. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +0 -2
  102. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +0 -2
  103. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +0 -2
  104. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +0 -2
  105. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +0 -2
  106. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +0 -2
  107. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +0 -2
  108. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +0 -2
  109. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +0 -2
  110. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +0 -2
  111. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +62 -2
  112. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +0 -2
  113. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +0 -2
  114. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +47 -2
  115. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +0 -2
  116. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +0 -2
  117. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +18 -2
  118. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +0 -2
  119. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +70 -5
  120. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +0 -2
  121. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +0 -2
  122. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +0 -2
  123. nautobot/project-static/docs/development/apps/api/configuration-view.html +0 -2
  124. nautobot/project-static/docs/development/apps/api/database-backend-config.html +0 -2
  125. nautobot/project-static/docs/development/apps/api/models/django-admin.html +0 -2
  126. nautobot/project-static/docs/development/apps/api/models/global-search.html +0 -2
  127. nautobot/project-static/docs/development/apps/api/models/graphql.html +0 -2
  128. nautobot/project-static/docs/development/apps/api/models/index.html +0 -2
  129. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +0 -2
  130. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +0 -2
  131. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +0 -2
  132. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +0 -2
  133. nautobot/project-static/docs/development/apps/api/platform-features/index.html +0 -2
  134. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +0 -2
  135. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +0 -2
  136. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +0 -2
  137. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +0 -2
  138. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +0 -2
  139. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +0 -2
  140. nautobot/project-static/docs/development/apps/api/prometheus.html +0 -2
  141. nautobot/project-static/docs/development/apps/api/setup.html +0 -2
  142. nautobot/project-static/docs/development/apps/api/testing.html +0 -89
  143. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +0 -2
  144. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +0 -2
  145. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +0 -2
  146. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +0 -2
  147. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +0 -2
  148. nautobot/project-static/docs/development/apps/api/views/base-template.html +0 -2
  149. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +0 -2
  150. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +0 -2
  151. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +0 -2
  152. nautobot/project-static/docs/development/apps/api/views/index.html +0 -2
  153. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +0 -2
  154. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +0 -2
  155. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +0 -2
  156. nautobot/project-static/docs/development/apps/api/views/notes.html +0 -2
  157. nautobot/project-static/docs/development/apps/api/views/rest-api.html +0 -2
  158. nautobot/project-static/docs/development/apps/api/views/urls.html +0 -2
  159. nautobot/project-static/docs/development/apps/index.html +0 -2
  160. nautobot/project-static/docs/development/apps/migration/code-updates.html +0 -2
  161. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +1 -3
  162. nautobot/project-static/docs/development/apps/migration/from-v1.html +0 -2
  163. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +0 -2
  164. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +0 -2
  165. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +0 -2
  166. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +0 -2
  167. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +0 -2
  168. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +0 -2
  169. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +0 -2
  170. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +0 -2
  171. nautobot/project-static/docs/development/apps/porting-from-netbox.html +0 -2
  172. nautobot/project-static/docs/development/core/application-registry.html +0 -2
  173. nautobot/project-static/docs/development/core/best-practices.html +3 -5
  174. nautobot/project-static/docs/development/core/bootstrap-ui.html +0 -2
  175. nautobot/project-static/docs/development/core/caching.html +0 -2
  176. nautobot/project-static/docs/development/core/controllers.html +0 -2
  177. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +0 -2
  178. nautobot/project-static/docs/development/core/generic-views.html +0 -2
  179. nautobot/project-static/docs/development/core/getting-started.html +78 -109
  180. nautobot/project-static/docs/development/core/homepage.html +0 -2
  181. nautobot/project-static/docs/development/core/index.html +0 -2
  182. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +0 -2
  183. nautobot/project-static/docs/development/core/model-checklist.html +0 -2
  184. nautobot/project-static/docs/development/core/model-features.html +0 -2
  185. nautobot/project-static/docs/development/core/natural-keys.html +0 -2
  186. nautobot/project-static/docs/development/core/navigation-menu.html +0 -2
  187. nautobot/project-static/docs/development/core/release-checklist.html +1 -3
  188. nautobot/project-static/docs/development/core/role-internals.html +0 -2
  189. nautobot/project-static/docs/development/core/settings.html +0 -2
  190. nautobot/project-static/docs/development/core/style-guide.html +1 -3
  191. nautobot/project-static/docs/development/core/templates.html +0 -2
  192. nautobot/project-static/docs/development/core/testing.html +24 -200
  193. nautobot/project-static/docs/development/core/ui-component-framework.html +0 -2
  194. nautobot/project-static/docs/development/core/user-preferences.html +0 -2
  195. nautobot/project-static/docs/development/index.html +0 -2
  196. nautobot/project-static/docs/development/jobs/index.html +0 -2
  197. nautobot/project-static/docs/development/jobs/migration/from-v1.html +0 -2
  198. nautobot/project-static/docs/index.html +0 -2
  199. nautobot/project-static/docs/media/user-guide/administration/getting-started/nautobot-cloud.png +0 -0
  200. nautobot/project-static/docs/objects.inv +0 -0
  201. nautobot/project-static/docs/overview/application_stack.html +1 -3
  202. nautobot/project-static/docs/overview/design_philosophy.html +0 -2
  203. nautobot/project-static/docs/release-notes/index.html +0 -2
  204. nautobot/project-static/docs/release-notes/version-1.0.html +0 -2
  205. nautobot/project-static/docs/release-notes/version-1.1.html +0 -2
  206. nautobot/project-static/docs/release-notes/version-1.2.html +0 -2
  207. nautobot/project-static/docs/release-notes/version-1.3.html +0 -2
  208. nautobot/project-static/docs/release-notes/version-1.4.html +0 -2
  209. nautobot/project-static/docs/release-notes/version-1.5.html +0 -2
  210. nautobot/project-static/docs/release-notes/version-1.6.html +0 -2
  211. nautobot/project-static/docs/release-notes/version-2.0.html +0 -2
  212. nautobot/project-static/docs/release-notes/version-2.1.html +0 -2
  213. nautobot/project-static/docs/release-notes/version-2.2.html +0 -2
  214. nautobot/project-static/docs/release-notes/version-2.3.html +0 -2
  215. nautobot/project-static/docs/release-notes/version-2.4.html +364 -3
  216. nautobot/project-static/docs/search/search_index.json +1 -1
  217. nautobot/project-static/docs/sitemap.xml +290 -290
  218. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  219. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +0 -2
  220. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +0 -2
  221. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +0 -2
  222. nautobot/project-static/docs/user-guide/administration/configuration/index.html +0 -2
  223. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +0 -2
  224. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +2 -50
  225. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +0 -2
  226. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +0 -2
  227. nautobot/project-static/docs/user-guide/administration/guides/docker.html +0 -2
  228. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +0 -2
  229. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +71 -2
  230. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +0 -2
  231. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +0 -2
  232. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +0 -2
  233. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +0 -2
  234. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +0 -2
  235. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +0 -2
  236. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +0 -2
  237. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +3 -3
  238. nautobot/project-static/docs/user-guide/administration/installation/index.html +257 -18
  239. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +0 -2
  240. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +0 -2
  241. nautobot/project-static/docs/user-guide/administration/installation/services.html +0 -2
  242. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +0 -2
  243. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +0 -2
  244. nautobot/project-static/docs/user-guide/administration/security/index.html +0 -2
  245. nautobot/project-static/docs/user-guide/administration/security/notices.html +0 -2
  246. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +1 -3
  247. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +0 -2
  248. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +0 -2
  249. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +0 -2
  250. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +0 -2
  251. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +0 -2
  252. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +0 -2
  253. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +0 -2
  254. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +0 -2
  255. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +0 -2
  256. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +2 -4
  257. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +0 -2
  258. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +0 -2
  259. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +0 -2
  260. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +0 -2
  261. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +0 -2
  262. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +0 -2
  263. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +0 -2
  264. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +0 -2
  265. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +0 -2
  266. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +0 -2
  267. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +0 -2
  268. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +0 -2
  269. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +0 -2
  270. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +0 -2
  271. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +0 -2
  272. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +0 -2
  273. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +0 -2
  274. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +0 -2
  275. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +0 -2
  276. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +0 -2
  277. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +0 -2
  278. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +0 -2
  279. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +0 -2
  280. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +0 -2
  281. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +0 -2
  282. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +0 -2
  283. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +0 -2
  284. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +0 -2
  285. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +0 -2
  286. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +0 -2
  287. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +0 -2
  288. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +0 -2
  289. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +0 -2
  290. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +0 -2
  291. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +0 -2
  292. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +0 -2
  293. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +0 -2
  294. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +0 -2
  295. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +0 -2
  296. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +0 -2
  297. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +0 -2
  298. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +0 -2
  299. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +0 -2
  300. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +0 -2
  301. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +0 -2
  302. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +0 -2
  303. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +0 -2
  304. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +0 -2
  305. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +0 -2
  306. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +0 -2
  307. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +4 -2
  308. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +0 -2
  309. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +0 -2
  310. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +0 -2
  311. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +0 -2
  312. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +0 -2
  313. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +0 -2
  314. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +0 -2
  315. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +0 -2
  316. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +0 -2
  317. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +0 -2
  318. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +0 -2
  319. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +0 -2
  320. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +0 -2
  321. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +0 -2
  322. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +0 -2
  323. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +0 -2
  324. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +0 -2
  325. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +0 -2
  326. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +0 -2
  327. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +0 -2
  328. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +0 -2
  329. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +0 -2
  330. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +0 -2
  331. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +0 -2
  332. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +0 -2
  333. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +0 -2
  334. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +0 -2
  335. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +0 -2
  336. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +11 -13
  337. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +0 -2
  338. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +8 -10
  339. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +1 -2
  340. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +0 -2
  341. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +40 -27
  342. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +4 -6
  343. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +1 -3
  344. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +77 -7
  345. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +1 -3
  346. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +0 -3
  347. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +1 -3
  348. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +0 -2
  349. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +0 -2
  350. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +0 -2
  351. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +0 -2
  352. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +0 -2
  353. nautobot/project-static/docs/user-guide/index.html +89 -4
  354. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +0 -2
  355. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +0 -2
  356. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +0 -2
  357. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +0 -2
  358. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +0 -2
  359. nautobot/project-static/docs/user-guide/platform-functionality/events.html +0 -2
  360. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +0 -2
  361. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +0 -2
  362. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +0 -2
  363. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +0 -2
  364. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +0 -2
  365. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +0 -2
  366. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +0 -2
  367. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +0 -2
  368. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +0 -2
  369. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +0 -2
  370. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +0 -2
  371. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +0 -2
  372. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +0 -2
  373. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +0 -2
  374. nautobot/project-static/docs/user-guide/platform-functionality/note.html +0 -2
  375. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +0 -2
  376. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +0 -2
  377. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +0 -2
  378. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +0 -2
  379. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +0 -2
  380. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +0 -2
  381. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +0 -2
  382. nautobot/project-static/docs/user-guide/platform-functionality/role.html +0 -2
  383. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +0 -2
  384. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +0 -2
  385. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +0 -2
  386. nautobot/project-static/docs/user-guide/platform-functionality/status.html +0 -2
  387. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +0 -2
  388. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +0 -2
  389. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +0 -2
  390. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +0 -2
  391. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +207 -124
  392. nautobot/project-static/js/forms.js +88 -37
  393. nautobot/project-static/js/homepage_layout.js +12 -3
  394. nautobot/virtualization/forms.py +20 -0
  395. nautobot/virtualization/templates/virtualization/clustergroup.html +1 -39
  396. nautobot/virtualization/templates/virtualization/clustertype.html +1 -0
  397. nautobot/virtualization/tests/test_api.py +14 -3
  398. nautobot/virtualization/tests/test_views.py +10 -2
  399. nautobot/virtualization/urls.py +10 -93
  400. nautobot/virtualization/views.py +33 -72
  401. {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/METADATA +6 -5
  402. {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/RECORD +407 -402
  403. {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/WHEEL +1 -1
  404. nautobot/core/tests/performance_baselines.yml +0 -8900
  405. nautobot/dcim/templates/dcim/modulebay_create.html +0 -39
  406. nautobot/ipam/tests/test_migrations.py +0 -462
  407. /nautobot/ipam/templates/ipam/{namespace_ipaddresses.html → namespace_ip_addresses.html} +0 -0
  408. {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/LICENSE.txt +0 -0
  409. {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/NOTICE +0 -0
  410. {nautobot-2.4.5.dist-info → nautobot-2.4.7.dist-info}/entry_points.txt +0 -0
@@ -163,16 +163,6 @@ class VRFDeviceAssignmentTest(APIViewTestCases.APIViewTestCase):
163
163
  virtual_machine=cls.test_vm,
164
164
  rd="65000:4",
165
165
  )
166
- VRFDeviceAssignment.objects.create(
167
- vrf=cls.vrfs[0],
168
- virtual_device_context=cls.vdcs[0],
169
- name="VRFDeviceAssignment 1",
170
- rd="65000:5",
171
- )
172
- VRFDeviceAssignment.objects.create(
173
- vrf=cls.vrfs[0],
174
- virtual_device_context=cls.vdcs[1],
175
- )
176
166
 
177
167
  cls.update_data = {
178
168
  "name": "VRFDeviceAssignment 2",
@@ -207,21 +197,30 @@ class VRFDeviceAssignmentTest(APIViewTestCases.APIViewTestCase):
207
197
 
208
198
  def test_creating_invalid_vrf_device_assignments(self):
209
199
  # Add object-level permission
210
- self.add_permissions("ipam.add_vrfdeviceassignment")
200
+ self.add_permissions(
201
+ "ipam.add_vrfdeviceassignment",
202
+ "dcim.view_device",
203
+ "dcim.view_virtualdevicecontext",
204
+ "ipam.view_vrf",
205
+ "virtualization.view_virtualmachine",
206
+ )
207
+ existing_vrf_device = VRFDeviceAssignment.objects.filter(device__isnull=False).first()
208
+ existing_vrf_vm = VRFDeviceAssignment.objects.filter(virtual_machine__isnull=False).first()
209
+ existing_vrf_vdc = VRFDeviceAssignment.objects.filter(virtual_device_context__isnull=False).first()
211
210
  duplicate_create_data = [
212
211
  {
213
- "vrf": self.vrfs[0].pk,
214
- "device": self.devices[1].pk,
212
+ "vrf": existing_vrf_device.vrf.pk,
213
+ "device": existing_vrf_device.device.pk,
215
214
  "rd": "65000:6",
216
215
  },
217
216
  {
218
- "vrf": self.vrfs[1].pk,
219
- "virtual_machine": self.test_vm.pk,
217
+ "vrf": existing_vrf_vm.vrf.pk,
218
+ "virtual_machine": existing_vrf_vm.virtual_machine.pk,
220
219
  "rd": "65000:6",
221
220
  },
222
221
  {
223
- "vrf": self.vrfs[0].pk,
224
- "virtual_device_context": self.vdcs[1].pk,
222
+ "vrf": existing_vrf_vdc.vrf.pk,
223
+ "virtual_device_context": existing_vrf_vdc.virtual_device_context.pk,
225
224
  "rd": "65000:6",
226
225
  },
227
226
  ]
@@ -311,7 +310,7 @@ class VRFPrefixAssignmentTest(APIViewTestCases.APIViewTestCase):
311
310
  "vrf": self.vrfs[0].pk,
312
311
  "prefix": None,
313
312
  }
314
- self.add_permissions("ipam.add_vrfprefixassignment")
313
+ self.add_permissions("ipam.add_vrfprefixassignment", "ipam.view_prefix", "ipam.view_vrf")
315
314
  response = self.client.post(self._get_list_url(), duplicate_create_data, format="json", **self.header)
316
315
  self.assertContains(
317
316
  response, "The fields vrf, prefix must make a unique set.", status_code=status.HTTP_400_BAD_REQUEST
@@ -420,7 +419,16 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
420
419
  """
421
420
  Tests for the 2.0/2.1 REST API of Prefixes.
422
421
  """
423
- self.add_permissions("ipam.view_prefix", "ipam.add_prefix", "ipam.change_prefix")
422
+ self.add_permissions(
423
+ "dcim.view_location",
424
+ "ipam.view_prefix",
425
+ "ipam.add_prefix",
426
+ "ipam.change_prefix",
427
+ "ipam.view_ipaddress",
428
+ "ipam.view_namespace",
429
+ "ipam.view_rir",
430
+ "extras.view_status",
431
+ )
424
432
 
425
433
  with self.subTest("valid GET"):
426
434
  prefix = Prefix.objects.annotate(location_count=Count("locations")).filter(location_count=1).first()
@@ -516,7 +524,7 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
516
524
  else:
517
525
  self.fail("Suitable prefix fixture not found")
518
526
  url = reverse("ipam-api:prefix-available-prefixes", kwargs={"pk": prefix.pk})
519
- self.add_permissions("ipam.add_prefix")
527
+ self.add_permissions("ipam.add_prefix", "ipam.view_namespace", "extras.view_status", "extras.add_customfield")
520
528
 
521
529
  # Create four available prefixes with individual requests
522
530
  child_prefix_length = prefix.prefix_length + 2
@@ -566,7 +574,9 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
566
574
  self.fail("Suitable prefix fixture not found")
567
575
 
568
576
  url = reverse("ipam-api:prefix-available-prefixes", kwargs={"pk": prefix.pk})
569
- self.add_permissions("ipam.view_prefix", "ipam.add_prefix")
577
+ self.add_permissions(
578
+ "ipam.view_prefix", "ipam.add_prefix", "extras.view_status", "extras.add_customfield", "ipam.view_namespace"
579
+ )
570
580
 
571
581
  # Try to create five prefixes (only four are available)
572
582
  child_prefix_length = prefix.prefix_length + 2
@@ -626,7 +636,7 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
626
636
  description="This is the Prefix created for whole network.",
627
637
  )
628
638
  url = reverse("ipam-api:prefix-available-prefixes", kwargs={"pk": prefix.pk})
629
- self.add_permissions("ipam.view_prefix")
639
+ self.add_permissions("ipam.view_prefix", "ipam.view_namespace", "extras.view_status")
630
640
  self.add_permissions(
631
641
  "ipam.add_prefix", constraints={"description__startswith": "This is the Prefix created for"}
632
642
  )
@@ -683,9 +693,10 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
683
693
  description="This is the Prefix created for whole network.",
684
694
  )
685
695
  url = reverse("ipam-api:prefix-available-prefixes", kwargs={"pk": prefix.pk})
686
- self.add_permissions("ipam.view_prefix")
696
+ self.add_permissions("ipam.view_prefix", "ipam.view_namespace", "extras.view_status")
687
697
  self.add_permissions(
688
- "ipam.add_prefix", constraints={"description__startswith": "This is the Prefix created for"}
698
+ "ipam.add_prefix",
699
+ constraints={"description__startswith": "This is the Prefix created for"},
689
700
  )
690
701
 
691
702
  # Test invalid request
@@ -812,7 +823,7 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
812
823
  namespace=self.namespace,
813
824
  )
814
825
  url = reverse("ipam-api:prefix-available-ips", kwargs={"pk": prefix.pk})
815
- self.add_permissions("ipam.view_prefix", "ipam.add_ipaddress", "extras.view_status")
826
+ self.add_permissions("ipam.view_prefix", "ipam.add_ipaddress", "ipam.view_namespace", "extras.view_status")
816
827
 
817
828
  data = {
818
829
  "status": self.status.pk,
@@ -839,7 +850,7 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
839
850
  cf = CustomField.objects.create(key="ipcf", label="IP Custom Field", type="text")
840
851
  cf.content_types.add(ContentType.objects.get_for_model(IPAddress))
841
852
  url = reverse("ipam-api:prefix-available-ips", kwargs={"pk": prefix.pk})
842
- self.add_permissions("ipam.view_prefix", "ipam.add_ipaddress", "extras.view_status")
853
+ self.add_permissions("ipam.view_prefix", "ipam.view_namespace", "ipam.add_ipaddress", "extras.view_status")
843
854
 
844
855
  # Create all six available IPs with individual requests
845
856
  for i in range(1, 7):
@@ -875,7 +886,13 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
875
886
  cf = CustomField.objects.create(key="ipcf", label="IP Custom Field", type="text")
876
887
  cf.content_types.add(ContentType.objects.get_for_model(IPAddress))
877
888
  url = reverse("ipam-api:prefix-available-ips", kwargs={"pk": prefix.pk})
878
- self.add_permissions("ipam.view_prefix", "ipam.add_ipaddress", "extras.view_status")
889
+ self.add_permissions(
890
+ "ipam.view_prefix",
891
+ "ipam.add_ipaddress",
892
+ "ipam.view_namespace",
893
+ "extras.view_customfield",
894
+ "extras.view_status",
895
+ )
879
896
 
880
897
  # Try to create seven IPs (only six are available)
881
898
  data = [
@@ -906,7 +923,7 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
906
923
  description="This is the Prefix created for whole network.",
907
924
  )
908
925
  url = reverse("ipam-api:prefix-available-ips", kwargs={"pk": prefix.pk})
909
- self.add_permissions("ipam.view_prefix", "ipam.view_ipaddress")
926
+ self.add_permissions("ipam.view_prefix", "ipam.view_ipaddress", "ipam.view_namespace", "extras.view_status")
910
927
  self.add_permissions(
911
928
  "ipam.add_ipaddress", constraints={"description__startswith": "This is the IP created for"}
912
929
  )
@@ -959,7 +976,7 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
959
976
  description="This is a Prefix created for whole network.",
960
977
  )
961
978
  url = reverse("ipam-api:prefix-available-ips", kwargs={"pk": prefix.pk})
962
- self.add_permissions("ipam.view_prefix", "ipam.view_ipaddress")
979
+ self.add_permissions("ipam.view_prefix", "ipam.view_ipaddress", "ipam.view_namespace", "extras.view_status")
963
980
  self.add_permissions(
964
981
  "ipam.add_ipaddress", constraints={"description__startswith": "This is the IP created for"}
965
982
  )
@@ -1183,7 +1200,7 @@ class IPAddressTest(APIViewTestCases.APIViewTestCase):
1183
1200
 
1184
1201
  def test_create_requires_parent_or_namespace(self):
1185
1202
  """Test that missing parent/namespace fields result in an error."""
1186
- self.add_permissions("ipam.add_ipaddress")
1203
+ self.add_permissions("ipam.add_ipaddress", "extras.view_status")
1187
1204
  data = {
1188
1205
  "address": "192.168.0.10/32",
1189
1206
  "status": self.statuses[0].pk,
@@ -1214,7 +1231,7 @@ class IPAddressTest(APIViewTestCases.APIViewTestCase):
1214
1231
  def test_create_multiple_outside_nat_success(self):
1215
1232
  """Validate NAT inside address can tie to multiple NAT outside addresses."""
1216
1233
  # Create the two outside NAT IP Addresses tied back to the single inside NAT address
1217
- self.add_permissions("ipam.add_ipaddress", "ipam.view_ipaddress")
1234
+ self.add_permissions("ipam.add_ipaddress", "ipam.view_ipaddress", "ipam.view_namespace", "extras.view_status")
1218
1235
  nat_inside = IPAddress.objects.filter(nat_outside_list__isnull=True).first()
1219
1236
  # Create NAT outside with above address IP as inside NAT
1220
1237
  ip1 = self.client.post(
@@ -1251,7 +1268,9 @@ class IPAddressTest(APIViewTestCases.APIViewTestCase):
1251
1268
  self.assertEqual(response.data["nat_outside_list"][1]["address"], "192.168.0.20/24")
1252
1269
 
1253
1270
  def test_creating_ipaddress_with_an_invalid_parent(self):
1254
- self.add_permissions("ipam.add_ipaddress")
1271
+ self.add_permissions(
1272
+ "ipam.add_ipaddress", "extras.view_status", "ipam.view_prefix", "ipam.view_ipaddress", "ipam.view_namespace"
1273
+ )
1255
1274
  prefixes = (
1256
1275
  Prefix.objects.create(prefix="10.0.0.0/8", status=self.statuses[0], namespace=self.namespace),
1257
1276
  Prefix.objects.create(prefix="192.168.0.0/25", status=self.statuses[0], namespace=self.namespace),
@@ -1403,6 +1422,8 @@ class VLANGroupTest(APIViewTestCases.APIViewTestCase):
1403
1422
  "ipam.view_vlangroup",
1404
1423
  "ipam.view_vlan",
1405
1424
  "ipam.add_vlan",
1425
+ "extras.view_status",
1426
+ "extras.view_customfield",
1406
1427
  )
1407
1428
 
1408
1429
  # Create all nine available VLANs with individual requests
@@ -1445,6 +1466,7 @@ class VLANGroupTest(APIViewTestCases.APIViewTestCase):
1445
1466
  "ipam.view_vlangroup",
1446
1467
  "ipam.view_vlan",
1447
1468
  "ipam.add_vlan",
1469
+ "extras.view_status",
1448
1470
  )
1449
1471
 
1450
1472
  # Try to create ten VLANs (only nine are available)
@@ -1492,6 +1514,7 @@ class VLANGroupTest(APIViewTestCases.APIViewTestCase):
1492
1514
  "ipam.view_vlangroup",
1493
1515
  "ipam.view_vlan",
1494
1516
  "ipam.add_vlan",
1517
+ "extras.view_status",
1495
1518
  )
1496
1519
 
1497
1520
  # Try to create VLANs with specified VLAN IDs. Also, explicitly (and redundantly) specify a VLAN Group.
@@ -1562,6 +1585,7 @@ class VLANGroupTest(APIViewTestCases.APIViewTestCase):
1562
1585
  self.add_permissions(
1563
1586
  "ipam.view_vlangroup",
1564
1587
  "ipam.view_vlan",
1588
+ "extras.view_status",
1565
1589
  )
1566
1590
  self.add_permissions("ipam.add_vlan", constraints={"description__startswith": "This is the VLAN created for"})
1567
1591
 
@@ -1609,6 +1633,7 @@ class VLANGroupTest(APIViewTestCases.APIViewTestCase):
1609
1633
  self.add_permissions(
1610
1634
  "ipam.view_vlangroup",
1611
1635
  "ipam.view_vlan",
1636
+ "extras.view_status",
1612
1637
  )
1613
1638
  self.add_permissions("ipam.add_vlan", constraints={"description__startswith": "This is the VLAN created for"})
1614
1639
 
@@ -1714,9 +1739,14 @@ class VLANTest(APIViewTestCases.APIViewTestCase):
1714
1739
  def test_vlan_2_1_api_version_response(self):
1715
1740
  """Assert location can be used in VLAN API create/retrieve."""
1716
1741
 
1717
- self.add_permissions("ipam.view_vlan")
1718
- self.add_permissions("ipam.add_vlan")
1719
- self.add_permissions("ipam.change_vlan")
1742
+ self.add_permissions(
1743
+ "dcim.view_location",
1744
+ "ipam.view_vlan",
1745
+ "ipam.add_vlan",
1746
+ "ipam.change_vlan",
1747
+ "ipam.view_vlangroup",
1748
+ "extras.view_status",
1749
+ )
1720
1750
  with self.subTest("Assert GET"):
1721
1751
  vlan = VLAN.objects.annotate(locations_count=Count("locations")).filter(locations_count=1).first()
1722
1752
  url = reverse("ipam-api:vlan-detail", kwargs={"pk": vlan.pk})
@@ -1878,7 +1908,7 @@ class ServiceTest(APIViewTestCases.APIViewTestCase):
1878
1908
 
1879
1909
  Ref: https://github.com/nautobot/nautobot/issues/265
1880
1910
  """
1881
- self.add_permissions("ipam.add_service")
1911
+ self.add_permissions("ipam.add_service", "dcim.view_device")
1882
1912
  url = reverse("ipam-api:service-list")
1883
1913
  device = self.devices[0]
1884
1914
 
@@ -1108,16 +1108,6 @@ class VRFDeviceAssignmentTestCase(FilterTestCases.FilterTestCase):
1108
1108
  virtual_machine=cls.test_vm_2,
1109
1109
  rd="65000:4",
1110
1110
  )
1111
- VRFDeviceAssignment.objects.create(
1112
- vrf=cls.vrfs[0],
1113
- virtual_device_context=cls.vdcs[0],
1114
- name="VRFDeviceAssignment 1",
1115
- rd="65000:5",
1116
- )
1117
- VRFDeviceAssignment.objects.create(
1118
- vrf=cls.vrfs[0],
1119
- virtual_device_context=cls.vdcs[1],
1120
- )
1121
1111
 
1122
1112
 
1123
1113
  class VLANGroupTestCase(FilterTestCases.FilterTestCase):
@@ -6,6 +6,7 @@ from django.db.models import Count
6
6
  from django.test import override_settings
7
7
  from django.urls import reverse
8
8
  from django.utils.html import strip_tags
9
+ from django.utils.http import urlencode
9
10
  from django.utils.timezone import make_aware
10
11
  from netaddr import IPNetwork
11
12
 
@@ -145,6 +146,25 @@ class RIRTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
145
146
  # Ensure that we have at least one RIR with no prefixes that can be used for the "delete_object" tests.
146
147
  RIR.objects.create(name="RIR XYZ")
147
148
 
149
+ @override_settings(EXEMPT_VIEW_PERMISSIONS=[])
150
+ def test_list_objects_with_permission(self):
151
+ """Test rendering of LinkedCountColumn for related fields without display_field override."""
152
+ response = super().test_list_objects_with_permission()
153
+ response_body = extract_page_body(response.content.decode(response.charset))
154
+
155
+ prefix_list_url = reverse(get_route_for_model(Prefix, "list"))
156
+
157
+ for rir in self._get_queryset().all():
158
+ if str(rir.pk) in response_body:
159
+ count = rir.prefixes.count()
160
+ if count > 1:
161
+ self.assertBodyContains(
162
+ response,
163
+ f'<a href="{prefix_list_url}?{urlencode({"rir": rir.name})}" class="badge">{count}</a>',
164
+ )
165
+ elif count == 1:
166
+ self.assertBodyContains(response, hyperlinked_object(rir.prefixes.first()))
167
+
148
168
 
149
169
  class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.ListObjectsViewTestCase):
150
170
  model = Prefix
@@ -194,7 +214,7 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.List
194
214
 
195
215
  @override_settings(EXEMPT_VIEW_PERMISSIONS=[])
196
216
  def test_list_objects_with_permission(self):
197
- """Test rendering of LinkedCountColumn for related fields."""
217
+ """Test rendering of LinkedCountColumn for related fields with display_field override."""
198
218
  response = super().test_list_objects_with_permission()
199
219
  response_body = extract_page_body(response.content.decode(response.charset))
200
220
 
@@ -208,7 +228,7 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.List
208
228
  response, f'<a href="{locations_list_url}?prefixes={prefix.pk}" class="badge">{count}</a>'
209
229
  )
210
230
  elif count == 1:
211
- self.assertBodyContains(response, hyperlinked_object(prefix.locations.first()))
231
+ self.assertBodyContains(response, hyperlinked_object(prefix.locations.first(), "name"))
212
232
 
213
233
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
214
234
  def test_empty_queryset(self):
@@ -1239,3 +1259,25 @@ class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1239
1259
  }
1240
1260
  response = self.client.post(**request)
1241
1261
  self.assertBodyContains(response, "A service must be associated with either a device or a virtual machine.")
1262
+
1263
+ @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1264
+ def test_port_bulk_edit_invalid(self):
1265
+ self.add_permissions("ipam.change_service")
1266
+ url = self._get_url("bulk_edit")
1267
+ pk_list = list(self._get_queryset().values_list("pk", flat=True)[:3])
1268
+
1269
+ data = {
1270
+ "pk": pk_list,
1271
+ "protocol": ServiceProtocolChoices.PROTOCOL_UDP,
1272
+ "ports": "[106,107]", # String representation of the list
1273
+ "description": "New description",
1274
+ "_apply": True,
1275
+ }
1276
+
1277
+ response = self.client.post(url, data)
1278
+ response_content = response.content.decode(response.charset)
1279
+ self.assertHttpStatus(response, 200)
1280
+ self.assertInHTML(
1281
+ ' <strong class="panel-title">Ports</strong>: <ul class="errorlist"><li>invalid literal for int() with base 10: &#x27;[106&#x27;</li></ul>',
1282
+ response_content,
1283
+ )
nautobot/ipam/urls.py CHANGED
@@ -7,7 +7,6 @@ from . import views
7
7
  from .models import (
8
8
  IPAddress,
9
9
  Prefix,
10
- Service,
11
10
  VLAN,
12
11
  VLANGroup,
13
12
  )
@@ -17,27 +16,12 @@ app_name = "ipam"
17
16
  router = NautobotUIViewSetRouter()
18
17
  router.register("ip-address-to-interface", views.IPAddressToInterfaceUIViewSet)
19
18
  router.register("namespaces", views.NamespaceUIViewSet)
19
+ router.register("rirs", views.RIRUIViewSet)
20
20
  router.register("route-targets", views.RouteTargetUIViewSet)
21
+ router.register("services", views.ServiceUIViewSet)
21
22
  router.register("vrfs", views.VRFUIViewSet)
22
- router.register("rirs", views.RIRUIViewSet)
23
23
 
24
24
  urlpatterns = [
25
- # Namespaces
26
- path(
27
- "namespaces/<uuid:pk>/ip-addresses/",
28
- views.NamespaceIPAddressesView.as_view(),
29
- name="namespace_ipaddresses",
30
- ),
31
- path(
32
- "namespaces/<uuid:pk>/prefixes/",
33
- views.NamespacePrefixesView.as_view(),
34
- name="namespace_prefixes",
35
- ),
36
- path(
37
- "namespaces/<uuid:pk>/vrfs/",
38
- views.NamespaceVRFsView.as_view(),
39
- name="namespace_vrfs",
40
- ),
41
25
  # Prefixes
42
26
  path("prefixes/", views.PrefixListView.as_view(), name="prefix_list"),
43
27
  path("prefixes/add/", views.PrefixEditView.as_view(), name="prefix_add"),
@@ -222,35 +206,6 @@ urlpatterns = [
222
206
  name="vlan_notes",
223
207
  kwargs={"model": VLAN},
224
208
  ),
225
- # Services
226
- path("services/", views.ServiceListView.as_view(), name="service_list"),
227
- path("services/add/", views.ServiceEditView.as_view(), name="service_add"),
228
- path("services/import/", views.ServiceBulkImportView.as_view(), name="service_import"), # 3.0 TODO: remove, unused
229
- path("services/edit/", views.ServiceBulkEditView.as_view(), name="service_bulk_edit"),
230
- path(
231
- "services/delete/",
232
- views.ServiceBulkDeleteView.as_view(),
233
- name="service_bulk_delete",
234
- ),
235
- path("services/<uuid:pk>/", views.ServiceView.as_view(), name="service"),
236
- path("services/<uuid:pk>/edit/", views.ServiceEditView.as_view(), name="service_edit"),
237
- path(
238
- "services/<uuid:pk>/delete/",
239
- views.ServiceDeleteView.as_view(),
240
- name="service_delete",
241
- ),
242
- path(
243
- "services/<uuid:pk>/changelog/",
244
- ObjectChangeLogView.as_view(),
245
- name="service_changelog",
246
- kwargs={"model": Service},
247
- ),
248
- path(
249
- "services/<uuid:pk>/notes/",
250
- ObjectNotesView.as_view(),
251
- name="service_notes",
252
- kwargs={"model": Service},
253
- ),
254
209
  ]
255
210
 
256
211
  urlpatterns += router.urls