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
@@ -0,0 +1,177 @@
1
+ """Utilities for testing IPAM functionality, including data migrations."""
2
+
3
+ import random
4
+
5
+ from django.apps import apps
6
+ from netaddr import IPNetwork
7
+
8
+ # Calculate the probabilities to use for the maybe_subdivide() function defined below.
9
+
10
+ # Frequency of IPv4 (leaf, network) Prefixes by each given mask length in a "realistic" data set.
11
+ # Based loosely on a survey of one large real-world deployment's IP space usage
12
+ FREQUENCY_BY_MASK_LENGTH = [
13
+ 0, # /0
14
+ 0,
15
+ 0,
16
+ 0,
17
+ 0, # /4
18
+ 0,
19
+ 0,
20
+ 0,
21
+ 0, # /8
22
+ 0,
23
+ 0,
24
+ 0,
25
+ 0, # /12
26
+ 1,
27
+ 2,
28
+ 4,
29
+ 16, # /16
30
+ 8,
31
+ 12,
32
+ 16,
33
+ 20, # /20
34
+ 120,
35
+ 150,
36
+ 400,
37
+ 5000, # /24
38
+ 13000,
39
+ 16000,
40
+ 19000,
41
+ 17000, # /28
42
+ 16000,
43
+ 32000,
44
+ 4000,
45
+ 1200, # /32
46
+ ]
47
+
48
+ # Amount of IP space needed at each mask length (frequency at this length, plus the rollup of subdivided nets)
49
+ # Start calculation from the /32 frequency:
50
+ CUMULATIVE_BY_MASK_LENGTH = [FREQUENCY_BY_MASK_LENGTH[-1]]
51
+ # Then work backwards to each parent mask length
52
+ for mask_len in range(len(FREQUENCY_BY_MASK_LENGTH) - 2, -1, -1): # 31, ... 0
53
+ CUMULATIVE_BY_MASK_LENGTH.append(CUMULATIVE_BY_MASK_LENGTH[-1] // 2 + FREQUENCY_BY_MASK_LENGTH[mask_len])
54
+ # Reverse the list to get order by ascending prefix length, same as FREQUENCY_BY_MASK_LENGTH
55
+ CUMULATIVE_BY_MASK_LENGTH.reverse()
56
+
57
+ # Chance to stop subdividing at any given prefix length and create a network Prefix with this length
58
+ CHANCE_TO_STOP = [
59
+ 0 if not cumulative else frequency / cumulative
60
+ for frequency, cumulative in zip(FREQUENCY_BY_MASK_LENGTH, CUMULATIVE_BY_MASK_LENGTH)
61
+ ]
62
+
63
+
64
+ def maybe_subdivide(network):
65
+ """
66
+ Generator for recursively and probabilistically subdividing a network into subnets.
67
+
68
+ Yields:
69
+ IPNetwork: each constructed subdivision of the given network
70
+ """
71
+ if random.random() < CHANCE_TO_STOP[network.prefixlen]: # noqa: S311 # suspicious-non-cryptographic-random-usage
72
+ # Do not subdivide any further
73
+ yield network
74
+ else:
75
+ # Split it into its two child networks and recurse
76
+ subnets = network.subnet(network.prefixlen + 1)
77
+ for subnet in subnets:
78
+ yield from maybe_subdivide(subnet)
79
+
80
+
81
+ def maybe_random_instance(queryset, chance_of_none=0.75):
82
+ """
83
+ Helper function - randomly return either a random instance of the given queryset or None.
84
+ """
85
+ if random.random() < chance_of_none: # noqa: S311 # suspicious-non-cryptographic-random-usage
86
+ return None
87
+ return random.choice(queryset) # noqa: S311 # suspicious-non-cryptographic-random-usage
88
+
89
+
90
+ def create_prefixes_and_ips(initial_subnet: str, apps=apps, seed="Nautobot"): # pylint: disable=redefined-outer-name
91
+ """
92
+ Create many (Nautobot 1.x) Prefix and IPAddress records under a given initial_subnet.
93
+
94
+ The specific records created are pseudo-random (consistent for any given `initial_subnet` and `seed` values),
95
+ but will *in general* consist of about 95% coverage of the subnet by non-overlapping Prefix partitions and about
96
+ 5% coverage of the subnet by individual IPAddress records. Additionally, about 10% of Prefixes and IPAddresses
97
+ respectively will be duplicated one or more times.
98
+
99
+ Args:
100
+ initial_subnet (str): The parent subnet ("10.0.0.0/16") that will encompass the Prefix and IPAddress records.
101
+ apps: Django application registry containing definitions of the (historical) Prefix, IPAddress, etc. models.
102
+ seed: Random generator seed to ensure reproducible pseudo-random construction of the data.
103
+ """
104
+ IPAddress = apps.get_model("ipam", "IPAddress")
105
+ Prefix = apps.get_model("ipam", "Prefix")
106
+ Status = apps.get_model("extras", "Status")
107
+ Tenant = apps.get_model("tenancy", "Tenant")
108
+ VRF = apps.get_model("ipam", "VRF")
109
+
110
+ print(f"Seeding the PRNG with seed {seed}")
111
+ random.seed(seed) # suspicious-non-cryptographic-random-usage
112
+
113
+ status_active, _ = Status.objects.get_or_create(name="Active", defaults={"slug": "active"})
114
+
115
+ for i in range(1, 11):
116
+ Tenant.objects.create(name=f"{initial_subnet} Tenant {i}")
117
+ VRF.objects.create(name=f"{initial_subnet} VRF {i}", enforce_unique=False) # TODO should some enforce_unique?
118
+
119
+ all_tenants = list(Tenant.objects.all())
120
+ all_vrfs = list(VRF.objects.all())
121
+
122
+ print(f"Creating Prefixes to subdivide {initial_subnet}")
123
+ unique_prefix_count = 0
124
+ duplicate_prefix_count = 0
125
+ for subnet in maybe_subdivide(IPNetwork(initial_subnet)):
126
+ if random.random() < 0.95: # noqa: S311 # suspicious-non-cryptographic-random-usage
127
+ # 95% chance to create any given Prefix
128
+ Prefix.objects.create(
129
+ network=str(subnet.network),
130
+ broadcast=str(subnet.broadcast if subnet.broadcast else subnet[-1]),
131
+ prefix_length=subnet.prefixlen,
132
+ status=status_active,
133
+ tenant=maybe_random_instance(all_tenants),
134
+ vrf=maybe_random_instance(all_vrfs),
135
+ )
136
+ unique_prefix_count += 1
137
+ while random.random() < 0.1: # noqa: S311 # suspicious-non-cryptographic-random-usage
138
+ # 10% repeating chance to create a duplicate(s) of this Prefix
139
+ Prefix.objects.create(
140
+ network=str(subnet.network),
141
+ broadcast=str(subnet.broadcast if subnet.broadcast else subnet[-1]),
142
+ prefix_length=subnet.prefixlen,
143
+ status=status_active,
144
+ tenant=maybe_random_instance(all_tenants),
145
+ vrf=maybe_random_instance(all_vrfs),
146
+ )
147
+ duplicate_prefix_count += 1
148
+ print(f"Created {unique_prefix_count} unique Prefixes and {duplicate_prefix_count} duplicates")
149
+
150
+ print(f"Creating IPAddresses within {initial_subnet}")
151
+ unique_ip_count = 0
152
+ duplicate_ip_count = 0
153
+ for ip in IPNetwork(initial_subnet):
154
+ if random.random() < 0.05: # noqa: S311 # suspicious-non-cryptographic-random-usage
155
+ # 5% chance to create any given IP address
156
+ network = IPNetwork(ip)
157
+ IPAddress.objects.create(
158
+ host=str(network.ip),
159
+ broadcast=str(network.broadcast if network.broadcast else network[-1]),
160
+ prefix_length=network.prefixlen,
161
+ status=status_active,
162
+ tenant=maybe_random_instance(all_tenants),
163
+ vrf=maybe_random_instance(all_vrfs),
164
+ )
165
+ unique_ip_count += 1
166
+ while random.random() < 0.1: # noqa: S311 # suspicious-non-cryptographic-random-usage
167
+ # 10% repeating chance to create a duplicate(s) of this IP
168
+ IPAddress.objects.create(
169
+ host=str(network.ip),
170
+ broadcast=str(network.broadcast if network.broadcast else network[-1]),
171
+ prefix_length=network.prefixlen,
172
+ status=status_active,
173
+ tenant=maybe_random_instance(all_tenants),
174
+ vrf=maybe_random_instance(all_vrfs),
175
+ )
176
+ duplicate_ip_count += 1
177
+ print(f"Created {unique_ip_count} unique IPAddresses and {duplicate_ip_count} duplicates")
nautobot/ipam/views.py CHANGED
@@ -16,6 +16,8 @@ from django.utils.http import urlencode
16
16
  from django.views.generic import View
17
17
  from django_tables2 import RequestConfig
18
18
  import netaddr
19
+ from rest_framework.decorators import action
20
+ from rest_framework.response import Response
19
21
 
20
22
  from nautobot.cloud.tables import CloudNetworkTable
21
23
  from nautobot.core.constants import MAX_PAGE_SIZE_DEFAULT
@@ -63,27 +65,7 @@ logger = logging.getLogger(__name__)
63
65
  #
64
66
 
65
67
 
66
- def get_namespace_related_counts(instance, request):
67
- """Return counts of all IPAM objects related to the given Namespace."""
68
- return {
69
- "vrf_count": instance.vrfs.restrict(request.user, "view").count(),
70
- "prefix_count": instance.prefixes.restrict(request.user, "view").count(),
71
- "ip_address_count": instance.ip_addresses.restrict(request.user, "view").count(),
72
- }
73
-
74
-
75
- class NamespaceUIViewSet(
76
- view_mixins.ObjectDetailViewMixin,
77
- view_mixins.ObjectListViewMixin,
78
- view_mixins.ObjectEditViewMixin,
79
- view_mixins.ObjectDestroyViewMixin,
80
- view_mixins.ObjectChangeLogViewMixin,
81
- view_mixins.ObjectBulkCreateViewMixin, # 3.0 TODO: remove, no longer used
82
- view_mixins.ObjectBulkDestroyViewMixin,
83
- view_mixins.ObjectBulkUpdateViewMixin,
84
- view_mixins.ObjectNotesViewMixin,
85
- ):
86
- lookup_field = "pk"
68
+ class NamespaceUIViewSet(NautobotUIViewSet):
87
69
  form_class = forms.NamespaceForm
88
70
  bulk_update_form_class = forms.NamespaceBulkEditForm
89
71
  filterset_class = filters.NamespaceFilterSet
@@ -91,134 +73,95 @@ class NamespaceUIViewSet(
91
73
  queryset = Namespace.objects.all()
92
74
  serializer_class = serializers.NamespaceSerializer
93
75
  table_class = tables.NamespaceTable
76
+ object_detail_content = object_detail.ObjectDetailContent(
77
+ panels=(object_detail.ObjectFieldsPanel(section=SectionChoices.LEFT_HALF, weight=100, fields="__all__"),),
78
+ extra_tabs=(
79
+ object_detail.DistinctViewTab(
80
+ weight=800,
81
+ tab_id="vrfs",
82
+ label="VRFs",
83
+ url_name="ipam:namespace_vrfs",
84
+ related_object_attribute="vrfs",
85
+ ),
86
+ object_detail.DistinctViewTab(
87
+ weight=900,
88
+ tab_id="prefixes",
89
+ label="Prefixes",
90
+ url_name="ipam:namespace_prefixes",
91
+ related_object_attribute="prefixes",
92
+ ),
93
+ object_detail.DistinctViewTab(
94
+ weight=1000,
95
+ tab_id="ip_addresses",
96
+ label="IP Addresses",
97
+ url_name="ipam:namespace_ip_addresses",
98
+ related_object_attribute="ip_addresses",
99
+ ),
100
+ ),
101
+ )
94
102
 
95
103
  def get_extra_context(self, request, instance):
96
104
  context = super().get_extra_context(request, instance)
97
-
98
- if self.action == "retrieve":
99
- context.update(get_namespace_related_counts(instance, request))
100
-
105
+ context.update({"object_detail_content": self.object_detail_content})
101
106
  return context
102
107
 
108
+ @action(detail=True, url_path="vrfs")
109
+ def vrfs(self, request, *args, **kwargs):
110
+ instance = self.get_object()
111
+ vrfs = instance.vrfs.restrict(request.user, "view")
112
+ vrf_table = tables.VRFTable(
113
+ data=vrfs,
114
+ user=request.user,
115
+ exclude=["namespace"],
116
+ )
117
+ if request.user.has_perm("ipam.change_vrf") or request.user.has_perm("ipam.delete_vrf"):
118
+ vrf_table.columns.show("pk")
103
119
 
104
- class NamespaceIPAddressesView(generic.ObjectView):
105
- queryset = Namespace.objects.all()
106
- template_name = "ipam/namespace_ipaddresses.html"
107
-
108
- def get_extra_context(self, request, instance):
109
- # Find all IPAddresses belonging to this Namespace
110
- ip_addresses = instance.ip_addresses.restrict(request.user, "view").select_related("role", "status", "tenant")
111
-
112
- ip_address_table = tables.IPAddressTable(ip_addresses, exclude=["namespace"])
113
- if request.user.has_perm("ipam.change_ipaddress") or request.user.has_perm("ipam.delete_ipaddress"):
114
- ip_address_table.columns.show("pk")
115
-
116
- paginate = {
117
- "paginator_class": EnhancedPaginator,
118
- "per_page": get_paginate_count(request),
119
- }
120
- RequestConfig(request, paginate).configure(ip_address_table)
121
-
122
- # Compile permissions list for rendering the object table
123
- permissions = {
124
- "add": request.user.has_perm("ipam.add_ipaddress"),
125
- "change": request.user.has_perm("ipam.change_ipaddress"),
126
- "delete": request.user.has_perm("ipam.delete_ipaddress"),
127
- }
128
- bulk_querystring = f"namespace={instance.id}"
129
-
130
- context = super().get_extra_context(request, instance)
131
- context.update(
120
+ RequestConfig(
121
+ request, paginate={"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
122
+ ).configure(vrf_table)
123
+ return Response(
132
124
  {
133
- "ip_address_table": ip_address_table,
134
- "permissions": permissions,
135
- "bulk_querystring": bulk_querystring,
136
- "active_tab": "ip-addresses",
125
+ "vrf_table": vrf_table,
126
+ "active_tab": "vrfs",
137
127
  }
138
128
  )
139
- context.update(get_namespace_related_counts(instance, request))
140
-
141
- return context
142
-
143
-
144
- class NamespacePrefixesView(generic.ObjectView):
145
- queryset = Namespace.objects.all()
146
- template_name = "ipam/namespace_prefixes.html"
147
129
 
148
- def get_extra_context(self, request, instance):
149
- # Find all Prefixes belonging to this Namespace
130
+ @action(detail=True, url_path="prefixes")
131
+ def prefixes(self, request, *args, **kwargs):
132
+ instance = self.get_object()
150
133
  prefixes = instance.prefixes.restrict(request.user, "view").select_related("status")
151
-
152
- prefix_table = tables.PrefixTable(prefixes, exclude=["namespace"])
134
+ prefix_table = tables.PrefixTable(data=prefixes, user=request.user, exclude=["namespace"])
153
135
  if request.user.has_perm("ipam.change_prefix") or request.user.has_perm("ipam.delete_prefix"):
154
136
  prefix_table.columns.show("pk")
155
137
 
156
- paginate = {
157
- "paginator_class": EnhancedPaginator,
158
- "per_page": get_paginate_count(request),
159
- }
160
- RequestConfig(request, paginate).configure(prefix_table)
161
-
162
- # Compile permissions list for rendering the object table
163
- permissions = {
164
- "add": request.user.has_perm("ipam.add_prefix"),
165
- "change": request.user.has_perm("ipam.change_prefix"),
166
- "delete": request.user.has_perm("ipam.delete_prefix"),
167
- }
168
- bulk_querystring = f"namespace={instance.id}"
169
-
170
- context = super().get_extra_context(request, instance)
171
- context.update(
138
+ RequestConfig(
139
+ request, paginate={"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
140
+ ).configure(prefix_table)
141
+ return Response(
172
142
  {
173
143
  "prefix_table": prefix_table,
174
- "permissions": permissions,
175
- "bulk_querystring": bulk_querystring,
176
144
  "active_tab": "prefixes",
177
145
  }
178
146
  )
179
- context.update(get_namespace_related_counts(instance, request))
180
-
181
- return context
182
-
183
-
184
- class NamespaceVRFsView(generic.ObjectView):
185
- queryset = Namespace.objects.all()
186
- template_name = "ipam/namespace_vrfs.html"
187
-
188
- def get_extra_context(self, request, instance):
189
- # Find all VRFs belonging to this Namespace
190
- vrfs = instance.vrfs.restrict(request.user, "view")
191
-
192
- vrf_table = tables.VRFTable(vrfs, exclude=["namespace"])
193
- if request.user.has_perm("ipam.change_vrf") or request.user.has_perm("ipam.delete_vrf"):
194
- vrf_table.columns.show("pk")
195
147
 
196
- paginate = {
197
- "paginator_class": EnhancedPaginator,
198
- "per_page": get_paginate_count(request),
199
- }
200
- RequestConfig(request, paginate).configure(vrf_table)
201
-
202
- # Compile permissions list for rendering the object table
203
- permissions = {
204
- "add": request.user.has_perm("ipam.add_vrf"),
205
- "change": request.user.has_perm("ipam.change_vrf"),
206
- "delete": request.user.has_perm("ipam.delete_vrf"),
207
- }
208
- bulk_querystring = f"namespace={instance.id}"
148
+ @action(detail=True, url_path="ip-addresses", url_name="ip_addresses")
149
+ def ip_addresses(self, request, *args, **kwargs):
150
+ instance = self.get_object()
151
+ ip_addresses = instance.ip_addresses.restrict(request.user, "view").select_related("role", "status", "tenant")
152
+ ip_address_table = tables.IPAddressTable(data=ip_addresses, user=request.user, exclude=["namespace"])
153
+ if request.user.has_perm("ipam.change_ipaddress") or request.user.has_perm("ipam.delete_ipaddress"):
154
+ ip_address_table.columns.show("pk")
209
155
 
210
- context = super().get_extra_context(request, instance)
211
- context.update(
156
+ RequestConfig(
157
+ request, paginate={"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
158
+ ).configure(ip_address_table)
159
+ return Response(
212
160
  {
213
- "vrf_table": vrf_table,
214
- "permissions": permissions,
215
- "bulk_querystring": bulk_querystring,
216
- "active_tab": "vrfs",
161
+ "ip_address_table": ip_address_table,
162
+ "active_tab": "ip_addresses",
217
163
  }
218
164
  )
219
- context.update(get_namespace_related_counts(instance, request))
220
-
221
- return context
222
165
 
223
166
 
224
167
  #
@@ -1356,19 +1299,7 @@ class VLANBulkDeleteView(generic.BulkDeleteView):
1356
1299
  #
1357
1300
 
1358
1301
 
1359
- class ServiceListView(generic.ObjectListView):
1360
- queryset = Service.objects.all()
1361
- filterset = filters.ServiceFilterSet
1362
- filterset_form = forms.ServiceFilterForm
1363
- table = tables.ServiceTable
1364
- action_buttons = ("add", "import", "export")
1365
-
1366
-
1367
- class ServiceView(generic.ObjectView):
1368
- queryset = Service.objects.prefetch_related("ip_addresses")
1369
-
1370
-
1371
- class ServiceEditView(generic.ObjectEditView):
1302
+ class ServiceEditView(generic.ObjectEditView): # This view is used to assign services to devices and VMs
1372
1303
  queryset = Service.objects.prefetch_related("ip_addresses")
1373
1304
  model_form = forms.ServiceForm
1374
1305
  template_name = "ipam/service_edit.html"
@@ -1384,23 +1315,30 @@ class ServiceEditView(generic.ObjectEditView):
1384
1315
  return obj
1385
1316
 
1386
1317
 
1387
- class ServiceBulkImportView(generic.BulkImportView): # 3.0 TODO: remove, unused
1388
- queryset = Service.objects.all()
1389
- table = tables.ServiceTable
1390
-
1391
-
1392
- class ServiceDeleteView(generic.ObjectDeleteView):
1393
- queryset = Service.objects.all()
1394
-
1395
-
1396
- class ServiceBulkEditView(generic.BulkEditView):
1397
- queryset = Service.objects.select_related("device", "virtual_machine")
1398
- filterset = filters.ServiceFilterSet
1399
- table = tables.ServiceTable
1400
- form = forms.ServiceBulkEditForm
1401
-
1318
+ class ServiceUIViewSet(NautobotUIViewSet): # 3.0 TODO: remove, unused BulkImportView
1319
+ model = Service
1320
+ bulk_update_form_class = forms.ServiceBulkEditForm
1321
+ filterset_class = filters.ServiceFilterSet
1322
+ filterset_form_class = forms.ServiceFilterForm
1323
+ form_class = forms.ServiceForm
1324
+ queryset = Service.objects.select_related("device", "virtual_machine").prefetch_related("ip_addresses")
1325
+ serializer_class = serializers.ServiceSerializer
1326
+ table_class = tables.ServiceTable
1402
1327
 
1403
- class ServiceBulkDeleteView(generic.BulkDeleteView):
1404
- queryset = Service.objects.select_related("device", "virtual_machine")
1405
- filterset = filters.ServiceFilterSet
1406
- table = tables.ServiceTable
1328
+ object_detail_content = object_detail.ObjectDetailContent(
1329
+ panels=(
1330
+ object_detail.ObjectFieldsPanel(
1331
+ section=SectionChoices.LEFT_HALF,
1332
+ weight=100,
1333
+ fields=["name", "parent", "protocol", "port_list", "description"],
1334
+ ),
1335
+ object_detail.ObjectsTablePanel(
1336
+ weight=200,
1337
+ section=SectionChoices.RIGHT_HALF,
1338
+ table_class=tables.IPAddressTable,
1339
+ table_filter="services",
1340
+ select_related_fields=["tenant", "status", "role"],
1341
+ add_button_route=None,
1342
+ ),
1343
+ )
1344
+ )
@@ -890,6 +890,11 @@ td span.hover_copy:hover .hover_copy_button {
890
890
  cursor: move;
891
891
  }
892
892
 
893
+ /* Make text in homepage panels selectable */
894
+ #draggable-homepage-panels .list-group-item {
895
+ user-select: text !important;
896
+ }
897
+
893
898
  /* Make panel being dragged opaque */
894
899
  .dragging {
895
900
  opacity: 0.5;
@@ -9171,8 +9171,6 @@
9171
9171
 
9172
9172
  <script src="/projects/core/en/stable/assets/javascripts/bundle.60a45f97.min.js"></script>
9173
9173
 
9174
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9175
-
9176
9174
 
9177
9175
  </body>
9178
9176
  </html>
@@ -9338,8 +9338,6 @@
9338
9338
 
9339
9339
  <script src="../assets/javascripts/bundle.60a45f97.min.js"></script>
9340
9340
 
9341
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9342
-
9343
9341
 
9344
9342
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
9345
9343
  document$.subscribe(() => { lightbox.reload() });
@@ -9271,8 +9271,6 @@
9271
9271
 
9272
9272
  <script src="../assets/javascripts/bundle.60a45f97.min.js"></script>
9273
9273
 
9274
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9275
-
9276
9274
 
9277
9275
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
9278
9276
  document$.subscribe(() => { lightbox.reload() });
@@ -9539,8 +9539,6 @@ Relationships, etc.</p>
9539
9539
 
9540
9540
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
9541
9541
 
9542
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9543
-
9544
9542
 
9545
9543
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
9546
9544
  document$.subscribe(() => { lightbox.reload() });
@@ -9407,8 +9407,6 @@
9407
9407
 
9408
9408
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
9409
9409
 
9410
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9411
-
9412
9410
 
9413
9411
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
9414
9412
  document$.subscribe(() => { lightbox.reload() });
@@ -13563,8 +13563,6 @@ data any serializer fields that do not correspond to a specific model field</p>
13563
13563
 
13564
13564
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
13565
13565
 
13566
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
13567
-
13568
13566
 
13569
13567
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
13570
13568
  document$.subscribe(() => { lightbox.reload() });
@@ -9839,8 +9839,6 @@ with web_request_context(user, context_detail="manual-fix"):
9839
9839
 
9840
9840
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
9841
9841
 
9842
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9843
-
9844
9842
 
9845
9843
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
9846
9844
  document$.subscribe(() => { lightbox.reload() });
@@ -9924,8 +9924,6 @@ is equivalent to a Celery task state.</p>
9924
9924
 
9925
9925
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
9926
9926
 
9927
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9928
-
9929
9927
 
9930
9928
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
9931
9929
  document$.subscribe(() => { lightbox.reload() });
@@ -9382,8 +9382,6 @@ and will generate warning logs.</p>
9382
9382
 
9383
9383
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
9384
9384
 
9385
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9386
-
9387
9385
 
9388
9386
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
9389
9387
  document$.subscribe(() => { lightbox.reload() });
@@ -9307,8 +9307,6 @@
9307
9307
 
9308
9308
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
9309
9309
 
9310
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9311
-
9312
9310
 
9313
9311
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
9314
9312
  document$.subscribe(() => { lightbox.reload() });
@@ -9586,8 +9586,6 @@ Returns:
9586
9586
 
9587
9587
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
9588
9588
 
9589
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9590
-
9591
9589
 
9592
9590
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
9593
9591
  document$.subscribe(() => { lightbox.reload() });
@@ -9949,8 +9949,6 @@ EventBrokers, then call <code>register_event_broker()</code> for each one, as pa
9949
9949
 
9950
9950
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
9951
9951
 
9952
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9953
-
9954
9952
 
9955
9953
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
9956
9954
  document$.subscribe(() => { lightbox.reload() });
@@ -9797,8 +9797,6 @@ would trigger this exception upon access.</p>
9797
9797
 
9798
9798
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
9799
9799
 
9800
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9801
-
9802
9800
 
9803
9801
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
9804
9802
  document$.subscribe(() => { lightbox.reload() });
@@ -10045,8 +10045,6 @@ status = random_instance(lambda: Status.objects.get_for_model(Object), allow_nul
10045
10045
 
10046
10046
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
10047
10047
 
10048
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
10049
-
10050
10048
 
10051
10049
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
10052
10050
  document$.subscribe(() => { lightbox.reload() });
@@ -11539,8 +11539,6 @@ filter values while maintaining the field's built-in validation. Example: GET /a
11539
11539
 
11540
11540
  <script src="../../../assets/javascripts/bundle.60a45f97.min.js"></script>
11541
11541
 
11542
- <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
11543
-
11544
11542
 
11545
11543
  <script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
11546
11544
  document$.subscribe(() => { lightbox.reload() });