nautobot 2.4.0b1__py3-none-any.whl → 2.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nautobot might be problematic. Click here for more details.

Files changed (601) hide show
  1. nautobot/apps/__init__.py +1 -1
  2. nautobot/apps/api.py +8 -8
  3. nautobot/apps/change_logging.py +2 -2
  4. nautobot/apps/choices.py +4 -4
  5. nautobot/apps/events.py +3 -3
  6. nautobot/apps/factory.py +2 -2
  7. nautobot/apps/filters.py +1 -1
  8. nautobot/apps/forms.py +20 -20
  9. nautobot/apps/graphql.py +2 -2
  10. nautobot/apps/jobs.py +8 -8
  11. nautobot/apps/models.py +19 -19
  12. nautobot/apps/tables.py +1 -1
  13. nautobot/apps/testing.py +10 -10
  14. nautobot/apps/ui.py +2 -2
  15. nautobot/apps/utils.py +7 -7
  16. nautobot/apps/views.py +7 -7
  17. nautobot/circuits/api/serializers.py +1 -0
  18. nautobot/circuits/api/views.py +4 -8
  19. nautobot/circuits/tables.py +2 -1
  20. nautobot/circuits/templates/circuits/circuit_create.html +1 -7
  21. nautobot/circuits/views.py +3 -3
  22. nautobot/cloud/api/views.py +6 -10
  23. nautobot/cloud/models.py +1 -1
  24. nautobot/cloud/views.py +0 -16
  25. nautobot/core/api/constants.py +11 -0
  26. nautobot/core/api/fields.py +5 -5
  27. nautobot/core/api/filter_backends.py +3 -9
  28. nautobot/core/api/schema.py +13 -2
  29. nautobot/core/api/serializers.py +40 -34
  30. nautobot/core/api/views.py +56 -4
  31. nautobot/core/celery/log.py +4 -4
  32. nautobot/core/celery/schedulers.py +2 -2
  33. nautobot/core/choices.py +2 -2
  34. nautobot/core/events/__init__.py +3 -3
  35. nautobot/core/filters.py +67 -35
  36. nautobot/core/forms/__init__.py +19 -19
  37. nautobot/core/forms/fields.py +14 -11
  38. nautobot/core/forms/forms.py +33 -2
  39. nautobot/core/graphql/types.py +1 -1
  40. nautobot/core/jobs/__init__.py +28 -7
  41. nautobot/core/jobs/bulk_actions.py +285 -0
  42. nautobot/core/jobs/cleanup.py +48 -12
  43. nautobot/core/jobs/groups.py +1 -1
  44. nautobot/core/management/commands/validate_models.py +1 -1
  45. nautobot/core/models/__init__.py +3 -1
  46. nautobot/core/models/query_functions.py +2 -2
  47. nautobot/core/models/tree_queries.py +6 -3
  48. nautobot/core/settings.py +29 -2
  49. nautobot/core/settings.yaml +21 -0
  50. nautobot/core/tables.py +79 -61
  51. nautobot/core/templates/about.html +67 -0
  52. nautobot/core/templates/inc/media.html +3 -0
  53. nautobot/core/templates/inc/nav_menu.html +1 -0
  54. nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
  55. nautobot/core/templates/inc/tenant_table_row.html +11 -0
  56. nautobot/core/templates/nautobot_config.py.j2 +13 -0
  57. nautobot/core/templates/search.html +7 -0
  58. nautobot/core/templates/utilities/render_jinja2.html +1 -1
  59. nautobot/core/templates/utilities/templatetags/tag.html +1 -1
  60. nautobot/core/templates/utilities/theme_preview.html +7 -0
  61. nautobot/core/templatetags/helpers.py +11 -2
  62. nautobot/core/testing/__init__.py +8 -8
  63. nautobot/core/testing/api.py +170 -15
  64. nautobot/core/testing/filters.py +45 -10
  65. nautobot/core/testing/forms.py +2 -0
  66. nautobot/core/testing/integration.py +86 -4
  67. nautobot/core/testing/mixins.py +7 -2
  68. nautobot/core/testing/views.py +44 -29
  69. nautobot/core/tests/integration/test_app_home.py +0 -1
  70. nautobot/core/tests/integration/test_app_navbar.py +0 -1
  71. nautobot/core/tests/integration/test_filters.py +0 -2
  72. nautobot/core/tests/integration/test_home.py +0 -1
  73. nautobot/core/tests/integration/test_navbar.py +0 -1
  74. nautobot/core/tests/integration/test_view_authentication.py +1 -0
  75. nautobot/core/tests/runner.py +1 -1
  76. nautobot/core/tests/test_api.py +98 -1
  77. nautobot/core/tests/test_csv.py +25 -3
  78. nautobot/core/tests/test_filters.py +209 -246
  79. nautobot/core/tests/test_forms.py +1 -0
  80. nautobot/core/tests/test_jobs.py +460 -1
  81. nautobot/core/tests/test_models.py +9 -0
  82. nautobot/core/tests/test_settings_schema.py +7 -0
  83. nautobot/core/tests/test_tables.py +100 -0
  84. nautobot/core/tests/test_utils.py +63 -1
  85. nautobot/core/tests/test_views.py +30 -3
  86. nautobot/core/ui/nav.py +1 -0
  87. nautobot/core/ui/object_detail.py +15 -1
  88. nautobot/core/urls.py +11 -0
  89. nautobot/core/utils/lookup.py +11 -8
  90. nautobot/core/utils/querysets.py +64 -0
  91. nautobot/core/utils/requests.py +24 -9
  92. nautobot/core/views/__init__.py +42 -0
  93. nautobot/core/views/generic.py +131 -197
  94. nautobot/core/views/mixins.py +126 -38
  95. nautobot/core/views/renderers.py +6 -6
  96. nautobot/dcim/api/serializers.py +56 -64
  97. nautobot/dcim/api/views.py +47 -113
  98. nautobot/dcim/constants.py +6 -13
  99. nautobot/dcim/factory.py +6 -1
  100. nautobot/dcim/filters/__init__.py +31 -2
  101. nautobot/dcim/forms.py +36 -17
  102. nautobot/dcim/graphql/types.py +2 -2
  103. nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
  104. nautobot/dcim/models/__init__.py +1 -1
  105. nautobot/dcim/models/device_component_templates.py +2 -2
  106. nautobot/dcim/models/device_components.py +22 -20
  107. nautobot/dcim/models/devices.py +10 -1
  108. nautobot/dcim/models/locations.py +3 -3
  109. nautobot/dcim/models/power.py +6 -5
  110. nautobot/dcim/models/racks.py +4 -4
  111. nautobot/dcim/tables/__init__.py +3 -3
  112. nautobot/dcim/tables/devices.py +7 -5
  113. nautobot/dcim/tables/devicetypes.py +2 -2
  114. nautobot/dcim/tables/racks.py +1 -1
  115. nautobot/dcim/templates/dcim/controller_create.html +1 -7
  116. nautobot/dcim/templates/dcim/controller_retrieve.html +1 -9
  117. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +2 -0
  118. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +5 -0
  119. nautobot/dcim/templates/dcim/device.html +1 -9
  120. nautobot/dcim/templates/dcim/device_edit.html +36 -37
  121. nautobot/dcim/templates/dcim/location.html +1 -9
  122. nautobot/dcim/templates/dcim/location_edit.html +1 -7
  123. nautobot/dcim/templates/dcim/rack.html +1 -9
  124. nautobot/dcim/templates/dcim/rack_edit.html +1 -7
  125. nautobot/dcim/templates/dcim/rackreservation.html +1 -9
  126. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -9
  127. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +1 -7
  128. nautobot/dcim/tests/integration/test_controller.py +62 -0
  129. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
  130. nautobot/dcim/tests/integration/test_device_bulk_delete.py +189 -0
  131. nautobot/dcim/tests/integration/test_device_bulk_edit.py +181 -0
  132. nautobot/dcim/tests/test_api.py +16 -5
  133. nautobot/dcim/tests/test_filters.py +33 -0
  134. nautobot/dcim/tests/test_forms.py +51 -2
  135. nautobot/dcim/tests/test_graphql.py +52 -0
  136. nautobot/dcim/tests/test_jobs.py +118 -0
  137. nautobot/dcim/tests/test_models.py +52 -9
  138. nautobot/dcim/tests/test_views.py +21 -83
  139. nautobot/dcim/views.py +1 -13
  140. nautobot/extras/api/customfields.py +2 -2
  141. nautobot/extras/api/serializers.py +90 -85
  142. nautobot/extras/api/views.py +22 -27
  143. nautobot/extras/constants.py +2 -0
  144. nautobot/extras/filters/__init__.py +8 -6
  145. nautobot/extras/forms/base.py +2 -2
  146. nautobot/extras/forms/forms.py +139 -31
  147. nautobot/extras/forms/mixins.py +14 -6
  148. nautobot/extras/group_sync.py +3 -3
  149. nautobot/extras/health_checks.py +1 -2
  150. nautobot/extras/jobs.py +85 -18
  151. nautobot/extras/managers.py +3 -1
  152. nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
  153. nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
  154. nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
  155. nautobot/extras/models/__init__.py +1 -1
  156. nautobot/extras/models/contacts.py +1 -1
  157. nautobot/extras/models/customfields.py +12 -11
  158. nautobot/extras/models/groups.py +11 -9
  159. nautobot/extras/models/jobs.py +23 -4
  160. nautobot/extras/models/models.py +2 -2
  161. nautobot/extras/plugins/__init__.py +13 -2
  162. nautobot/extras/plugins/marketplace_manifest.yml +84 -79
  163. nautobot/extras/plugins/tables.py +16 -14
  164. nautobot/extras/plugins/views.py +65 -69
  165. nautobot/extras/registry.py +1 -1
  166. nautobot/extras/secrets/__init__.py +2 -2
  167. nautobot/extras/tables.py +7 -5
  168. nautobot/extras/templates/extras/dynamicgroup.html +1 -9
  169. nautobot/extras/templates/extras/job_detail.html +16 -0
  170. nautobot/extras/templates/extras/job_edit.html +1 -0
  171. nautobot/extras/templates/extras/jobqueue_retrieve.html +1 -9
  172. nautobot/extras/templates/extras/marketplace.html +29 -11
  173. nautobot/extras/templates/extras/plugin_detail.html +32 -15
  174. nautobot/extras/templates/extras/plugins_tiles.html +21 -10
  175. nautobot/extras/templatetags/job_buttons.py +4 -4
  176. nautobot/extras/test_jobs/api_test_job.py +1 -1
  177. nautobot/extras/test_jobs/atomic_transaction.py +2 -2
  178. nautobot/extras/test_jobs/dry_run.py +1 -1
  179. nautobot/extras/test_jobs/fail.py +5 -5
  180. nautobot/extras/test_jobs/file_output.py +1 -1
  181. nautobot/extras/test_jobs/file_upload_fail.py +1 -1
  182. nautobot/extras/test_jobs/file_upload_pass.py +1 -1
  183. nautobot/extras/test_jobs/ipaddress_vars.py +3 -1
  184. nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
  185. nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
  186. nautobot/extras/test_jobs/log_redaction.py +1 -1
  187. nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
  188. nautobot/extras/test_jobs/modify_db.py +1 -1
  189. nautobot/extras/test_jobs/object_var_optional.py +1 -1
  190. nautobot/extras/test_jobs/object_var_required.py +1 -1
  191. nautobot/extras/test_jobs/object_vars.py +1 -1
  192. nautobot/extras/test_jobs/pass.py +3 -3
  193. nautobot/extras/test_jobs/profiling.py +1 -1
  194. nautobot/extras/test_jobs/relative_import.py +3 -3
  195. nautobot/extras/test_jobs/singleton.py +16 -0
  196. nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
  197. nautobot/extras/test_jobs/task_queues.py +1 -1
  198. nautobot/extras/tests/integration/test_plugin_banner.py +0 -2
  199. nautobot/extras/tests/test_api.py +13 -13
  200. nautobot/extras/tests/test_customfields.py +1 -1
  201. nautobot/extras/tests/test_datasources.py +2 -1
  202. nautobot/extras/tests/test_dynamicgroups.py +1 -1
  203. nautobot/extras/tests/test_filters.py +6 -6
  204. nautobot/extras/tests/test_forms.py +33 -1
  205. nautobot/extras/tests/test_jobs.py +178 -32
  206. nautobot/extras/tests/test_models.py +16 -10
  207. nautobot/extras/tests/test_plugins.py +62 -9
  208. nautobot/extras/tests/test_relationships.py +120 -9
  209. nautobot/extras/tests/test_views.py +56 -194
  210. nautobot/extras/utils.py +3 -2
  211. nautobot/extras/views.py +30 -98
  212. nautobot/ipam/api/fields.py +3 -3
  213. nautobot/ipam/api/serializers.py +41 -33
  214. nautobot/ipam/api/views.py +68 -117
  215. nautobot/ipam/factory.py +1 -1
  216. nautobot/ipam/filters.py +3 -2
  217. nautobot/ipam/lookups.py +101 -62
  218. nautobot/ipam/models.py +66 -16
  219. nautobot/ipam/querysets.py +2 -2
  220. nautobot/ipam/tables.py +23 -7
  221. nautobot/ipam/templates/ipam/ipaddress.html +1 -9
  222. nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
  223. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
  224. nautobot/ipam/templates/ipam/prefix.html +1 -9
  225. nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
  226. nautobot/ipam/templates/ipam/vlan.html +1 -9
  227. nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
  228. nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
  229. nautobot/ipam/tests/test_api.py +436 -3
  230. nautobot/ipam/tests/test_forms.py +49 -47
  231. nautobot/ipam/tests/test_migrations.py +30 -30
  232. nautobot/ipam/tests/test_models.py +95 -34
  233. nautobot/ipam/tests/test_querysets.py +63 -1
  234. nautobot/ipam/tests/test_views.py +3 -0
  235. nautobot/ipam/utils/__init__.py +36 -6
  236. nautobot/ipam/views.py +61 -87
  237. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
  238. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
  239. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
  240. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
  241. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
  242. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
  243. nautobot/project-static/docs/404.html +46 -4
  244. nautobot/project-static/docs/apps/index.html +46 -4
  245. nautobot/project-static/docs/apps/nautobot-apps.html +47 -6
  246. nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
  247. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js → bundle.88dd0f4e.min.js} +2 -2
  248. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js.map → bundle.88dd0f4e.min.js.map} +2 -2
  249. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +62 -10
  250. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +59 -7
  251. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +374 -122
  252. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +90 -18
  253. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +95 -21
  254. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +53 -6
  255. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +52 -5
  256. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +79 -17
  257. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +102 -28
  258. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +108 -21
  259. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +131 -38
  260. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +239 -65
  261. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +581 -165
  262. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +109 -36
  263. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +453 -167
  264. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +493 -211
  265. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +60 -8
  266. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +71 -15
  267. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +407 -55
  268. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +620 -205
  269. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +858 -412
  270. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +59 -7
  271. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +448 -186
  272. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +365 -147
  273. nautobot/project-static/docs/development/apps/api/configuration-view.html +46 -4
  274. nautobot/project-static/docs/development/apps/api/database-backend-config.html +46 -4
  275. nautobot/project-static/docs/development/apps/api/models/django-admin.html +46 -4
  276. nautobot/project-static/docs/development/apps/api/models/global-search.html +46 -4
  277. nautobot/project-static/docs/development/apps/api/models/graphql.html +46 -4
  278. nautobot/project-static/docs/development/apps/api/models/index.html +46 -4
  279. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +46 -4
  280. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +46 -4
  281. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +46 -4
  282. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +46 -4
  283. nautobot/project-static/docs/development/apps/api/platform-features/index.html +46 -4
  284. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +46 -4
  285. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +46 -4
  286. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +46 -4
  287. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +46 -4
  288. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +68 -7
  289. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +46 -4
  290. nautobot/project-static/docs/development/apps/api/prometheus.html +46 -4
  291. nautobot/project-static/docs/development/apps/api/setup.html +46 -4
  292. nautobot/project-static/docs/development/apps/api/testing.html +46 -4
  293. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +46 -4
  294. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +46 -4
  295. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +46 -4
  296. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +46 -4
  297. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +46 -4
  298. nautobot/project-static/docs/development/apps/api/views/base-template.html +46 -4
  299. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +46 -4
  300. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +46 -4
  301. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +46 -4
  302. nautobot/project-static/docs/development/apps/api/views/index.html +46 -4
  303. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +46 -4
  304. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +46 -4
  305. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +46 -4
  306. nautobot/project-static/docs/development/apps/api/views/notes.html +46 -4
  307. nautobot/project-static/docs/development/apps/api/views/rest-api.html +52 -6
  308. nautobot/project-static/docs/development/apps/api/views/urls.html +46 -4
  309. nautobot/project-static/docs/development/apps/index.html +46 -4
  310. nautobot/project-static/docs/development/apps/migration/code-updates.html +46 -4
  311. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +46 -4
  312. nautobot/project-static/docs/development/apps/migration/from-v1.html +46 -4
  313. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +46 -4
  314. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +46 -4
  315. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +46 -4
  316. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +46 -4
  317. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +50 -8
  318. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +46 -4
  319. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +211 -14
  320. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +46 -4
  321. nautobot/project-static/docs/development/apps/porting-from-netbox.html +46 -4
  322. nautobot/project-static/docs/development/core/application-registry.html +46 -4
  323. nautobot/project-static/docs/development/core/best-practices.html +46 -4
  324. nautobot/project-static/docs/development/core/bootstrap-ui.html +46 -4
  325. nautobot/project-static/docs/development/core/caching.html +46 -4
  326. nautobot/project-static/docs/development/core/controllers.html +46 -4
  327. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +73 -74
  328. nautobot/project-static/docs/development/core/generic-views.html +46 -4
  329. nautobot/project-static/docs/development/core/getting-started.html +249 -224
  330. nautobot/project-static/docs/development/core/homepage.html +49 -7
  331. nautobot/project-static/docs/development/core/index.html +46 -4
  332. nautobot/project-static/docs/development/core/{local-k8s.html → minikube-dev-environment-for-k8s-jobs.html} +469 -168
  333. nautobot/project-static/docs/development/core/model-checklist.html +56 -12
  334. nautobot/project-static/docs/development/core/model-features.html +46 -4
  335. nautobot/project-static/docs/development/core/natural-keys.html +46 -4
  336. nautobot/project-static/docs/development/core/navigation-menu.html +46 -4
  337. nautobot/project-static/docs/development/core/release-checklist.html +49 -7
  338. nautobot/project-static/docs/development/core/role-internals.html +46 -4
  339. nautobot/project-static/docs/development/core/settings.html +46 -4
  340. nautobot/project-static/docs/development/core/style-guide.html +49 -7
  341. nautobot/project-static/docs/development/core/templates.html +46 -4
  342. nautobot/project-static/docs/development/core/testing.html +46 -4
  343. nautobot/project-static/docs/development/core/ui-component-framework.html +369 -273
  344. nautobot/project-static/docs/development/core/user-preferences.html +46 -4
  345. nautobot/project-static/docs/development/index.html +46 -4
  346. nautobot/project-static/docs/development/jobs/index.html +216 -122
  347. nautobot/project-static/docs/development/jobs/migration/from-v1.html +46 -4
  348. nautobot/project-static/docs/index.html +54 -23
  349. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
  350. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
  351. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
  352. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
  353. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
  354. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
  355. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
  356. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
  357. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
  358. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
  359. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
  360. nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
  361. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
  362. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
  363. nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
  364. nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
  365. nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
  366. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
  367. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
  368. nautobot/project-static/docs/objects.inv +0 -0
  369. nautobot/project-static/docs/overview/application_stack.html +47 -7
  370. nautobot/project-static/docs/overview/design_philosophy.html +46 -4
  371. nautobot/project-static/docs/release-notes/index.html +52 -12
  372. nautobot/project-static/docs/release-notes/version-1.0.html +234 -193
  373. nautobot/project-static/docs/release-notes/version-1.1.html +231 -190
  374. nautobot/project-static/docs/release-notes/version-1.2.html +306 -265
  375. nautobot/project-static/docs/release-notes/version-1.3.html +332 -291
  376. nautobot/project-static/docs/release-notes/version-1.4.html +417 -377
  377. nautobot/project-static/docs/release-notes/version-1.5.html +605 -566
  378. nautobot/project-static/docs/release-notes/version-1.6.html +904 -447
  379. nautobot/project-static/docs/release-notes/version-2.0.html +528 -489
  380. nautobot/project-static/docs/release-notes/version-2.1.html +363 -324
  381. nautobot/project-static/docs/release-notes/version-2.2.html +356 -317
  382. nautobot/project-static/docs/release-notes/version-2.3.html +997 -352
  383. nautobot/project-static/docs/release-notes/version-2.4.html +525 -101
  384. nautobot/project-static/docs/requirements.txt +2 -2
  385. nautobot/project-static/docs/search/search_index.json +1 -1
  386. nautobot/project-static/docs/sitemap.xml +295 -287
  387. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  388. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +46 -4
  389. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +46 -4
  390. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +48 -6
  391. nautobot/project-static/docs/user-guide/administration/configuration/index.html +46 -4
  392. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +46 -4
  393. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +110 -8
  394. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +46 -4
  395. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +46 -4
  396. nautobot/project-static/docs/user-guide/administration/guides/docker.html +46 -4
  397. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +46 -4
  398. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +46 -4
  399. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +46 -4
  400. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +46 -4
  401. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +46 -4
  402. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +48 -6
  403. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +46 -4
  404. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +46 -4
  405. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +46 -4
  406. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +66 -8
  407. nautobot/project-static/docs/user-guide/administration/installation/index.html +46 -4
  408. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +47 -5
  409. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +46 -4
  410. nautobot/project-static/docs/user-guide/administration/installation/services.html +46 -4
  411. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +46 -4
  412. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +46 -4
  413. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +46 -4
  414. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +46 -4
  415. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +46 -4
  416. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +46 -4
  417. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +46 -4
  418. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +46 -4
  419. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +46 -4
  420. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +49 -8
  421. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +46 -4
  422. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +46 -4
  423. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +46 -4
  424. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +46 -4
  425. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +46 -4
  426. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +46 -4
  427. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +46 -4
  428. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +46 -4
  429. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +46 -4
  430. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +46 -4
  431. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +46 -4
  432. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +46 -4
  433. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +46 -4
  434. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +46 -4
  435. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +46 -4
  436. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +46 -4
  437. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +46 -4
  438. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +46 -4
  439. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +46 -4
  440. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +46 -4
  441. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +46 -4
  442. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +46 -4
  443. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +46 -4
  444. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +46 -4
  445. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +46 -4
  446. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +46 -4
  447. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +46 -4
  448. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +46 -4
  449. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +46 -4
  450. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +46 -4
  451. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +46 -4
  452. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +46 -4
  453. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +46 -4
  454. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +46 -4
  455. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +46 -4
  456. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +46 -4
  457. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +46 -4
  458. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +46 -4
  459. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +46 -4
  460. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +46 -4
  461. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +46 -4
  462. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +46 -4
  463. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +46 -4
  464. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +46 -4
  465. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +46 -4
  466. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +46 -4
  467. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +46 -4
  468. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +46 -4
  469. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +46 -4
  470. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +46 -4
  471. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +46 -4
  472. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +46 -4
  473. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +46 -4
  474. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +46 -4
  475. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +46 -4
  476. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +46 -4
  477. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +46 -4
  478. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +50 -12
  479. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +46 -4
  480. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +46 -4
  481. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +46 -4
  482. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +46 -4
  483. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +46 -4
  484. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +46 -4
  485. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +46 -4
  486. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +46 -4
  487. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +46 -4
  488. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +46 -4
  489. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +46 -4
  490. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +46 -4
  491. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +49 -7
  492. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +46 -4
  493. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +46 -4
  494. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +46 -4
  495. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +46 -4
  496. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +46 -4
  497. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +46 -4
  498. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +46 -4
  499. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +46 -4
  500. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +46 -4
  501. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +46 -4
  502. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +46 -4
  503. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +46 -4
  504. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +46 -4
  505. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +46 -4
  506. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +46 -4
  507. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +46 -4
  508. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +46 -4
  509. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +46 -4
  510. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +46 -4
  511. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +46 -4
  512. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +46 -4
  513. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +46 -4
  514. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +51 -7
  515. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +46 -4
  516. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
  517. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
  518. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
  519. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
  520. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
  521. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
  522. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
  523. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
  524. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
  525. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
  526. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
  527. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
  528. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
  529. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +46 -4
  530. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +46 -4
  531. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +49 -7
  532. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
  533. nautobot/project-static/docs/user-guide/index.html +46 -4
  534. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +46 -4
  535. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +50 -8
  536. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +46 -4
  537. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +46 -4
  538. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +46 -4
  539. nautobot/project-static/docs/user-guide/platform-functionality/events.html +46 -4
  540. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +46 -4
  541. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +46 -4
  542. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +46 -4
  543. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +46 -4
  544. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +46 -4
  545. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +46 -4
  546. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +50 -7
  547. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +46 -4
  548. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +49 -7
  549. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +46 -4
  550. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +46 -4
  551. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9722 -0
  552. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +46 -4
  553. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +46 -4
  554. nautobot/project-static/docs/user-guide/platform-functionality/note.html +46 -4
  555. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +46 -4
  556. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +47 -5
  557. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +46 -4
  558. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +46 -4
  559. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +94 -25
  560. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +74 -5
  561. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +46 -4
  562. nautobot/project-static/docs/user-guide/platform-functionality/role.html +46 -4
  563. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +46 -4
  564. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +46 -4
  565. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +46 -4
  566. nautobot/project-static/docs/user-guide/platform-functionality/status.html +46 -4
  567. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +46 -4
  568. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +46 -4
  569. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +46 -4
  570. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +46 -4
  571. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +46 -4
  572. nautobot/project-static/js/forms.js +1 -1
  573. nautobot/tenancy/api/views.py +9 -13
  574. nautobot/tenancy/views.py +4 -2
  575. nautobot/users/admin.py +1 -1
  576. nautobot/users/api/serializers.py +5 -4
  577. nautobot/users/api/views.py +3 -3
  578. nautobot/virtualization/api/serializers.py +4 -4
  579. nautobot/virtualization/api/views.py +5 -24
  580. nautobot/virtualization/filters.py +20 -3
  581. nautobot/virtualization/models.py +1 -1
  582. nautobot/virtualization/tables.py +2 -2
  583. nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
  584. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
  585. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
  586. nautobot/virtualization/tests/test_filters.py +17 -0
  587. nautobot/wireless/filters.py +2 -2
  588. nautobot/wireless/forms.py +1 -1
  589. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +1 -9
  590. nautobot/wireless/tests/integration/__init__.py +0 -0
  591. nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
  592. nautobot/wireless/tests/test_filters.py +29 -1
  593. nautobot/wireless/tests/test_views.py +22 -1
  594. nautobot/wireless/views.py +0 -10
  595. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/METADATA +6 -6
  596. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/RECORD +600 -550
  597. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/WHEEL +1 -1
  598. nautobot/core/fixtures/user-data.json +0 -59
  599. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/LICENSE.txt +0 -0
  600. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/NOTICE +0 -0
  601. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/entry_points.txt +0 -0
