nautobot 2.0.0a3__py3-none-any.whl → 2.0.0b1__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.
Files changed (780) hide show
  1. nautobot/apps/api.py +6 -8
  2. nautobot/apps/forms.py +0 -2
  3. nautobot/apps/ui.py +0 -8
  4. nautobot/circuits/api/serializers.py +9 -117
  5. nautobot/circuits/api/urls.py +1 -1
  6. nautobot/circuits/api/views.py +0 -1
  7. nautobot/circuits/forms.py +0 -65
  8. nautobot/circuits/migrations/0014_related_name_changes.py +1 -1
  9. nautobot/circuits/migrations/0016_tagsfield.py +34 -0
  10. nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
  11. nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
  12. nautobot/circuits/models.py +3 -87
  13. nautobot/circuits/navigation.py +14 -69
  14. nautobot/circuits/signals.py +0 -2
  15. nautobot/circuits/tables.py +39 -1
  16. nautobot/circuits/tests/integration/test_relationships.py +9 -9
  17. nautobot/circuits/tests/test_api.py +4 -8
  18. nautobot/circuits/tests/test_filters.py +10 -4
  19. nautobot/circuits/tests/test_models.py +5 -1
  20. nautobot/circuits/tests/test_views.py +27 -5
  21. nautobot/circuits/views.py +18 -10
  22. nautobot/core/api/__init__.py +8 -2
  23. nautobot/core/api/fields.py +15 -6
  24. nautobot/core/api/filter_backends.py +3 -2
  25. nautobot/core/api/metadata.py +237 -30
  26. nautobot/core/api/mixins.py +94 -0
  27. nautobot/core/api/pagination.py +4 -0
  28. nautobot/core/api/parsers.py +154 -0
  29. nautobot/core/api/renderers.py +153 -2
  30. nautobot/core/api/schema.py +46 -2
  31. nautobot/core/api/serializers.py +377 -35
  32. nautobot/core/api/urls.py +11 -3
  33. nautobot/core/api/utils.py +174 -2
  34. nautobot/core/api/versioning.py +32 -10
  35. nautobot/core/api/views.py +266 -72
  36. nautobot/core/apps/__init__.py +138 -220
  37. nautobot/core/celery/__init__.py +112 -41
  38. nautobot/core/celery/backends.py +19 -12
  39. nautobot/core/celery/control.py +46 -0
  40. nautobot/core/celery/encoders.py +53 -0
  41. nautobot/core/celery/log.py +38 -0
  42. nautobot/core/celery/schedulers.py +23 -4
  43. nautobot/core/celery/task.py +1 -16
  44. nautobot/core/checks.py +0 -27
  45. nautobot/core/choices.py +0 -113
  46. nautobot/core/{cli.py → cli/__init__.py} +1 -1
  47. nautobot/core/cli/__main__.py +3 -0
  48. nautobot/core/constants.py +0 -24
  49. nautobot/core/context_processors.py +12 -0
  50. nautobot/core/filters.py +2 -2
  51. nautobot/core/forms/__init__.py +0 -4
  52. nautobot/core/forms/fields.py +38 -65
  53. nautobot/core/forms/forms.py +4 -1
  54. nautobot/core/forms/utils.py +0 -52
  55. nautobot/core/graphql/schema.py +4 -27
  56. nautobot/core/jobs/__init__.py +75 -0
  57. nautobot/core/management/commands/build_ui.py +255 -0
  58. nautobot/core/management/commands/generate_test_data.py +3 -2
  59. nautobot/core/management/commands/post_upgrade.py +24 -24
  60. nautobot/core/models/__init__.py +26 -1
  61. nautobot/core/models/fields.py +24 -5
  62. nautobot/core/models/generics.py +2 -42
  63. nautobot/core/models/managers.py +5 -0
  64. nautobot/core/models/name_color_content_types.py +0 -14
  65. nautobot/core/models/tree_queries.py +14 -4
  66. nautobot/core/models/utils.py +5 -6
  67. nautobot/core/models/validators.py +17 -8
  68. nautobot/core/releases.py +8 -10
  69. nautobot/core/settings.py +80 -42
  70. nautobot/core/tables.py +5 -5
  71. nautobot/core/tasks.py +4 -7
  72. nautobot/core/templates/base.html +1 -49
  73. nautobot/core/templates/base_django.html +49 -0
  74. nautobot/core/templates/base_react.html +55 -0
  75. nautobot/core/templates/buttons/export.html +6 -4
  76. nautobot/core/templates/generic/object_bulk_create.html +10 -21
  77. nautobot/core/templates/generic/object_list.html +3 -1
  78. nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
  79. nautobot/core/templates/inc/footer.html +1 -0
  80. nautobot/core/templates/inc/javascript.html +0 -14
  81. nautobot/core/templates/inc/nav_menu.html +28 -33
  82. nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
  83. nautobot/core/templates/inc/relationships_table_rows.html +2 -2
  84. nautobot/core/templates/nautobot_config.py.j2 +8 -20
  85. nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
  86. nautobot/core/templates/rest_framework/api.html +8 -0
  87. nautobot/core/templatetags/buttons.py +32 -28
  88. nautobot/core/testing/__init__.py +47 -44
  89. nautobot/core/testing/api.py +362 -47
  90. nautobot/core/testing/filters.py +1 -1
  91. nautobot/core/testing/migrations.py +2 -0
  92. nautobot/core/testing/mixins.py +22 -9
  93. nautobot/core/testing/schema.py +2 -1
  94. nautobot/core/testing/views.py +21 -46
  95. nautobot/core/tests/integration/test_filters.py +17 -8
  96. nautobot/core/tests/integration/test_navbar.py +11 -34
  97. nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
  98. nautobot/core/tests/nautobot_config.py +2 -3
  99. nautobot/core/tests/test_api.py +290 -21
  100. nautobot/core/tests/test_checks.py +0 -7
  101. nautobot/core/tests/test_filters.py +107 -59
  102. nautobot/core/tests/test_forms.py +26 -92
  103. nautobot/core/tests/test_graphql.py +110 -77
  104. nautobot/core/tests/test_logging.py +4 -0
  105. nautobot/core/tests/test_managers.py +3 -1
  106. nautobot/core/tests/test_models.py +2 -0
  107. nautobot/core/tests/test_paginator.py +3 -1
  108. nautobot/core/tests/test_releases.py +12 -12
  109. nautobot/core/tests/test_templatetags_helpers.py +4 -4
  110. nautobot/core/tests/test_utils.py +32 -68
  111. nautobot/core/tests/test_views.py +12 -15
  112. nautobot/core/utils/data.py +17 -0
  113. nautobot/core/utils/deprecation.py +9 -6
  114. nautobot/core/utils/filtering.py +8 -3
  115. nautobot/core/utils/git.py +12 -4
  116. nautobot/core/utils/lookup.py +3 -1
  117. nautobot/core/utils/requests.py +1 -104
  118. nautobot/core/views/__init__.py +1 -0
  119. nautobot/core/views/generic.py +75 -110
  120. nautobot/core/views/mixins.py +52 -61
  121. nautobot/core/views/renderers.py +6 -7
  122. nautobot/core/views/utils.py +80 -0
  123. nautobot/dcim/api/serializers.py +160 -667
  124. nautobot/dcim/api/urls.py +1 -1
  125. nautobot/dcim/api/views.py +7 -44
  126. nautobot/dcim/choices.py +2 -0
  127. nautobot/dcim/filters/__init__.py +21 -0
  128. nautobot/dcim/form_mixins.py +1 -27
  129. nautobot/dcim/forms.py +19 -765
  130. nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -1
  131. nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -13
  132. nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -1
  133. nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -1
  134. nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
  135. nautobot/dcim/migrations/0035_related_name_changes.py +1 -1
  136. nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -1
  137. nautobot/dcim/migrations/0040_tagsfield.py +109 -0
  138. nautobot/dcim/migrations/{0040_ipam__namespaces.py → 0041_ipam__namespaces.py} +1 -1
  139. nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
  140. nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
  141. nautobot/dcim/models/cables.py +3 -33
  142. nautobot/dcim/models/device_component_templates.py +6 -0
  143. nautobot/dcim/models/device_components.py +12 -198
  144. nautobot/dcim/models/devices.py +30 -143
  145. nautobot/dcim/models/locations.py +3 -64
  146. nautobot/dcim/models/power.py +3 -50
  147. nautobot/dcim/models/racks.py +7 -84
  148. nautobot/dcim/navigation.py +141 -467
  149. nautobot/dcim/signals.py +0 -2
  150. nautobot/dcim/tables/locations.py +2 -2
  151. nautobot/dcim/tables/power.py +1 -2
  152. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
  153. nautobot/dcim/templates/dcim/devicetype.html +2 -2
  154. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
  155. nautobot/dcim/templates/dcim/location.html +16 -1
  156. nautobot/dcim/templates/dcim/locationtype.html +15 -0
  157. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
  158. nautobot/dcim/templates/dcim/rackgroup.html +0 -12
  159. nautobot/dcim/tests/test_api.py +166 -81
  160. nautobot/dcim/tests/test_cablepaths.py +41 -35
  161. nautobot/dcim/tests/test_filters.py +67 -23
  162. nautobot/dcim/tests/test_forms.py +5 -205
  163. nautobot/dcim/tests/test_graphql.py +7 -2
  164. nautobot/dcim/tests/test_migrations.py +6 -11
  165. nautobot/dcim/tests/test_models.py +182 -110
  166. nautobot/dcim/tests/test_natural_ordering.py +11 -8
  167. nautobot/dcim/tests/test_signals.py +6 -3
  168. nautobot/dcim/tests/test_views.py +197 -175
  169. nautobot/dcim/urls.py +11 -16
  170. nautobot/dcim/views.py +7 -134
  171. nautobot/docs/additional-features/caching.md +6 -87
  172. nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
  173. nautobot/docs/additional-features/jobs.md +177 -195
  174. nautobot/docs/administration/nautobot-server.md +6 -21
  175. nautobot/docs/administration/replicating-nautobot.md +0 -10
  176. nautobot/docs/configuration/optional-settings.md +32 -41
  177. nautobot/docs/configuration/required-settings.md +11 -52
  178. nautobot/docs/development/application-registry.md +2 -13
  179. nautobot/docs/development/extending-models.md +15 -17
  180. nautobot/docs/development/generic-views.md +0 -2
  181. nautobot/docs/development/getting-started.md +55 -5
  182. nautobot/docs/development/navigation-menu.md +22 -93
  183. nautobot/docs/development/react-ui.md +105 -0
  184. nautobot/docs/development/role-internals.md +1 -3
  185. nautobot/docs/development/style-guide.md +6 -4
  186. nautobot/docs/index.md +3 -2
  187. nautobot/docs/installation/migrating-from-netbox.md +11 -42
  188. nautobot/docs/installation/nautobot.md +1 -1
  189. nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  190. nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  191. nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  192. nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  193. nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
  194. nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  195. nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  196. nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  197. nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  198. nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  199. nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  200. nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  201. nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  202. nautobot/docs/installation/upgrading-from-nautobot-v1.md +170 -747
  203. nautobot/docs/models/dcim/device.md +3 -0
  204. nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
  205. nautobot/docs/models/extras/computedfield.md +4 -4
  206. nautobot/docs/models/extras/gitrepository.md +3 -0
  207. nautobot/docs/models/extras/job.md +1 -0
  208. nautobot/docs/models/extras/jobbutton.md +18 -13
  209. nautobot/docs/models/extras/jobhook.md +7 -4
  210. nautobot/docs/models/extras/jobresult.md +6 -2
  211. nautobot/docs/models/extras/relationship.md +2 -2
  212. nautobot/docs/models/extras/status.md +6 -19
  213. nautobot/docs/models/ipam/ipaddress.md +3 -0
  214. nautobot/docs/models/virtualization/virtualmachine.md +3 -0
  215. nautobot/docs/plugins/development.md +83 -21
  216. nautobot/docs/release-notes/version-1.5.md +53 -0
  217. nautobot/docs/release-notes/version-2.0.md +180 -0
  218. nautobot/docs/requirements.txt +1 -0
  219. nautobot/docs/rest-api/overview.md +384 -215
  220. nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
  221. nautobot/extras/admin.py +3 -5
  222. nautobot/extras/api/customfields.py +15 -39
  223. nautobot/extras/api/fields.py +0 -11
  224. nautobot/extras/api/mixins.py +45 -0
  225. nautobot/extras/api/relationships.py +63 -158
  226. nautobot/extras/api/serializers.py +165 -700
  227. nautobot/extras/api/urls.py +1 -1
  228. nautobot/extras/api/views.py +294 -280
  229. nautobot/extras/apps.py +4 -7
  230. nautobot/extras/choices.py +11 -9
  231. nautobot/extras/constants.py +9 -3
  232. nautobot/extras/datasources/__init__.py +2 -0
  233. nautobot/extras/datasources/git.py +135 -186
  234. nautobot/extras/datasources/registry.py +25 -35
  235. nautobot/extras/filters/__init__.py +20 -19
  236. nautobot/extras/filters/mixins.py +4 -4
  237. nautobot/extras/forms/forms.py +63 -127
  238. nautobot/extras/forms/mixins.py +23 -51
  239. nautobot/extras/health_checks.py +0 -33
  240. nautobot/extras/jobs.py +387 -565
  241. nautobot/extras/management/commands/runjob.py +24 -62
  242. nautobot/extras/managers.py +30 -7
  243. nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
  244. nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -1
  245. nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -1
  246. nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -7
  247. nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -32
  248. nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -1
  249. nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -1
  250. nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
  251. nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -1
  252. nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -2
  253. nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -1
  254. nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -1
  255. nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
  256. nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -1
  257. nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
  258. nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -9
  259. nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -1
  260. nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
  261. nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
  262. nautobot/extras/migrations/{0076_remove_name_field_and_make_label_field_non_nullable.py → 0077_remove_name_field_and_make_label_field_non_nullable.py} +1 -1
  263. nautobot/extras/migrations/{0077_remove_slug.py → 0078_remove_slug.py} +1 -5
  264. nautobot/extras/migrations/0079_tagsfield.py +28 -0
  265. nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
  266. nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
  267. nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
  268. nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
  269. nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
  270. nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
  271. nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
  272. nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
  273. nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
  274. nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
  275. nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
  276. nautobot/extras/models/__init__.py +2 -3
  277. nautobot/extras/models/change_logging.py +0 -36
  278. nautobot/extras/models/customfields.py +39 -33
  279. nautobot/extras/models/datasources.py +48 -50
  280. nautobot/extras/models/groups.py +5 -6
  281. nautobot/extras/models/jobs.py +189 -321
  282. nautobot/extras/models/mixins.py +0 -71
  283. nautobot/extras/models/models.py +0 -19
  284. nautobot/extras/models/relationships.py +19 -13
  285. nautobot/extras/models/roles.py +0 -34
  286. nautobot/extras/models/secrets.py +2 -26
  287. nautobot/extras/models/statuses.py +6 -5
  288. nautobot/extras/models/tags.py +2 -17
  289. nautobot/extras/navigation.py +89 -307
  290. nautobot/extras/plugins/__init__.py +3 -120
  291. nautobot/extras/plugins/utils.py +0 -3
  292. nautobot/extras/plugins/validators.py +5 -4
  293. nautobot/extras/plugins/views.py +16 -3
  294. nautobot/extras/querysets.py +1 -7
  295. nautobot/extras/registry.py +3 -0
  296. nautobot/extras/signals.py +26 -60
  297. nautobot/extras/tables.py +34 -40
  298. nautobot/extras/tasks.py +0 -12
  299. nautobot/extras/templates/extras/configcontext.html +1 -1
  300. nautobot/extras/templates/extras/configcontextschema.html +16 -1
  301. nautobot/extras/templates/extras/customfield.html +0 -13
  302. nautobot/extras/templates/extras/gitrepository.html +3 -3
  303. nautobot/extras/templates/extras/inc/jobresult.html +10 -0
  304. nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
  305. nautobot/extras/templates/extras/job.html +35 -25
  306. nautobot/extras/templates/extras/job_approval_request.html +15 -30
  307. nautobot/extras/templates/extras/job_detail.html +13 -31
  308. nautobot/extras/templates/extras/job_edit.html +15 -17
  309. nautobot/extras/templates/extras/jobresult.html +24 -6
  310. nautobot/extras/templates/extras/scheduledjob.html +2 -2
  311. nautobot/extras/templates/extras/secret.html +28 -0
  312. nautobot/extras/templatetags/job_buttons.py +1 -0
  313. nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
  314. nautobot/extras/test_jobs/atomic_transaction.py +53 -0
  315. nautobot/extras/test_jobs/dry_run.py +29 -0
  316. nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
  317. nautobot/extras/test_jobs/duplicate_name2.py +9 -0
  318. nautobot/extras/test_jobs/fail.py +23 -0
  319. nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
  320. nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
  321. nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
  322. nautobot/extras/test_jobs/file_upload_pass.py +25 -0
  323. nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
  324. nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
  325. nautobot/extras/test_jobs/job_button_receiver.py +28 -0
  326. nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
  327. nautobot/extras/test_jobs/job_variables.py +88 -0
  328. nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
  329. nautobot/extras/test_jobs/log_redaction.py +20 -0
  330. nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
  331. nautobot/extras/test_jobs/modify_db.py +25 -0
  332. nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
  333. nautobot/extras/test_jobs/object_var_optional.py +21 -0
  334. nautobot/extras/test_jobs/object_var_required.py +21 -0
  335. nautobot/extras/test_jobs/object_vars.py +26 -0
  336. nautobot/extras/test_jobs/pass.py +25 -0
  337. nautobot/extras/test_jobs/profiling.py +32 -0
  338. nautobot/extras/test_jobs/read_only_job.py +15 -0
  339. nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
  340. nautobot/extras/{tests/example_jobs/test_soft_time_limit_greater_than_time_limit.py → test_jobs/soft_time_limit_greater_than_time_limit.py} +5 -1
  341. nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
  342. nautobot/extras/tests/integration/test_computedfields.py +1 -1
  343. nautobot/extras/tests/integration/test_configcontextschema.py +5 -3
  344. nautobot/extras/tests/integration/test_customfields.py +4 -2
  345. nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
  346. nautobot/extras/tests/integration/test_jobs.py +25 -27
  347. nautobot/extras/tests/integration/test_notes.py +8 -4
  348. nautobot/extras/tests/integration/test_relationships.py +2 -2
  349. nautobot/extras/tests/test_api.py +649 -642
  350. nautobot/extras/tests/test_changelog.py +3 -3
  351. nautobot/extras/tests/test_context_managers.py +5 -3
  352. nautobot/extras/tests/test_customfields.py +92 -50
  353. nautobot/extras/tests/test_datasources.py +189 -112
  354. nautobot/extras/tests/test_dynamicgroups.py +7 -8
  355. nautobot/extras/tests/test_filters.py +137 -89
  356. nautobot/extras/tests/test_forms.py +73 -75
  357. nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
  358. nautobot/extras/tests/test_jobs.py +262 -263
  359. nautobot/extras/tests/test_migrations.py +4 -3
  360. nautobot/extras/tests/test_models.py +116 -161
  361. nautobot/extras/tests/test_plugins.py +38 -60
  362. nautobot/extras/tests/test_relationships.py +167 -120
  363. nautobot/extras/tests/test_tags.py +6 -11
  364. nautobot/extras/tests/test_utils.py +31 -1
  365. nautobot/extras/tests/test_views.py +201 -145
  366. nautobot/extras/tests/test_webhooks.py +6 -2
  367. nautobot/extras/urls.py +42 -42
  368. nautobot/extras/utils.py +137 -163
  369. nautobot/extras/views.py +78 -152
  370. nautobot/ipam/api/fields.py +17 -0
  371. nautobot/ipam/api/serializers.py +58 -164
  372. nautobot/ipam/api/urls.py +1 -1
  373. nautobot/ipam/api/views.py +3 -2
  374. nautobot/ipam/apps.py +1 -2
  375. nautobot/ipam/filters.py +1 -10
  376. nautobot/ipam/forms.py +4 -177
  377. nautobot/ipam/lookups.py +1 -0
  378. nautobot/ipam/management/commands/__init__.py +0 -0
  379. nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
  380. nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -1
  381. nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -38
  382. nautobot/ipam/migrations/0020_related_name_changes.py +1 -1
  383. nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +2 -2
  384. nautobot/ipam/migrations/0028_tagsfield.py +44 -0
  385. nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
  386. nautobot/ipam/migrations/{0028_ipam__namespaces.py → 0030_ipam__namespaces.py} +77 -28
  387. nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
  388. nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
  389. nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
  390. nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
  391. nautobot/ipam/models.py +100 -236
  392. nautobot/ipam/navigation.py +36 -181
  393. nautobot/ipam/querysets.py +20 -25
  394. nautobot/ipam/signals.py +49 -6
  395. nautobot/ipam/tables.py +10 -3
  396. nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
  397. nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
  398. nautobot/ipam/templates/ipam/namespace_retrieve.html +17 -4
  399. nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
  400. nautobot/ipam/templates/ipam/prefix.html +1 -1
  401. nautobot/ipam/templates/ipam/vlangroup.html +0 -13
  402. nautobot/ipam/templates/ipam/vrf_edit.html +6 -0
  403. nautobot/ipam/tests/integration/test_prefixes.py +3 -26
  404. nautobot/ipam/tests/test_api.py +22 -19
  405. nautobot/ipam/tests/test_filters.py +59 -23
  406. nautobot/ipam/tests/test_migrations.py +6 -10
  407. nautobot/ipam/tests/test_models.py +323 -198
  408. nautobot/ipam/tests/test_ordering.py +2 -2
  409. nautobot/ipam/tests/test_querysets.py +44 -24
  410. nautobot/ipam/tests/test_views.py +73 -26
  411. nautobot/ipam/urls.py +16 -0
  412. nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
  413. nautobot/ipam/utils/migrations.py +713 -0
  414. nautobot/ipam/views.py +137 -20
  415. nautobot/project-static/docs/404.html +1178 -10
  416. nautobot/project-static/docs/additional-features/caching.html +1224 -159
  417. nautobot/project-static/docs/additional-features/change-logging.html +1180 -12
  418. nautobot/project-static/docs/additional-features/config-contexts.html +1180 -12
  419. nautobot/project-static/docs/additional-features/graphql.html +1179 -11
  420. nautobot/project-static/docs/additional-features/healthcheck.html +1180 -12
  421. nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1184 -12
  422. nautobot/project-static/docs/additional-features/jobs.html +1514 -328
  423. nautobot/project-static/docs/additional-features/napalm.html +1180 -12
  424. nautobot/project-static/docs/additional-features/prometheus-metrics.html +1180 -12
  425. nautobot/project-static/docs/additional-features/template-filters.html +1180 -12
  426. nautobot/project-static/docs/administration/celery-queues.html +1178 -10
  427. nautobot/project-static/docs/administration/nautobot-server.html +1451 -304
  428. nautobot/project-static/docs/administration/nautobot-shell.html +1178 -10
  429. nautobot/project-static/docs/administration/permissions.html +1178 -10
  430. nautobot/project-static/docs/administration/replicating-nautobot.html +1262 -113
  431. nautobot/project-static/docs/apps/index.html +1178 -10
  432. nautobot/project-static/docs/apps/nautobot-apps.html +1178 -10
  433. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1580 -426
  434. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1178 -10
  435. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3481 -1838
  436. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1178 -10
  437. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1178 -10
  438. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1185 -11
  439. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1719 -551
  440. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2062 -930
  441. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +1946 -659
  442. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1180 -12
  443. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1189 -21
  444. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +9283 -6218
  445. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2734 -2122
  446. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1178 -10
  447. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2337 -1300
  448. nautobot/project-static/docs/configuration/authentication/ldap.html +1178 -10
  449. nautobot/project-static/docs/configuration/authentication/remote.html +1178 -10
  450. nautobot/project-static/docs/configuration/authentication/sso.html +1178 -10
  451. nautobot/project-static/docs/configuration/index.html +1178 -10
  452. nautobot/project-static/docs/configuration/optional-settings.html +1311 -160
  453. nautobot/project-static/docs/configuration/required-settings.html +1312 -211
  454. nautobot/project-static/docs/core-functionality/circuits.html +1178 -10
  455. nautobot/project-static/docs/core-functionality/device-types.html +1178 -10
  456. nautobot/project-static/docs/core-functionality/devices.html +1182 -10
  457. nautobot/project-static/docs/core-functionality/ipam.html +1182 -10
  458. nautobot/project-static/docs/core-functionality/power.html +1178 -10
  459. nautobot/project-static/docs/core-functionality/secrets.html +1178 -10
  460. nautobot/project-static/docs/core-functionality/services.html +1178 -10
  461. nautobot/project-static/docs/core-functionality/sites-and-racks.html +1178 -10
  462. nautobot/project-static/docs/core-functionality/tenancy.html +1178 -10
  463. nautobot/project-static/docs/core-functionality/virtualization.html +1182 -10
  464. nautobot/project-static/docs/core-functionality/vlans.html +1179 -11
  465. nautobot/project-static/docs/development/application-registry.html +1190 -42
  466. nautobot/project-static/docs/development/best-practices.html +1178 -10
  467. nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1178 -10
  468. nautobot/project-static/docs/development/extending-models.html +1238 -83
  469. nautobot/project-static/docs/development/generic-views.html +1180 -14
  470. nautobot/project-static/docs/development/getting-started.html +1365 -90
  471. nautobot/project-static/docs/development/homepage.html +1178 -10
  472. nautobot/project-static/docs/development/index.html +1178 -10
  473. nautobot/project-static/docs/development/model-features.html +1178 -10
  474. nautobot/project-static/docs/development/natural-keys.html +1178 -10
  475. nautobot/project-static/docs/development/navigation-menu.html +1215 -125
  476. nautobot/project-static/docs/development/react-ui.html +4199 -0
  477. nautobot/project-static/docs/development/release-checklist.html +1178 -10
  478. nautobot/project-static/docs/development/role-internals.html +1179 -12
  479. nautobot/project-static/docs/development/style-guide.html +1188 -19
  480. nautobot/project-static/docs/development/templates.html +1178 -10
  481. nautobot/project-static/docs/development/testing.html +1178 -10
  482. nautobot/project-static/docs/development/user-preferences.html +1178 -10
  483. nautobot/project-static/docs/docker/index.html +1178 -10
  484. nautobot/project-static/docs/index.html +1183 -12
  485. nautobot/project-static/docs/installation/centos.html +1178 -10
  486. nautobot/project-static/docs/installation/external-authentication.html +1178 -10
  487. nautobot/project-static/docs/installation/http-server.html +1178 -10
  488. nautobot/project-static/docs/installation/index.html +1178 -10
  489. nautobot/project-static/docs/installation/migrating-from-netbox.html +1305 -189
  490. nautobot/project-static/docs/installation/migrating-from-postgresql.html +1178 -10
  491. nautobot/project-static/docs/installation/nautobot.html +1179 -11
  492. nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1178 -10
  493. nautobot/project-static/docs/installation/selinux-troubleshooting.html +1178 -10
  494. nautobot/project-static/docs/installation/services.html +1178 -10
  495. nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  496. nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  497. nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  498. nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  499. nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
  500. nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  501. nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  502. nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  503. nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  504. nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  505. nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  506. nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  507. nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  508. nautobot/project-static/docs/installation/ubuntu.html +1178 -10
  509. nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +3823 -2152
  510. nautobot/project-static/docs/installation/upgrading.html +1178 -10
  511. nautobot/project-static/docs/models/circuits/circuit.html +1293 -103
  512. nautobot/project-static/docs/models/circuits/circuittermination.html +1293 -103
  513. nautobot/project-static/docs/models/circuits/circuittype.html +1293 -103
  514. nautobot/project-static/docs/models/circuits/provider.html +1293 -103
  515. nautobot/project-static/docs/models/circuits/providernetwork.html +1293 -103
  516. nautobot/project-static/docs/models/dcim/cable.html +1324 -103
  517. nautobot/project-static/docs/models/dcim/consoleport.html +1293 -103
  518. nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1293 -103
  519. nautobot/project-static/docs/models/dcim/consoleserverport.html +1293 -103
  520. nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1293 -103
  521. nautobot/project-static/docs/models/dcim/device.html +1326 -132
  522. nautobot/project-static/docs/models/dcim/devicebay.html +1293 -103
  523. nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1293 -103
  524. nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1379 -97
  525. nautobot/project-static/docs/models/dcim/devicetype.html +1293 -103
  526. nautobot/project-static/docs/models/dcim/frontport.html +1293 -103
  527. nautobot/project-static/docs/models/dcim/frontporttemplate.html +1293 -103
  528. nautobot/project-static/docs/models/dcim/interface.html +1293 -103
  529. nautobot/project-static/docs/models/dcim/interfacetemplate.html +1293 -103
  530. nautobot/project-static/docs/models/dcim/inventoryitem.html +1293 -103
  531. nautobot/project-static/docs/models/dcim/location.html +1293 -103
  532. nautobot/project-static/docs/models/dcim/locationtype.html +1293 -103
  533. nautobot/project-static/docs/models/dcim/manufacturer.html +1292 -102
  534. nautobot/project-static/docs/models/dcim/platform.html +1272 -82
  535. nautobot/project-static/docs/models/dcim/powerfeed.html +1270 -80
  536. nautobot/project-static/docs/models/dcim/poweroutlet.html +1272 -82
  537. nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1272 -82
  538. nautobot/project-static/docs/models/dcim/powerpanel.html +1270 -80
  539. nautobot/project-static/docs/models/dcim/powerport.html +1272 -82
  540. nautobot/project-static/docs/models/dcim/powerporttemplate.html +1272 -82
  541. nautobot/project-static/docs/models/dcim/rack.html +1272 -82
  542. nautobot/project-static/docs/models/dcim/rackgroup.html +1272 -82
  543. nautobot/project-static/docs/models/dcim/rackreservation.html +1272 -82
  544. nautobot/project-static/docs/models/dcim/rearport.html +1286 -96
  545. nautobot/project-static/docs/models/dcim/rearporttemplate.html +1286 -96
  546. nautobot/project-static/docs/models/dcim/region.html +1178 -10
  547. nautobot/project-static/docs/models/dcim/site.html +1178 -10
  548. nautobot/project-static/docs/models/dcim/virtualchassis.html +1284 -94
  549. nautobot/project-static/docs/models/extras/computedfield.html +1184 -16
  550. nautobot/project-static/docs/models/extras/configcontext.html +1314 -86
  551. nautobot/project-static/docs/models/extras/configcontextschema.html +1276 -86
  552. nautobot/project-static/docs/models/extras/customfield.html +1180 -12
  553. nautobot/project-static/docs/models/extras/customlink.html +1180 -12
  554. nautobot/project-static/docs/models/extras/dynamicgroup.html +1180 -12
  555. nautobot/project-static/docs/models/extras/exporttemplate.html +1180 -12
  556. nautobot/project-static/docs/models/extras/gitrepository.html +1184 -12
  557. nautobot/project-static/docs/models/extras/graphqlquery.html +1321 -86
  558. nautobot/project-static/docs/models/extras/imageattachment.html +1276 -86
  559. nautobot/project-static/docs/models/extras/job.html +1277 -86
  560. nautobot/project-static/docs/models/extras/jobbutton.html +1201 -29
  561. nautobot/project-static/docs/models/extras/jobhook.html +1188 -16
  562. nautobot/project-static/docs/models/extras/joblogentry.html +1274 -84
  563. nautobot/project-static/docs/models/extras/jobresult.html +1364 -169
  564. nautobot/project-static/docs/models/extras/note.html +1180 -12
  565. nautobot/project-static/docs/models/extras/relationship.html +1182 -14
  566. nautobot/project-static/docs/models/extras/role.html +1320 -86
  567. nautobot/project-static/docs/models/extras/secret.html +1314 -86
  568. nautobot/project-static/docs/models/extras/secretsgroup.html +1276 -86
  569. nautobot/project-static/docs/models/extras/status.html +1188 -59
  570. nautobot/project-static/docs/models/extras/tag.html +1180 -12
  571. nautobot/project-static/docs/models/extras/webhook.html +1180 -12
  572. nautobot/project-static/docs/models/ipam/ipaddress.html +1327 -102
  573. nautobot/project-static/docs/models/ipam/prefix.html +1276 -86
  574. nautobot/project-static/docs/models/ipam/rir.html +1276 -86
  575. nautobot/project-static/docs/models/ipam/routetarget.html +1276 -86
  576. nautobot/project-static/docs/models/ipam/service.html +1276 -86
  577. nautobot/project-static/docs/models/ipam/vlan.html +1276 -86
  578. nautobot/project-static/docs/models/ipam/vlangroup.html +1276 -86
  579. nautobot/project-static/docs/models/ipam/vrf.html +1276 -86
  580. nautobot/project-static/docs/models/tenancy/tenant.html +1276 -86
  581. nautobot/project-static/docs/models/tenancy/tenantgroup.html +1276 -86
  582. nautobot/project-static/docs/models/users/objectpermission.html +1314 -86
  583. nautobot/project-static/docs/models/users/token.html +1276 -86
  584. nautobot/project-static/docs/models/virtualization/cluster.html +1276 -86
  585. nautobot/project-static/docs/models/virtualization/clustergroup.html +1276 -86
  586. nautobot/project-static/docs/models/virtualization/clustertype.html +1276 -86
  587. nautobot/project-static/docs/models/virtualization/virtualmachine.html +1321 -127
  588. nautobot/project-static/docs/models/virtualization/vminterface.html +1276 -86
  589. nautobot/project-static/docs/objects.inv +0 -0
  590. nautobot/project-static/docs/plugins/development.html +1726 -495
  591. nautobot/project-static/docs/plugins/index.html +1178 -10
  592. nautobot/project-static/docs/plugins/porting-from-netbox.html +1178 -10
  593. nautobot/project-static/docs/release-notes/index.html +1178 -10
  594. nautobot/project-static/docs/release-notes/version-1.0.html +1178 -10
  595. nautobot/project-static/docs/release-notes/version-1.1.html +1178 -10
  596. nautobot/project-static/docs/release-notes/version-1.2.html +1178 -10
  597. nautobot/project-static/docs/release-notes/version-1.3.html +1178 -10
  598. nautobot/project-static/docs/release-notes/version-1.4.html +1178 -10
  599. nautobot/project-static/docs/release-notes/version-1.5.html +1608 -225
  600. nautobot/project-static/docs/release-notes/version-2.0.html +1547 -47
  601. nautobot/project-static/docs/requirements.txt +1 -0
  602. nautobot/project-static/docs/rest-api/authentication.html +1179 -11
  603. nautobot/project-static/docs/rest-api/filtering.html +1178 -10
  604. nautobot/project-static/docs/rest-api/overview.html +1841 -446
  605. nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
  606. nautobot/project-static/docs/search/search_index.json +1 -1
  607. nautobot/project-static/docs/sitemap.xml +197 -187
  608. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  609. nautobot/project-static/docs/user-guides/custom-fields.html +1178 -10
  610. nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1178 -10
  611. nautobot/project-static/docs/user-guides/getting-started/index.html +1178 -10
  612. nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1178 -10
  613. nautobot/project-static/docs/user-guides/getting-started/ipam.html +1178 -10
  614. nautobot/project-static/docs/user-guides/getting-started/platforms.html +1178 -10
  615. nautobot/project-static/docs/user-guides/getting-started/regions.html +1178 -10
  616. nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1178 -10
  617. nautobot/project-static/docs/user-guides/getting-started/tenants.html +1178 -10
  618. nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1178 -10
  619. nautobot/project-static/docs/user-guides/git-data-source.html +1178 -10
  620. nautobot/project-static/docs/user-guides/graphql.html +1178 -10
  621. nautobot/project-static/docs/user-guides/relationships.html +1178 -10
  622. nautobot/project-static/docs/user-guides/s3-django-storage.html +1178 -10
  623. nautobot/project-static/js/forms.js +16 -9
  624. nautobot/project-static/js/theme.js +5 -0
  625. nautobot/tenancy/api/serializers.py +4 -32
  626. nautobot/tenancy/api/urls.py +1 -1
  627. nautobot/tenancy/forms.py +0 -28
  628. nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
  629. nautobot/tenancy/models.py +0 -25
  630. nautobot/tenancy/navigation.py +6 -39
  631. nautobot/tenancy/templates/tenancy/tenant.html +12 -12
  632. nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
  633. nautobot/tenancy/tests/test_api.py +1 -3
  634. nautobot/tenancy/tests/test_filters.py +10 -5
  635. nautobot/tenancy/views.py +0 -2
  636. nautobot/ui/.eslintignore +6 -0
  637. nautobot/ui/.gitignore +10 -0
  638. nautobot/ui/.prettierignore +9 -0
  639. nautobot/ui/.prettierrc +4 -0
  640. nautobot/ui/README.md +33 -0
  641. nautobot/ui/app_imports.js.j2 +7 -0
  642. nautobot/ui/craco.config.js +46 -0
  643. nautobot/ui/jsconfig-base.json +11 -0
  644. nautobot/ui/jsconfig.json +5 -0
  645. nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
  646. nautobot/ui/package-lock.json +21451 -0
  647. nautobot/ui/package.json +70 -0
  648. nautobot/ui/public/index.html +47 -0
  649. nautobot/ui/public/logo192.png +0 -0
  650. nautobot/ui/public/logo512.png +0 -0
  651. nautobot/ui/public/manifest.json +25 -0
  652. nautobot/ui/public/nautobot_logo.svg +131 -0
  653. nautobot/ui/public/robots.txt +3 -0
  654. nautobot/ui/src/App.js +71 -0
  655. nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
  656. nautobot/ui/src/components/AppTab.js +40 -0
  657. nautobot/ui/src/components/Apps.js +60 -0
  658. nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
  659. nautobot/ui/src/components/HomePanel.js +58 -0
  660. nautobot/ui/src/components/JobHistoryTable.js +78 -0
  661. nautobot/ui/src/components/Layout.js +53 -0
  662. nautobot/ui/src/components/LoadingWidget.js +25 -0
  663. nautobot/ui/src/components/Navbar.js +116 -0
  664. nautobot/ui/src/components/NotificationPopover.js +27 -0
  665. nautobot/ui/src/components/ObjectListTable.js +209 -0
  666. nautobot/ui/src/components/ReferenceDataTag.js +35 -0
  667. nautobot/ui/src/components/RouterButton.js +10 -0
  668. nautobot/ui/src/components/RouterLink.js +10 -0
  669. nautobot/ui/src/components/SidebarNav.js +147 -0
  670. nautobot/ui/src/components/Table.js +48 -0
  671. nautobot/ui/src/components/TableItem.js +71 -0
  672. nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
  673. nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
  674. nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
  675. nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
  676. nautobot/ui/src/components/__tests__/Table.test.js +36 -0
  677. nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
  678. nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
  679. nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
  680. nautobot/ui/src/components/pagination.js +93 -0
  681. nautobot/ui/src/components/paginator.js +79 -0
  682. nautobot/ui/src/components/paginator_form.js +43 -0
  683. nautobot/ui/src/components/usePagination.js +57 -0
  684. nautobot/ui/src/constants/apiPath.js +10 -0
  685. nautobot/ui/src/constants/icons.js +15 -0
  686. nautobot/ui/src/constants/size.js +15 -0
  687. nautobot/ui/src/index.js +65 -0
  688. nautobot/ui/src/reportWebVitals.js +15 -0
  689. nautobot/ui/src/router.js +77 -0
  690. nautobot/ui/src/utils/api.js +131 -0
  691. nautobot/ui/src/utils/app-import.js +15 -0
  692. nautobot/ui/src/utils/color.js +15 -0
  693. nautobot/ui/src/utils/date.js +14 -0
  694. nautobot/ui/src/utils/index.js +15 -0
  695. nautobot/ui/src/utils/navigation.js +32 -0
  696. nautobot/ui/src/utils/session.js +64 -0
  697. nautobot/ui/src/utils/store.js +242 -0
  698. nautobot/ui/src/utils/string.js +6 -0
  699. nautobot/ui/src/utils/url.js +4 -0
  700. nautobot/ui/src/views/Home.js +138 -0
  701. nautobot/ui/src/views/InstalledApps.js +80 -0
  702. nautobot/ui/src/views/Login.js +48 -0
  703. nautobot/ui/src/views/Logout.js +20 -0
  704. nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
  705. nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
  706. nautobot/ui/src/views/__tests__/Login.test.js +15 -0
  707. nautobot/ui/src/views/generic/GenericView.js +142 -0
  708. nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
  709. nautobot/ui/src/views/generic/ObjectList.js +127 -0
  710. nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
  711. nautobot/users/admin.py +1 -1
  712. nautobot/users/api/serializers.py +51 -61
  713. nautobot/users/api/urls.py +1 -1
  714. nautobot/users/api/views.py +53 -2
  715. nautobot/users/tests/test_api.py +110 -25
  716. nautobot/virtualization/api/serializers.py +18 -130
  717. nautobot/virtualization/api/urls.py +1 -1
  718. nautobot/virtualization/api/views.py +1 -22
  719. nautobot/virtualization/forms.py +13 -99
  720. nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -1
  721. nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -11
  722. nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -1
  723. nautobot/virtualization/migrations/0018_related_name_changes.py +1 -1
  724. nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
  725. nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
  726. nautobot/virtualization/migrations/{0021_ipam__namespaces.py → 0023_ipam__namespaces.py} +2 -2
  727. nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
  728. nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
  729. nautobot/virtualization/models.py +31 -123
  730. nautobot/virtualization/navigation.py +18 -99
  731. nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -1
  732. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
  733. nautobot/virtualization/tests/test_api.py +25 -26
  734. nautobot/virtualization/tests/test_filters.py +41 -15
  735. nautobot/virtualization/tests/test_models.py +31 -7
  736. nautobot/virtualization/tests/test_views.py +42 -25
  737. nautobot/virtualization/views.py +7 -6
  738. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +3 -7
  739. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +744 -602
  740. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
  741. nautobot/circuits/api/nested_serializers.py +0 -69
  742. nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
  743. nautobot/dcim/api/nested_serializers.py +0 -356
  744. nautobot/dcim/templates/dcim/device_import.html +0 -5
  745. nautobot/dcim/templates/dcim/device_import_child.html +0 -5
  746. nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
  747. nautobot/extras/api/nested_serializers.py +0 -353
  748. nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -41
  749. nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -46
  750. nautobot/extras/reports.py +0 -60
  751. nautobot/extras/scripts.py +0 -72
  752. nautobot/extras/tests/example_jobs/script_variables.py +0 -67
  753. nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
  754. nautobot/extras/tests/example_jobs/test_fail.py +0 -16
  755. nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
  756. nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
  757. nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
  758. nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
  759. nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
  760. nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
  761. nautobot/extras/tests/example_jobs/test_modify_db.py +0 -18
  762. nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
  763. nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
  764. nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
  765. nautobot/extras/tests/example_jobs/test_pass.py +0 -19
  766. nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
  767. nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
  768. nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
  769. nautobot/ipam/api/nested_serializers.py +0 -159
  770. nautobot/ipam/migrations/0029_ipam__prefix__add_parent.py +0 -31
  771. nautobot/ipam/migrations/0030_ipam__prefix__data_migration.py +0 -13
  772. nautobot/ipam/migrations/0031_ipam__ipaddress__add_parent.py +0 -41
  773. nautobot/ipam/migrations/0032_ipam__ipaddress__data_migration.py +0 -11
  774. nautobot/tenancy/api/nested_serializers.py +0 -31
  775. nautobot/users/api/nested_serializers.py +0 -67
  776. nautobot/virtualization/api/nested_serializers.py +0 -65
  777. /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
  778. /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
  779. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
  780. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