@@ -29,29 +29,29 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
29
29
  request_id=uuid.uuid4(),
30
30
  )
31
31
 
32
- def populateDataBeforeMigration(self, apps):
32
+ def populateDataBeforeMigration(self, installed_apps):
33
33
  """Populate Aggregate data before migrating to Prefixes"""
34
34
 
35
- self.aggregate = apps.get_model("ipam", "Aggregate")
35
+ self.aggregate = installed_apps.get_model("ipam", "Aggregate")
36
36
  # Workaround for django-taggit manager not working in migrations.
37
37
  # https://github.com/jazzband/django-taggit/issues/101
38
38
  # https://github.com/jazzband/django-taggit/issues/454
39
39
  self.aggregate.tags = TagsField()
40
- self.computed_field = apps.get_model("extras", "computedfield")
41
- self.content_type = apps.get_model("contenttypes", "ContentType")
42
- self.custom_field = apps.get_model("extras", "customfield")
43
- self.custom_link = apps.get_model("extras", "customlink")
44
- self.dynamic_group = apps.get_model("extras", "DynamicGroup")
45
- self.note = apps.get_model("extras", "note")
46
- self.object_change = apps.get_model("extras", "objectchange")
47
- self.object_permission = apps.get_model("users", "objectpermission")
48
- self.prefix = apps.get_model("ipam", "prefix")
40
+ self.computed_field = installed_apps.get_model("extras", "computedfield")
41
+ self.content_type = installed_apps.get_model("contenttypes", "ContentType")
42
+ self.custom_field = installed_apps.get_model("extras", "customfield")
43
+ self.custom_link = installed_apps.get_model("extras", "customlink")
44
+ self.dynamic_group = installed_apps.get_model("extras", "DynamicGroup")
45
+ self.note = installed_apps.get_model("extras", "note")
46
+ self.object_change = installed_apps.get_model("extras", "objectchange")
47
+ self.object_permission = installed_apps.get_model("users", "objectpermission")
48
+ self.prefix = installed_apps.get_model("ipam", "prefix")
49
49
  self.prefix.tags = TagsField()
50
- self.relationship = apps.get_model("extras", "relationship")
51
- self.relationship_association = apps.get_model("extras", "relationshipassociation")
52
- self.rir = apps.get_model("ipam", "RIR")
53
- self.status = apps.get_model("extras", "status")
54
- self.tag = apps.get_model("extras", "tag")
50
+ self.relationship = installed_apps.get_model("extras", "relationship")
51
+ self.relationship_association = installed_apps.get_model("extras", "relationshipassociation")
52
+ self.rir = installed_apps.get_model("ipam", "RIR")
53
+ self.status = installed_apps.get_model("extras", "status")
54
+ self.tag = installed_apps.get_model("extras", "tag")
55
55
 
56
56
  self.aggregate_ct = self.content_type.objects.get_for_model(self.aggregate)
57
57
  self.prefix_ct = self.content_type.objects.get_for_model(self.prefix)
@@ -114,8 +114,8 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
114
114
  self.aggregate1.tags.add("AggregateTagA", "AggregateTagB")
115
115
  self.aggregate2.tags.add("AggregateTagA")
116
116
  self.aggregate3.tags.add("AggregateTagB")
117
- self.aggregate5.tags.add("AggregateTagA", "AggregateTagB")
118
- self.aggregate6.tags.add("AggregateTagB")
117
+ self.aggregate5.tags.add("AggregateTagA", "AggregateTagB") # pylint: disable=no-member
118
+ self.aggregate6.tags.add("AggregateTagB") # pylint: disable=no-member
119
119
 