@@ -2,17 +2,26 @@ import json
2
2
  import logging
3
3
  import os
4
4
  from pathlib import Path
5
+ import pkgutil
6
+ import shutil
7
+ import sys
5
8
 
6
9
  from celery import Celery, shared_task, signals
10
+ from celery.app.log import TaskFormatter
7
11
  from celery.fixups.django import DjangoFixup
12
+ from celery.utils.log import get_logger
8
13
  from django.conf import settings
9
- from django.core.serializers.json import DjangoJSONEncoder
14
+ from django.utils.functional import SimpleLazyObject
10
15
  from django.utils.module_loading import import_string
11
16
  from kombu.serialization import register
12
17
  from prometheus_client import CollectorRegistry, multiprocess, start_http_server
13
18
 
14
- logger = logging.getLogger(__name__)
19
+ from nautobot.core.celery.control import discard_git_repository, refresh_git_repository # noqa: F401
20
+ from nautobot.core.celery.encoders import NautobotKombuJSONEncoder
21
+ from nautobot.core.celery.log import NautobotDatabaseHandler
22
+
15
23
 
24
+ logger = logging.getLogger(__name__)
16
25
  # The Celery documentation tells us to call setup on the app to initialize
17
26
  # settings, but we will NOT be doing that because of a chicken-and-egg problem
18
27
  # when bootstrapping the Django settings with `nautobot-server`.
@@ -25,7 +34,22 @@ logger = logging.getLogger(__name__)
25
34
  # NOT need to be called here.
26
35
  # nautobot.setup()
27
36
 
28
- app = Celery("nautobot", task_cls="nautobot.core.celery.task:NautobotTask")
37
+
38
+ class NautobotCelery(Celery):
39
+ task_cls = "nautobot.core.celery.task:NautobotTask"
40
+
41
+ def register_task(self, task, **options):
42
+ """Override the default task name for job classes to allow app provided jobs to use the full module path."""
43
+ from nautobot.extras.jobs import Job
44
+
45
+ if issubclass(task, Job):
46
+ task = task()
47
+ task.name = task.registered_name
48
+
49
+ return super().register_task(task, **options)
50
+
51
+
52
+ app = NautobotCelery("nautobot")
29
53
 
30
54
  # Using a string here means the worker doesn't have to serialize
31
55
  # the configuration object to child processes. Again, this is possible
@@ -43,7 +67,83 @@ DjangoFixup(app).install()
43
67
  app.autodiscover_tasks()
44
68
 
45
69
 
46
- @signals.worker_ready.connect()
70
+ @signals.import_modules.connect
71
+ def import_jobs_as_celery_tasks(sender, database_ready=True, **kwargs):
72
+ """
73
+ Import system Jobs into Celery as well as Jobs from JOBS_ROOT and GIT_ROOT.
74
+
75
+ Note that app-provided Jobs are automatically imported at startup time via NautobotAppConfig.ready()
76
+ """
77
+ logger.debug("Importing system Jobs")
78
+ sender.loader.import_task_module("nautobot.core.jobs")
79
+
80
+ jobs_root = settings.JOBS_ROOT
81
+ if jobs_root and os.path.exists(jobs_root):
82
+ if jobs_root not in sys.path:
83
+ sys.path.append(jobs_root)
84
+ for _, module_name, _ in pkgutil.iter_modules([jobs_root]):
85
+ try:
86
+ logger.debug("Importing Jobs from %s in JOBS_ROOT", module_name)
87
+ sender.loader.import_task_module(module_name)
88
+ except Exception as exc:
89
+ # logger.error(f"Unable to load module '{module_name}' from {jobs_root}: {exc:}")
90
+ logger.exception(exc)
91
+
92
+ git_root = settings.GIT_ROOT
93
+ if git_root and os.path.exists(git_root):
94
+ if git_root not in sys.path:
95
+ sys.path.append(git_root)
96
+
97
+ # We can't detect which Git directories we're *supposed* to auto-load Jobs from if we can't read GitRepository
98
+ # records from the DB, unfortunately.
99
+ # We work around this in JobModel.job_task to try later loading Git jobs on-the-fly if needed.
100
+ if database_ready:
101
+ from nautobot.extras.models import GitRepository
102
+
103
+ # Make sure there are no git clones in GIT_ROOT that *aren't* tracked by a GitRepository;
104
+ # for example, maybe a GitRepository was deleted while this worker process wasn't running?
105
+ for filename in os.listdir(git_root):
106
+ filepath = os.path.join(git_root, filename)
107
+ if (
108
+ os.path.isdir(filepath)
109
+ and os.path.isdir(os.path.join(filepath, ".git"))
110
+ and not GitRepository.objects.filter(slug=filename).exists()
111
+ ):
112
+ logger.warning("Deleting unmanaged (leftover?) Git repository clone at %s", filepath)
113
+ shutil.rmtree(filepath)
114
+
115
+ # Make sure all GitRepository records that include Jobs have up-to-date git clones, and load their jobs
116
+ for repo in GitRepository.objects.all():
117
+ refresh_git_repository(state=None, repository_pk=repo.pk, head=repo.current_head)
118
+
119
+
120
+ def add_nautobot_log_handler(logger_instance, log_format=None):
121
+ """Add NautobotDatabaseHandler to logger and update logger level filtering to send all log levels to our handler."""
122
+ if any(isinstance(h, NautobotDatabaseHandler) for h in logger_instance.handlers):
123
+ return
124
+ if logger_instance.level not in (logging.NOTSET, logging.DEBUG):
125
+ for handler in logger_instance.handlers:
126
+ handler.setLevel(logger_instance.level)
127
+ logger_instance.setLevel(logging.DEBUG)
128
+
129
+ if log_format is None:
130
+ log_format = app.conf.worker_task_log_format
131
+ handler = NautobotDatabaseHandler()
132
+ handler.setFormatter(TaskFormatter(log_format, use_color=False))
133
+ logger_instance.addHandler(handler)
134
+
135
+
136
+ @signals.celeryd_after_setup.connect
137
+ def setup_nautobot_job_logging(sender, instance, conf, **kwargs):
138
+ """Add nautobot database logging handler to celery stdout/stderr redirect logger and celery task logger."""
139
+ task_logger = get_logger("celery.task")
140
+ add_nautobot_log_handler(task_logger)
141
+ if conf.worker_redirect_stdouts:
142
+ redirect_logger = get_logger("celery.redirected")
143
+ add_nautobot_log_handler(redirect_logger)
144
+
145
+
146
+ @signals.worker_ready.connect
47
147
  def setup_prometheus(**kwargs):