120
120
  # notes
121
121
  self.note.objects.create(
@@ -141,7 +141,7 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
141
141
  self.note.objects.create(
142
142
  note="Aggregate5 test note",
143
143
  assigned_object_type=self.aggregate_ct,
144
- assigned_object_id=self.aggregate5.id,
144
+ assigned_object_id=self.aggregate5.id, # pylint: disable=no-member
145
145
  )
146
146
 
147
147
  # object permissions
@@ -157,8 +157,8 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
157
157
  # object changes
158
158
  self._create_objectchange(self.prefix1, "Pre-migration object change for prefix1")
159
159
  self._create_objectchange(self.prefix4, "Pre-migration object change for prefix4")
160
- self._create_objectchange(self.prefix5, "Pre-migration object change for prefix5")
161
- self._create_objectchange(self.aggregate5, "Pre-migration object change for aggregate5")
160
+ self._create_objectchange(self.prefix5, "Pre-migration object change for prefix5") # pylint: disable=no-member
161
+ self._create_objectchange(self.aggregate5, "Pre-migration object change for aggregate5") # pylint: disable=no-member
162
162
 
163
163
  # custom fields
164
164
  prefix_cf1 = self.custom_field.objects.create(name="prefixcf1")
@@ -179,24 +179,24 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
179
179
 
180
180
  self.aggregate3._custom_field_data["aggregatecf1"] = "testdata aggregatecf1 aggregate3"
181
181
 
182
- self.prefix5._custom_field_data["prefixcf1"] = "testdata prefixcf1 prefix5"
183
- self.prefix5._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 prefix5"
182
+ self.prefix5._custom_field_data["prefixcf1"] = "testdata prefixcf1 prefix5" # pylint: disable=no-member
183
+ self.prefix5._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 prefix5" # pylint: disable=no-member
184
184
 
185
- self.aggregate5._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 aggregate5"
186
- self.aggregate5._custom_field_data["aggregatecf1"] = "testdata aggregatecf1 aggregate5"
185
+ self.aggregate5._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 aggregate5" # pylint: disable=no-member
186
+ self.aggregate5._custom_field_data["aggregatecf1"] = "testdata aggregatecf1 aggregate5" # pylint: disable=no-member
187
187
 
188
- self.aggregate6._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 aggregate6"
188
+ self.aggregate6._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 aggregate6" # pylint: disable=no-member
189
189
 
190
190
  self.prefix1.save()
191
191
  self.prefix2.save()
192
192
  self.prefix3.save()
193
193
  self.prefix4.save()
194
- self.prefix5.save()
194
+ self.prefix5.save() # pylint: disable=no-member
195
195
  self.aggregate1.save()
196
196
  self.aggregate2.save()
197
197
  self.aggregate3.save()
198
- self.aggregate5.save()
199
- self.aggregate6.save()
198
+ self.aggregate5.save() # pylint: disable=no-member
199
+ self.aggregate6.save() # pylint: disable=no-member
200
200
 
201
201
  @skipIf(
202
202
  connection.vendor != "postgresql",
@@ -390,7 +390,7 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
390
390
  2,
391
391
  )
392
392
 
393
- for prefix in (self.prefix2, self.prefix3, self.prefix5):
393
+ for prefix in (self.prefix2, self.prefix3, self.prefix5): # pylint: disable=no-member
394
394
  self.assertEqual(
395
395
  self.object_change.objects.filter(changed_object_id=prefix.id).count(),
396
396
  1,
@@ -1,4 +1,5 @@
1
1
  from unittest import skipIf
2
+ from unittest.mock import patch
2
3
 
3
4
  from django.contrib.contenttypes.models import ContentType
4
5
  from django.core.exceptions import ValidationError
@@ -413,6 +414,42 @@ class TestPrefix(ModelTestCases.BaseModelTestCase):
413
414
  self.child1 = Prefix.objects.create(prefix="101.102.0.0/26", status=self.status, namespace=self.namespace)
414
415
  self.child2 = Prefix.objects.create(prefix="101.102.0.64/26", status=self.status, namespace=self.namespace)
415
416
 
417
+ def test_parent_exists_after_model_clean(self):
418
+ prefix = Prefix(
419
+ prefix="101.102.0.128/26",
420
+ status=self.status,
421
+ namespace=self.namespace,
422
+ type=PrefixTypeChoices.TYPE_CONTAINER,
423
+ )
424
+ prefix.clean()
425
+ self.assertEqual(prefix.parent, self.root)
426
+
427
+ def test_reparent_subnets_and_reparent_ips_call(self):
428
+ """Assert reparent_subnets and reparent_ips are only called if there is an update to either of network, namespace or prefix_length"""
429
+ prefix_ip = "101.102.0.0/28"
430
+ with self.subTest("Assert reparent_subnets"):
431
+ with patch.object(Prefix, "reparent_subnets", return_value=None) as mock_reparent_subnets:
432
+ Prefix.objects.create(prefix=prefix_ip, status=self.status, namespace=self.namespace)
433
+ mock_reparent_subnets.assert_called_once()
434
+
435
+ with patch.object(Prefix, "reparent_subnets", return_value=None) as mock_reparent_subnets:
436
+ prefix = Prefix.objects.get(prefix=prefix_ip)
437
+ prefix.description = "Sample Description"
438
+ prefix.save()
439
+ mock_reparent_subnets.assert_not_called()
440
+ prefix.delete()
441
+
442
+ with self.subTest("Assert reparent_ips"):
443
+ with patch.object(Prefix, "reparent_ips", return_value=None) as reparent_ips:
444
+ Prefix.objects.create(prefix=prefix_ip, status=self.status, namespace=self.namespace)
445
+ reparent_ips.assert_called_once()
446
+
447
+ with patch.object(Prefix, "reparent_ips", return_value=None) as reparent_ips:
448
+ prefix = Prefix.objects.get(prefix=prefix_ip)
449
+ prefix.description = "Sample Description"
450
+ prefix.save()
451
+ reparent_ips.assert_not_called()
452
+
416
453
  def test_location_queries(self):
417
454
  locations = Location.objects.all()[:4]
418
455
  for location in locations:
@@ -476,51 +513,68 @@ class TestPrefix(ModelTestCases.BaseModelTestCase):
476
513
  """Test the various ways of creating a Prefix all result in correctly populated fields."""
477
514
  with self.subTest("Creation with a prefix and status"):
478
515
  prefix = Prefix(prefix="192.0.3.0/24", status=self.status)
479
- prefix.save()
480
- self.assertEqual(prefix.network, "192.0.3.0")
481
- self.assertEqual(prefix.broadcast, "192.0.3.255")
482
- self.assertEqual(prefix.prefix_length, 24)
483
- self.assertEqual(prefix.type, PrefixTypeChoices.TYPE_NETWORK) # default value
484
- # parent field is tested exhaustively below
485
- self.assertEqual(prefix.ip_version, 4)
486
- self.assertEqual(prefix.namespace, get_default_namespace()) # default value
516
+ for method in [prefix.clean, prefix.save, prefix.refresh_from_db]:
517
+ method()
518
+ self.assertEqual(prefix.network, "192.0.3.0")
519
+ self.assertEqual(prefix.broadcast, "192.0.3.255")
520
+ self.assertEqual(prefix.prefix_length, 24)
521
+ self.assertEqual(prefix.type, PrefixTypeChoices.TYPE_NETWORK) # default value
522
+ # parent field is tested exhaustively below
523
+ self.assertEqual(prefix.ip_version, 4)
524
+ self.assertEqual(prefix.namespace, get_default_namespace()) # default value
525
+
526
+ with self.subTest("Creation with a network and prefix_length"):
527
+ prefix = Prefix(network="192.0.4.0", prefix_length=24, status=self.status)
528
+ for method in [prefix.clean, prefix.save, prefix.refresh_from_db]:
529
+ method()
530
+ self.assertEqual(prefix.network, "192.0.4.0")
531
+ self.assertEqual(prefix.broadcast, "192.0.4.255")
532
+ self.assertEqual(prefix.prefix_length, 24)
533
+ self.assertEqual(prefix.type, PrefixTypeChoices.TYPE_NETWORK) # default value
534
+ # parent field is tested exhaustively below
535
+ self.assertEqual(prefix.ip_version, 4)
536
+ self.assertEqual(prefix.namespace, get_default_namespace()) # default value
537
+ self.assertEqual(prefix.prefix, netaddr.IPNetwork("192.0.4.0/24"))
487
538
 
488
539
  with self.subTest("Creation with a network, broadcast, and prefix_length"):
489
- prefix = Prefix(network="192.0.4.0", broadcast="192.0.4.255", prefix_length=24, status=self.status)
490
- prefix.save()
491
- self.assertEqual(prefix.network, "192.0.4.0")
492
- self.assertEqual(prefix.broadcast, "192.0.4.255")
493
- self.assertEqual(prefix.prefix_length, 24)
494
- self.assertEqual(prefix.type, PrefixTypeChoices.TYPE_NETWORK) # default value
495
- # parent field is tested exhaustively below
496
- self.assertEqual(prefix.ip_version, 4)
497
- self.assertEqual(prefix.namespace, get_default_namespace()) # default value
498
- self.assertEqual(prefix.prefix, netaddr.IPNetwork("192.0.4.0/24"))
499
-
500
- with self.subTest("Creation with conflicting values - prefix takes precedence"):
540
+ prefix = Prefix(network="192.0.5.0", broadcast="192.0.5.255", prefix_length=24, status=self.status)
541
+ for method in [prefix.clean, prefix.save, prefix.refresh_from_db]:
542
+ method()
543
+ self.assertEqual(prefix.network, "192.0.5.0")
544
+ self.assertEqual(prefix.broadcast, "192.0.5.255")
545
+ self.assertEqual(prefix.prefix_length, 24)
546
+ self.assertEqual(prefix.type, PrefixTypeChoices.TYPE_NETWORK) # default value
547
+ # parent field is tested exhaustively below
548
+ self.assertEqual(prefix.ip_version, 4)
549
+ self.assertEqual(prefix.namespace, get_default_namespace()) # default value
550
+ self.assertEqual(prefix.prefix, netaddr.IPNetwork("192.0.5.0/24"))
551
+
552
+ with self.subTest("With conflicting values - prefix overrules network/broadcast/prefix_length/ip_version"):
501
553
  prefix = Prefix(
502
- prefix="192.0.5.0/24",
554
+ prefix="192.0.6.0/24",
503
555
  status=self.status,
504
556
  network="1.1.1.1",
505
557
  broadcast="2.2.2.2",
506
558
  prefix_length=27,
507
559
  ip_version=6,
508
560
  )
509
- prefix.save()
510
- self.assertEqual(prefix.network, "192.0.5.0")
511
- self.assertEqual(prefix.broadcast, "192.0.5.255")
512
- self.assertEqual(prefix.prefix_length, 24)
513
- self.assertEqual(prefix.ip_version, 4)
514
-
515
- with self.subTest("Creation with conflicting values - network and prefix_length take precedence"):
561
+ for method in [prefix.clean, prefix.save, prefix.refresh_from_db]:
562
+ method()
563
+ self.assertEqual(prefix.network, "192.0.6.0")
564
+ self.assertEqual(prefix.broadcast, "192.0.6.255")
565
+ self.assertEqual(prefix.prefix_length, 24)
566
+ self.assertEqual(prefix.ip_version, 4)
567
+
568
+ with self.subTest("With conflicting values - network/prefix_length overrule broadcast/ip_version"):
516
569
  prefix = Prefix(
517
- status=self.status, network="192.0.6.0", prefix_length=24, broadcast="192.0.6.127", ip_version=6
570
+ status=self.status, network="192.0.7.0", prefix_length=24, broadcast="192.0.7.127", ip_version=6
518
571
  )
519
- prefix.save()
520
- self.assertEqual(prefix.network, "192.0.6.0")
521
- self.assertEqual(prefix.broadcast, "192.0.6.255")
522
- self.assertEqual(prefix.prefix_length, 24)
523
- self.assertEqual(prefix.ip_version, 4)
572
+ for method in [prefix.clean, prefix.save, prefix.refresh_from_db]:
573
+ method()
574
+ self.assertEqual(prefix.network, "192.0.7.0")
575
+ self.assertEqual(prefix.broadcast, "192.0.7.255")
576
+ self.assertEqual(prefix.prefix_length, 24)
577
+ self.assertEqual(prefix.ip_version, 4)
524
578
 
525
579
  def test_tree_methods(self):
526
580
  """Test the various tree methods work as expected."""
@@ -766,6 +820,13 @@ class TestPrefix(ModelTestCases.BaseModelTestCase):
766
820
  IPAddress.objects.create(address="10.0.0.4/24", status=self.status, namespace=self.namespace)
767
821
  self.assertEqual(parent_prefix.get_first_available_ip(), "10.0.0.5/24")
768
822
 
823
+ def test_get_first_available_ip_calculate_child_ips(self):
824
+ parent_prefix = Prefix.objects.create(prefix="10.0.3.0/29", status=self.status, namespace=self.namespace)
825
+ Prefix.objects.create(prefix="10.0.3.0/30", status=self.status, namespace=self.namespace)
826
+ IPAddress(address="10.0.3.1/30", status=self.status, namespace=self.namespace).save()
827
+
828
+ self.assertEqual(parent_prefix.get_first_available_ip(), "10.0.3.2/29")
829
+
769
830
  def test_get_utilization(self):
770
831
  # Container Prefix
771
832
  prefix = Prefix.objects.create(
@@ -1,13 +1,15 @@
1
1
  import re
2
2
  from unittest import skipIf
3
3
 
4
- from django.db import connection
4
+ from django.contrib.contenttypes.models import ContentType
5
+ from django.db import connection, transaction
5
6
  import netaddr
6
7
 
7
8
  from nautobot.core.testing import TestCase
8
9
  from nautobot.extras.models import Status
9
10
  from nautobot.ipam import choices
10
11
  from nautobot.ipam.models import IPAddress, Namespace, Prefix
12
+ from nautobot.users.models import ObjectPermission
11
13
 
12
14
 
13
15
  class IPAddressQuerySet(TestCase):
@@ -266,6 +268,28 @@ class IPAddressQuerySet(TestCase):
266
268
  [instance for ip, instance in self.ips.items() if "10.0.0" in ip],
267
269
  )
268
270
 
271
+ def test_lookup_not_ambiguous(self):
272
+ """Check for issues like https://github.com/nautobot/nautobot/issues/5166."""
273
+ obj_perm = ObjectPermission.objects.create(name="Test Permission", constraints={}, actions=["view"])
274
+ obj_perm.object_types.add(ContentType.objects.get_for_model(IPAddress))
275
+ obj_perm.users.add(self.user)
276
+ queryset = IPAddress.objects.select_related("parent", "nat_inside", "status")
277
+
278
+ for permission_constraint in (
279
+ {"host__family": 4},
280
+ {"host__net_host": "10.0.0.1"},
281
+ {"host__net_host_contained": "10.0.0.0/24"},
282
+ {"host__net_in": ["10.0.0.0/24"]},
283
+ ):
284
+ with self.subTest(permission_type=next(iter(permission_constraint.keys()))):
285
+ try:
286
+ with transaction.atomic():
287
+ obj_perm.constraints = permission_constraint
288
+ obj_perm.save()
289
+ list(queryset.restrict(self.user, "view"))
290
+ finally:
291
+ delattr(self.user, "_object_perm_cache")
292
+
269
293
  @skipIf(
270
294
  connection.vendor == "postgresql",
271
295
  "Not currently supported on postgresql",
@@ -454,6 +478,20 @@ class IPAddressQuerySet(TestCase):
454
478
  [instance for ip, instance in self.ips.items() if re.match(r"2001(.*)1", ip)],
455
479
  )
456
480
 
481
+ def test_get_or_create(self):
482
+ # https://github.com/nautobot/nautobot/issues/6676
483
+ ip_obj, created = IPAddress.objects.update_or_create(
484
+ defaults={
485
+ "status": self.ipaddr_status,
486
+ },
487
+ host="10.0.0.1",
488
+ mask_length="24",
489
+ namespace=self.namespace,
490
+ )
491
+ self.assertFalse(created)
492
+ self.assertEqual(str(ip_obj.address), "10.0.0.1/24")
493
+ self.assertEqual(ip_obj.parent.namespace, self.namespace)
494
+
457
495
 
458
496
  class PrefixQuerysetTestCase(TestCase):
459
497
  queryset = Prefix.objects.all()
@@ -648,6 +686,30 @@ class PrefixQuerysetTestCase(TestCase):
648
686
  prefix = Prefix.objects.filter(network__net_equals="192.168.0.0/16")[0]
649
687
  self.assertEqual(Prefix.objects.filter(prefix="192.168.0.0/16")[0], prefix)
650
688
 
689
+ def test_lookup_not_ambiguous(self):
690
+ """Check for issues like https://github.com/nautobot/nautobot/issues/5166."""
691
+ obj_perm = ObjectPermission.objects.create(name="Test Permission", constraints={}, actions=["view"])
692
+ obj_perm.object_types.add(ContentType.objects.get_for_model(Prefix))
693
+ obj_perm.users.add(self.user)
694
+ queryset = Prefix.objects.select_related("parent", "rir", "role", "status", "namespace")
695
+
696
+ for permission_constraint in (
697
+ {"network__family": 4},
698
+ {"network__net_equals": "192.168.0.0/16"},
699
+ {"network__net_contained": "192.0.0.0/8"},
700
+ {"network__net_contained_or_equal": "192.0.0.0/8"},
701
+ {"network__net_contains": "192.168.3.192/32"},
702
+ {"network__net_contains_or_equals": "192.168.3.192/32"},
703
+ ):
704
+ with self.subTest(permission_type=next(iter(permission_constraint.keys()))):
705
+ try:
706
+ with transaction.atomic():
707
+ obj_perm.constraints = permission_constraint
708
+ obj_perm.save()
709
+ list(queryset.restrict(self.user, "view"))
710
+ finally:
711
+ delattr(self.user, "_object_perm_cache")
712
+
651
713
  @skipIf(
652
714
  connection.vendor == "postgresql",
653
715
  "Not currently supported on postgresql",
@@ -1054,6 +1054,9 @@ class VLANGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
1054
1054
  def get_deletable_object(self):
1055
1055
  return VLANGroup.objects.create(name="TEST DELETE ME")
1056
1056
 
1057
+ def get_deletable_object_pks(self):
1058
+ return [VLANGroup.objects.create(name="TEST DELETE ME").pk]
1059
+
1057
1060
 
1058
1061
  class VLANTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1059
1062
  model = VLAN
@@ -1,22 +1,29 @@
1
+ from collections.abc import Iterable
2
+
1
3
  from django.core.exceptions import ValidationError
2
4
  import netaddr
3
5
 
4
6
  from nautobot.core.forms.utils import compress_range
5
7
  from nautobot.dcim.models import Interface
6
8
  from nautobot.extras.models import RelationshipAssociation
7
- from nautobot.ipam.models import Prefix, VLAN
9
+ from nautobot.ipam.choices import PrefixTypeChoices
10
+ from nautobot.ipam.models import IPAddress, Namespace, Prefix, VLAN, VLANGroup
8
11
  from nautobot.ipam.querysets import IPAddressQuerySet
9
12
  from nautobot.virtualization.models import VMInterface
10
13
 
11
14
 
12
- def add_available_prefixes(parent, prefix_list):
15
+ def add_available_prefixes(parent: netaddr.IPNetwork, namespace: Namespace, prefix_list: Iterable[Prefix]):
13
16
  """
14
17
  Create fake Prefix objects for all unallocated space within a prefix.
15
18
  """
16
19
 
17
20
  # Find all unallocated space
18
- available_prefixes = netaddr.IPSet(parent) ^ netaddr.IPSet([p.prefix for p in prefix_list])
19
- available_prefixes = [Prefix(prefix=p, status=None) for p in available_prefixes.iter_cidrs()]
21
+ available_prefixes = netaddr.IPSet(parent) ^ netaddr.IPSet(
22
+ [p.prefix for p in prefix_list if p.type != PrefixTypeChoices.TYPE_CONTAINER or not p.descendants().exists()]
23
+ )
24
+ available_prefixes = [
25
+ Prefix(prefix=p, namespace=namespace, type=None, status=None) for p in available_prefixes.iter_cidrs()
26
+ ]
20
27
 
21
28
  # Concatenate and sort complete list of children
22
29
  prefix_list = list(prefix_list) + available_prefixes
@@ -25,7 +32,14 @@ def add_available_prefixes(parent, prefix_list):
25
32
  return prefix_list
26
33
 
27
34
 
28
- def add_available_ipaddresses(prefix, ipaddress_list, is_pool=False):
35
+ def get_add_available_prefixes_callback(show_available: bool, parent: Prefix):
36
+ """Conditionally provide a callback for add_available_prefixes()."""
37
+ if show_available:
38
+ return lambda prefixes: add_available_prefixes(parent.prefix, parent.namespace, prefixes)
39
+ return lambda prefixes: prefixes
40
+
41
+
42
+ def add_available_ipaddresses(prefix: netaddr.IPNetwork, ipaddress_list: Iterable[IPAddress], is_pool: bool = False):
29
43
  """
30
44
  Annotate ranges of available IP addresses within a given prefix. If is_pool is True, the first and last IP will be
31
45
  considered usable (regardless of mask length).
@@ -81,7 +95,16 @@ def add_available_ipaddresses(prefix, ipaddress_list, is_pool=False):
81
95
  return output
82
96
 
83
97
 
84
- def add_available_vlans(vlan_group, vlans):
98
+ def get_add_available_ipaddresses_callback(show_available: bool, parent: Prefix):
99
+ """Conditionally provide a callback for add_available_ipaddresses()."""
100
+ if show_available:
101
+ return lambda ip_addresses: add_available_ipaddresses(
102
+ parent.prefix, ip_addresses, is_pool=(parent.type == PrefixTypeChoices.TYPE_POOL)
103
+ )
104
+ return lambda ip_addresses: ip_addresses
105
+
106
+
107
+ def add_available_vlans(vlan_group: VLANGroup, vlans: list[VLAN]):
85
108
  """
86
109
  Create fake records for all gaps between used VLANs
87
110
  """
@@ -99,6 +122,13 @@ def add_available_vlans(vlan_group, vlans):
99
122
  return vlans
100
123
 
101
124
 
125
+ def get_add_available_vlans_callback(show_available: bool, vlan_group: VLANGroup):
126
+ """Conditionally provide a callback for add_available_vlans()."""
127
+ if show_available:
128
+ return lambda vlans: add_available_vlans(vlan_group=vlan_group, vlans=vlans)
129
+ return lambda vlans: vlans
130
+
131
+
102
132
  def handle_relationship_changes_when_merging_ips(merged_ip, merged_attributes, collapsed_ips):
103
133
  """
104
134
  Update/Delete RelationshipAssociation instances after we collapsed the IPs.