48
148
  """This sets up an HTTP server to serve prometheus metrics from the celery workers."""
49
149
  # Don't set up the server if the port is undefined
@@ -71,42 +171,6 @@ def setup_prometheus(**kwargs):
71
171
  logger.warning("Cannot export Prometheus metrics from worker, no available ports in range.")
72
172
 
73
173
 
74
- class NautobotKombuJSONEncoder(DjangoJSONEncoder):
75
- """
76
- Custom json encoder based on DjangoJSONEncoder that serializes objects that implement
77
- the `nautobot_serialize()` method via the `__nautobot_type__` interface. This is useful
78
- in passing special objects to and from Celery tasks.
79
-
80
- This pattern should generally be avoided by passing pointers to persisted objects to the
81
- Celery tasks and retrieving them from within the task execution. While this is always possible
82
- for model instances (which covers 99% of use cases), for rare instances where it does not,
83
- and the actual object must be passed, this pattern allows for encoding and decoding
84
- of such objects.
85
-
86
- It requires a conforming class to implement the instance method `nautobot_serialize()` which
87
- returns a json serializable dictionary of the object representation. The class must also implement
88
- the `nautobot_deserialize()` class method which takes the dictionary representation and returns
89
- an actual instance of the class.
90
- """
91
-
92
- def default(self, obj):
93
- if hasattr(obj, "nautobot_serialize"):
94
- cls = obj.__class__
95
- module = cls.__module__
96
- qual_name = ".".join([module, cls.__qualname__]) # fully qualified dotted import path
97
- logger.debug("Performing nautobot serialization on %s for type %s", obj, qual_name)
98
- data = {"__nautobot_type__": qual_name}
99
- data.update(obj.nautobot_serialize())
100
- return data
101
-
102
- elif isinstance(obj, set):
103
- # Convert a set to a list for passing to and from a task
104
- return list(obj)
105
-
106
- else:
107
- return DjangoJSONEncoder.default(self, obj)
108
-
109
-
110
174
  def nautobot_kombu_json_loads_hook(data):
111
175
  """
112
176
  In concert with the NautobotKombuJSONEncoder json encoder, this object hook method decodes
@@ -117,7 +181,7 @@ def nautobot_kombu_json_loads_hook(data):
117
181
  logger.debug("Performing nautobot deserialization for type %s", qual_name)
118
182
  cls = import_string(qual_name) # fully qualified dotted import path
119
183
  if cls:
120
- return cls.nautobot_deserialize(data)
184
+ return SimpleLazyObject(lambda: cls.objects.get(id=data["id"]))
121
185
  else:
122
186
  raise TypeError(f"Unable to import {qual_name} during nautobot deserialization")
123
187
  else:
@@ -148,3 +212,10 @@ register("nautobot_json", _dumps, _loads, content_type="application/x-nautobot-j
148
212
  #
149
213
 
150
214
  nautobot_task = shared_task
215
+
216
+
217
+ def register_jobs(*jobs):
218
+ """Helper method to register jobs with Celery"""
219
+ for job in jobs:
220
+ logger.debug("Registering job %s.%s", job.__module__, job.__name__)
221
+ app.register_task(job)
@@ -1,5 +1,6 @@
1
1
  from django_celery_results.backends import DatabaseBackend
2
2
 
3
+ from nautobot.extras.constants import JOB_RESULT_CUSTOM_CELERY_KWARGS
3
4
  from nautobot.extras.models import JobResult
4
5
 
5
6
 
@@ -20,38 +21,44 @@ class NautobotDatabaseBackend(DatabaseBackend):
20
21
 
21
22
  def _get_extended_properties(self, request, traceback):
22
23
  """
23
- Overload default so that `argsrepr` and `kwargsrepr` aren't used to construct `args` and
24
- `kwargs`. Our need to properly (de)serialize `NautobotFakeRequest` facilitates this.
24
+ Overload default so that `argsrepr` and `kwargsrepr` aren't used to construct `args` and `kwargs`.
25
+ Also adds custom kwargs passed in on `apply_async` calls to track user, job model, scheduled job, etc.
25
26
  """
26
27
  extended_props = {
27
- "periodic_task_name": None,
28
28
  "task_args": None,
29
29
  "task_kwargs": None,
30
+ "celery_kwargs": None,
31
+ "job_model_id": None,
32
+ "scheduled_job_id": None,
30
33
  "task_name": None,
31
34
  "traceback": None,
35
+ "user_id": None,
32
36
  "worker": None,
33
37
  }
34
38
  if request and self.app.conf.find_value_for_key("extended", "result"):
35
- # Let's not dump/encode args/kwargs at all in fact.
39
+ # do not encode args/kwargs as we store these in a JSONField instead of TextField
36
40
  task_args = getattr(request, "args", None)
37
41
  task_kwargs = getattr(request, "kwargs", None)
38
42
 
39
- # Encode input arguments
40
- if task_args is not None:
41
- _, _, task_args = self.encode_content(task_args)
43
+ properties = getattr(request, "properties", {}) or {}
42
44
 
43
- if task_kwargs is not None:
44
- _, _, task_kwargs = self.encode_content(task_kwargs)
45
+ # retrieve original "queue" kwarg from the request, celery stores it in delivery_info.routing_key
46
+ celery_kwargs = {"queue": request.delivery_info.get("routing_key", None)}
47
+
48
+ for kwarg_name in JOB_RESULT_CUSTOM_CELERY_KWARGS:
49
+ if kwarg_name in properties:
50
+ celery_kwargs[kwarg_name] = properties[kwarg_name]
45
51
 
46
- properties = getattr(request, "properties", {}) or {}
47
- periodic_task_name = properties.get("periodic_task_name", None)
48
52
  extended_props.update(
49
53
  {
50
- "periodic_task_name": periodic_task_name,
51
54
  "task_args": task_args,
52
55
  "task_kwargs": task_kwargs,
56
+ "celery_kwargs": celery_kwargs,
57
+ "job_model_id": properties.get("nautobot_job_job_model_id", None),
58
+ "scheduled_job_id": properties.get("nautobot_job_scheduled_job_id", None),
53
59
  "task_name": getattr(request, "task", None),
54
60
  "traceback": traceback,
61
+ "user_id": properties.get("nautobot_job_user_id", None),
55
62
  "worker": getattr(request, "hostname", None),
56
63
  }
57
64
  )
@@ -0,0 +1,46 @@
1
+ import logging
2
+ import os
3
+ import shutil
4
+
5
+ from celery.worker.control import control_command
6
+
7
+ from django.conf import settings
8
+
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ @control_command(args=[("repository_pk", str), ("head", str)])
14
+ def refresh_git_repository(state, repository_pk, head):
15
+ """
16
+ Celery worker control event to ensure that all active workers have the correct head for a given Git repository.
17
+ """
18
+ from nautobot.extras.datasources.git import ensure_git_repository, refresh_code_from_repository
19
+ from nautobot.extras.models import GitRepository
20
+
21
+ try:
22
+ repository = GitRepository.objects.get(pk=repository_pk)
23
+ # Refresh the repository on disk
24
+ ensure_git_repository(repository, head=head, logger=logger)
25
+ refresh_code_from_repository(repository.slug, consumer=state.consumer if state is not None else None)
26
+
27
+ return {"ok": {"head": repository.current_head}}
28
+ except Exception as exc:
29
+ logger.error("%s", exc)
30
+ return {"error": str(exc)}
31
+
32
+
33
+ @control_command(args=["repository_slug", str])
34
+ def discard_git_repository(state, repository_slug):
35
+ """
36
+ Celery worker control even to ensure that all active workers unload a given Git repository and delete it from disk.
37
+ """
38
+ from nautobot.extras.datasources.git import refresh_code_from_repository
39
+
40
+ filesystem_path = os.path.join(settings.GIT_ROOT, repository_slug)
41
+ if os.path.isdir(filesystem_path):
42
+ shutil.rmtree(filesystem_path)
43
+ # Unload any code from this repository
44
+ refresh_code_from_repository(
45
+ repository_slug, consumer=state.consumer if state is not None else None, skip_reimport=True
46
+ )
@@ -0,0 +1,53 @@
1
+ import logging
2
+
3
+ from rest_framework.utils.encoders import JSONEncoder
4
+
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ class NautobotKombuJSONEncoder(JSONEncoder):
10
+ """
11
+ Custom json encoder based on restframework's JSONEncoder that serializes objects that implement
12
+ the `nautobot_serialize()` method via the `__nautobot_type__` interface. This is useful
13
+ in passing special objects to and from Celery tasks.
14
+
15
+ This pattern should generally be avoided by passing pointers to persisted objects to the
16
+ Celery tasks and retrieving them from within the task execution. While this is always possible
17
+ for model instances (which covers 99% of use cases), for rare instances where it does not,
18
+ and the actual object must be passed, this pattern allows for encoding and decoding
19
+ of such objects.
20
+
21
+ It requires a conforming class to implement the instance method `nautobot_serialize()` which
22
+ returns a json serializable dictionary of the object representation. The class must also implement
23
+ the `nautobot_deserialize()` class method which takes the dictionary representation and returns
24
+ an actual instance of the class.
25
+ """
26
+
27
+ def default(self, obj):
28
+ # Import here to avoid django.core.exceptions.ImproperlyConfigured Error.
29
+ # Core App is not set up yet if we import this at the top of the file.
30
+ from nautobot.core.models import BaseModel
31
+ from nautobot.core.models.managers import TagsManager
32
+
33
+ if isinstance(obj, BaseModel):
34
+ cls = obj.__class__
35
+ module = cls.__module__
36
+ qual_name = ".".join([module, cls.__qualname__]) # fully qualified dotted import path
37
+ logger.debug("Performing nautobot serialization on %s for type %s", obj, qual_name)
38
+ data = {
39
+ "id": obj.id,
40
+ "__nautobot_type__": qual_name,
41
+ # TODO: change to natural key to provide additional context if object is deleted from the db
42
+ "display": getattr(obj, "display", str(obj)),
43
+ }
44
+ return data
45
+
46
+ elif isinstance(obj, set):
47
+ # Convert a set to a list for passing to and from a task
48
+ return list(obj)
49
+ elif isinstance(obj, TagsManager):
50
+ obj = obj.values_list("id", flat=True)
51
+ return obj
52
+ else:
53
+ return super().default(obj)
@@ -0,0 +1,38 @@
1
+ import logging
2
+
3
+ from celery import current_task
4
+ from django.core.exceptions import ValidationError
5
+
6
+
7
+ class NautobotDatabaseHandler(logging.Handler):
8
+ """Custom logging handler to log messages to JobLogEntry database entries."""
9
+
10
+ def emit(self, record):
11
+ if current_task is None:
12
+ return
13
+
14
+ from nautobot.extras.models.jobs import JobResult
15
+
16
+ try:
17
+ self.format(record)
18
+
19
+ try:
20
+ job_result = JobResult.objects.get(id=record.task_id)
21
+ except (ValidationError, JobResult.DoesNotExist):
22
+ # Both of these cases are very rare
23
+ # ValidationError - because the task_id might not a valid UUID
24
+ # JobResult.DoesNotExist - because we might not have a JobResult with that ID
25
+ return
26
+
27
+ # Skip recording the log entry if it has been marked as such
28
+ if getattr(record, "skip_db_logging", False):
29
+ return
30
+
31
+ job_result.log(
32
+ message=record.message,
33
+ level_choice=record.levelname.lower(),
34
+ obj=getattr(record, "object", None),
35
+ grouping=getattr(record, "grouping", record.funcName),
36
+ )
37
+ except Exception:
38
+ self.handleError(record)
@@ -1,3 +1,4 @@
1
+ from collections.abc import Mapping
1
2
  import logging
2
3
 
3
4
  from celery import current_app
@@ -38,11 +39,29 @@ class NautobotScheduleEntry(ModelEntry):
38
39
  )
39
40
  self._disable(model)
40
41
 
41
- self.options = {}
42
- if model.queue:
43
- self.options["queue"] = model.queue
42
+ self.options = {"nautobot_job_scheduled_job_id": model.id, "headers": {}}
43
+
44
+ if model.user:
45
+ self.options["nautobot_job_user_id"] = model.user.id
46
+ else:
47
+ logger.error(
48
+ "Disabling schedule %s with missing user",
49
+ self.name,
50
+ )
51
+ self._disable(model)
52
+
53
+ if model.job_model:
54
+ self.options["nautobot_job_job_model_id"] = model.job_model.id
55
+ else:
56
+ logger.error(
57
+ "Disabling schedule %s with missing job model",
58
+ self.name,
59
+ )
60
+ self._disable(model)
61
+
62
+ if isinstance(model.celery_kwargs, Mapping):
63
+ self.options.update(model.celery_kwargs)
44
64
 
45
- self.options["headers"] = {}
46
65
  self.total_run_count = model.total_run_count
47
66
  self.model = model
48
67
 
@@ -1,6 +1,6 @@
1
- from celery.utils.log import get_task_logger
2
1
  from celery import Task
3
2
 
3
+ from nautobot.extras.jobs import get_task_logger
4
4
 
5
5
  logger = get_task_logger(__name__)
6
6
 
@@ -10,18 +10,3 @@ class NautobotTask(Task):
10
10
 
11
11
 
12
12
  Task = NautobotTask # noqa: So that the class path resolves.
13
-
14
-
15
- # TODO(jathan): Remove this once this body of work is done. This is just useful for debugging but it
16
- # results int a lot of noise and slows things down.
17
- # from celery import signals
18
- # @signals.task_prerun.connect
19
- def debug_task_prerun(sender, task_id, task, args, kwargs, **extra):
20
- logger.error(">>> SENDER = %s", sender)
21
- logger.error(">>> TASK = %s", task)
22
- logger.error(">>> REQUEST = %s", task.request)
23
- logger.error(">>> TASK_NAME = %s", task.request.task)
24
- logger.error(">>> TASK_ID = %s", task_id)
25
- logger.error(">>> ARGS = %s", args)
26
- logger.error(">>> KWARGS = %s", kwargs)
27
- logger.error(">>> EXTRA = %s", extra)
nautobot/core/checks.py CHANGED
@@ -6,12 +6,6 @@ from django.core.exceptions import ValidationError
6
6
  from django.core.validators import URLValidator
7
7
 
8
8
 
9
- E001 = Error(
10
- "CACHEOPS_DEFAULTS['timeout'] value cannot be 0. To disable caching set CACHEOPS_ENABLED=False.",
11
- id="nautobot.core.E001",
12
- obj=settings,
13
- )
14
-
15
9
  E002 = Error(
16
10
  "'nautobot.core.authentication.ObjectPermissionBackend' must be included in AUTHENTICATION_BACKENDS",
17
11
  id="nautobot.core.E002",
@@ -42,20 +36,6 @@ W005 = Warning(
42
36
  obj=settings,
43
37
  )
44
38
 
45
- W006 = Warning(
46
- "CACHEOPS_ENABLED is set to True but cacheops is no longer recommended in v1.5. It can still be used but may lead to "
47
- "inaccurate data responses. Cacheops will be removed in a later release.",
48
- id="nautobot.core.W006",
49
- obj=settings,
50
- )
51
-
52
-
53
- @register(Tags.caches)
54
- def check_cache_timeout(app_configs, **kwargs):
55
- if settings.CACHEOPS_DEFAULTS.get("timeout") == 0:
56
- return [E001]
57
- return []
58
-
59
39
 
60
40
  @register(Tags.security)
61
41
  def check_object_permissions_backend(app_configs, **kwargs):
@@ -96,13 +76,6 @@ def check_maintenance_mode(app_configs, **kwargs):
96
76
  return []
97
77
 
98
78
 
99
- @register(Tags.compatibility)
100
- def check_cacheops_enabled(app_configs, **kwargs):
101
- if settings.CACHEOPS_ENABLED:
102
- return [W006]
103
- return []
104
-
105
-
106
79
  @register(Tags.security)
107
80
  def check_sanitizer_patterns(app_configs, **kwargs):
108
81
  errors = []
nautobot/core/choices.py CHANGED
@@ -167,116 +167,3 @@ class ColorChoices(ChoiceSet):
167
167
  (COLOR_BLACK, "Black"),
168
168
  (COLOR_WHITE, "White"),
169
169
  )
170
-
171
-
172
- #
173
- # Button color choices
174
- #
175
-
176
-
177
- class ButtonColorChoices(ChoiceSet):
178
- """
179
- Map standard button color choices to Bootstrap color classes
180
- """
181
-
182
- DEFAULT = "default"
183
- BLUE = "primary"
184
- GREY = "secondary"
185
- GREEN = "success"
186
- RED = "danger"
187
- YELLOW = "warning"
188
- BLACK = "dark"
189
-
190
- CHOICES = (
191
- (DEFAULT, "Default"),
192
- (BLUE, "Blue"),
193
- (GREY, "Grey"),
194
- (GREEN, "Green"),
195
- (RED, "Red"),
196
- (YELLOW, "Yellow"),
197
- (BLACK, "Black"),
198
- )
199
-
200
-
201
- class ButtonActionColorChoices(ChoiceSet):
202
- """
203
- Map standard button actions to Bootstrap color classes.
204
- """
205
-
206
- ADD = "success"
207
- CANCEL = "default"
208
- CLONE = "success"
209
- CONFIGURE = "default"
210
- CONNECT = "success"
211
- DEFAULT = "default"
212
- DELETE = "danger"
213
- DISCONNECT = "info"
214
- EDIT = "warning"
215
- EXPORT = "success"
216
- IMPORT = "primary"
217
- INFO = "info"
218
- SUBMIT = "primary"
219
- SWAP = "primary"
220
-
221
- CHOICES = (
222
- (ADD, "Add"),
223
- (CANCEL, "Cancel"),
224
- (CLONE, "Clone"),
225
- (CONFIGURE, "Configure"),
226
- (CONNECT, "Connect"),
227
- (DEFAULT, "Default"),
228
- (DELETE, "Delete"),
229
- (DISCONNECT, "Disconnect"),
230
- (EDIT, "Edit"),
231
- (EXPORT, "Export"),
232
- (IMPORT, "Import"),
233
- (INFO, "Info"),
234
- (SUBMIT, "Submit"),
235
- (SWAP, "Swap"),
236
- )
237
-
238
-
239
- class ButtonActionIconChoices(ChoiceSet):
240
- """
241
- Map standard button actions to Material Design Icons classes.
242
- """
243
-
244
- ADD = "mdi-plus-thick"
245
- ALERT = "mdi-alert"
246
- ARROW_DOWN = "mdi-arrow-down-bold"
247
- ARROW_UP = "mdi-arrow-up-bold"
248
- CONFIGURE = "mdi-cogs"
249
- CONNECT = "mdi-ethernet-cable"
250
- DELETE = "mdi-trash-can-outline"
251
- DISCONNECT = "mdi-ethernet-cable-off"
252
- EDIT = "mdi-pencil"
253
- EXPORT = "mdi-database-export-outline"
254
- HELP = "mdi-help-circle"
255
- INFO = "mdi-help-circle"
256
- IMPORT = "mdi-database-import-outline"
257
- LOCK = "mdi-lock"
258
- MAGNIFY = "mdi-magnify"
259
- NOTE = "mdi-note-text"
260
- SWAP = "mdi-swap-vertical"
261
- TRASH = "mdi-trash-can-outline"
262
-
263
- CHOICES = (
264
- (ADD, "Add"),
265
- (ALERT, "Alert"),
266
- (ARROW_DOWN, "Arrow Down"),
267
- (ARROW_UP, "Arrow Up"),
268
- (CONFIGURE, "Configure"),
269
- (CONNECT, "Connect"),
270
- (DELETE, "Delete"),
271
- (DISCONNECT, "Disconnect"),
272
- (EDIT, "Edit"),
273
- (EXPORT, "Export"),
274
- (HELP, "Help"),
275
- (INFO, "Info"),
276
- (IMPORT, "Import"),
277
- (LOCK, "Lock"),
278
- (MAGNIFY, "Magnify"),
279
- (NOTE, "Note"),
280
- (SWAP, "Swap"),
281
- (TRASH, "Trash"),
282
- )
@@ -27,7 +27,7 @@ SETTINGS_ENVVAR = "NAUTOBOT_CONFIG"
27
27
  BASE_DIR = os.path.dirname(__file__)
28
28
 
29
29
  # File path of template used to generate config emitted by `init`
30
- CONFIG_TEMPLATE = os.path.join(BASE_DIR, "templates/nautobot_config.py.j2")
30
+ CONFIG_TEMPLATE = os.path.join(BASE_DIR, "../templates/nautobot_config.py.j2")
31
31
 
32
32
  DESCRIPTION = """
33
33
  Nautobot server management utility.
@@ -0,0 +1,3 @@
1
+ from nautobot.core.cli import main
2
+
3
+ main()
@@ -32,30 +32,6 @@ FILTER_NUMERIC_BASED_LOOKUP_MAP = {
32
32
 
33
33
  FILTER_NEGATION_LOOKUP_MAP = {"n": "exact"}
34
34
 
35
-
36
- #
37
- # HTTP Request META safe copy
38
- #
39
-
40
- HTTP_REQUEST_META_SAFE_COPY = [
41
- "CONTENT_LENGTH",
42
- "CONTENT_TYPE",
43
- "HTTP_ACCEPT",
44
- "HTTP_ACCEPT_ENCODING",
45
- "HTTP_ACCEPT_LANGUAGE",
46
- "HTTP_HOST",
47
- "HTTP_REFERER",
48
- "HTTP_USER_AGENT",
49
- "QUERY_STRING",
50
- "REMOTE_ADDR",
51
- "REMOTE_HOST",
52
- "REMOTE_USER",
53
- "REQUEST_METHOD",
54
- "SERVER_NAME",
55
- "SERVER_PORT",
56
- ]
57
-
58
-
59
35
  #
60
36
  # Factory defaults
61
37
  #