nautobot 2.2.2__py3-none-any.whl → 2.2.4__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 (362) hide show
  1. nautobot/apps/jobs.py +2 -0
  2. nautobot/core/api/utils.py +12 -9
  3. nautobot/core/apps/__init__.py +2 -2
  4. nautobot/core/celery/__init__.py +79 -68
  5. nautobot/core/celery/backends.py +9 -1
  6. nautobot/core/celery/control.py +4 -7
  7. nautobot/core/celery/schedulers.py +4 -2
  8. nautobot/core/celery/task.py +78 -5
  9. nautobot/core/graphql/schema.py +2 -1
  10. nautobot/core/jobs/__init__.py +2 -1
  11. nautobot/core/settings.py +6 -4
  12. nautobot/core/settings.yaml +51 -16
  13. nautobot/core/templates/admin/base.html +2 -2
  14. nautobot/core/templates/base_django.html +2 -2
  15. nautobot/core/templates/buttons/export.html +47 -47
  16. nautobot/core/templates/generic/object_list.html +3 -3
  17. nautobot/core/templates/inc/javascript.html +3 -0
  18. nautobot/core/templates/inc/media.html +3 -0
  19. nautobot/core/templates/login.html +2 -2
  20. nautobot/core/templates/nautobot_config.py.j2 +2 -0
  21. nautobot/core/templatetags/helpers.py +66 -9
  22. nautobot/core/testing/__init__.py +6 -1
  23. nautobot/core/testing/api.py +12 -13
  24. nautobot/core/testing/mixins.py +2 -2
  25. nautobot/core/testing/views.py +50 -51
  26. nautobot/core/tests/test_api.py +23 -2
  27. nautobot/core/tests/test_jobs.py +79 -2
  28. nautobot/core/tests/test_templatetags_helpers.py +32 -0
  29. nautobot/core/tests/test_views.py +52 -0
  30. nautobot/core/tests/test_views_utils.py +22 -1
  31. nautobot/core/utils/module_loading.py +89 -0
  32. nautobot/core/views/mixins.py +4 -0
  33. nautobot/core/views/utils.py +3 -2
  34. nautobot/dcim/choices.py +14 -0
  35. nautobot/dcim/forms.py +51 -1
  36. nautobot/dcim/models/device_components.py +9 -5
  37. nautobot/dcim/templates/dcim/location.html +32 -13
  38. nautobot/dcim/templates/dcim/location_migrate_data_to_contact.html +102 -0
  39. nautobot/dcim/tests/test_views.py +376 -55
  40. nautobot/dcim/urls.py +5 -0
  41. nautobot/dcim/views.py +172 -21
  42. nautobot/extras/api/serializers.py +17 -6
  43. nautobot/extras/api/views.py +21 -10
  44. nautobot/extras/constants.py +3 -3
  45. nautobot/extras/datasources/git.py +47 -58
  46. nautobot/extras/forms/forms.py +3 -1
  47. nautobot/extras/jobs.py +79 -146
  48. nautobot/extras/models/datasources.py +0 -2
  49. nautobot/extras/models/jobs.py +36 -18
  50. nautobot/extras/plugins/__init__.py +1 -20
  51. nautobot/extras/signals.py +6 -9
  52. nautobot/extras/test_jobs/__init__.py +8 -0
  53. nautobot/extras/test_jobs/dry_run.py +3 -2
  54. nautobot/extras/test_jobs/fail.py +43 -0
  55. nautobot/extras/test_jobs/ipaddress_vars.py +40 -1
  56. nautobot/extras/test_jobs/jobs_module/__init__.py +5 -0
  57. nautobot/extras/test_jobs/jobs_module/jobs_submodule/__init__.py +1 -0
  58. nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +6 -0
  59. nautobot/extras/test_jobs/pass.py +40 -0
  60. nautobot/extras/test_jobs/relative_import.py +11 -0
  61. nautobot/extras/tests/test_api.py +3 -0
  62. nautobot/extras/tests/test_context_managers.py +18 -0
  63. nautobot/extras/tests/test_datasources.py +125 -118
  64. nautobot/extras/tests/test_job_variables.py +57 -15
  65. nautobot/extras/tests/test_jobs.py +135 -1
  66. nautobot/extras/tests/test_models.py +26 -19
  67. nautobot/extras/tests/test_plugins.py +1 -3
  68. nautobot/extras/tests/test_views.py +2 -4
  69. nautobot/extras/utils.py +2 -1
  70. nautobot/extras/views.py +82 -116
  71. nautobot/ipam/api/views.py +8 -1
  72. nautobot/ipam/graphql/types.py +11 -0
  73. nautobot/ipam/mixins.py +32 -0
  74. nautobot/ipam/models.py +2 -1
  75. nautobot/ipam/querysets.py +6 -1
  76. nautobot/ipam/tests/test_models.py +82 -0
  77. nautobot/ipam/views.py +6 -6
  78. nautobot/project-static/docs/404.html +107 -51
  79. nautobot/project-static/docs/apps/index.html +107 -51
  80. nautobot/project-static/docs/apps/nautobot-apps.html +107 -51
  81. nautobot/project-static/docs/assets/_mkdocstrings.css +6 -1
  82. nautobot/project-static/docs/assets/extra.css +11 -0
  83. nautobot/project-static/docs/assets/javascripts/bundle.3220b9d7.min.js +29 -0
  84. nautobot/project-static/docs/assets/javascripts/bundle.3220b9d7.min.js.map +7 -0
  85. nautobot/project-static/docs/assets/stylesheets/main.66ac8b77.min.css +1 -0
  86. nautobot/project-static/docs/assets/stylesheets/main.66ac8b77.min.css.map +1 -0
  87. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +107 -51
  88. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +107 -51
  89. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +108 -52
  90. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +107 -51
  91. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +107 -51
  92. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +107 -51
  93. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +107 -51
  94. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +107 -51
  95. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +107 -51
  96. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +107 -51
  97. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +107 -51
  98. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +107 -51
  99. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +107 -51
  100. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +287 -262
  101. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +107 -51
  102. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +107 -51
  103. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +107 -51
  104. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +107 -51
  105. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +107 -51
  106. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +107 -51
  107. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +107 -51
  108. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +107 -51
  109. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +107 -51
  110. nautobot/project-static/docs/development/apps/api/configuration-view.html +110 -54
  111. nautobot/project-static/docs/development/apps/api/database-backend-config.html +110 -54
  112. nautobot/project-static/docs/development/apps/api/models/django-admin.html +107 -51
  113. nautobot/project-static/docs/development/apps/api/models/global-search.html +110 -54
  114. nautobot/project-static/docs/development/apps/api/models/graphql.html +113 -57
  115. nautobot/project-static/docs/development/apps/api/models/index.html +107 -51
  116. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +113 -57
  117. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +107 -51
  118. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +110 -54
  119. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +107 -51
  120. nautobot/project-static/docs/development/apps/api/platform-features/index.html +107 -51
  121. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +110 -54
  122. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +111 -55
  123. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +110 -54
  124. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +110 -54
  125. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +107 -51
  126. nautobot/project-static/docs/development/apps/api/prometheus.html +110 -54
  127. nautobot/project-static/docs/development/apps/api/setup.html +107 -51
  128. nautobot/project-static/docs/development/apps/api/testing.html +113 -57
  129. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +110 -54
  130. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +110 -54
  131. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +107 -51
  132. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +107 -51
  133. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +113 -57
  134. nautobot/project-static/docs/development/apps/api/views/base-template.html +107 -51
  135. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +110 -54
  136. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +107 -51
  137. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +110 -54
  138. nautobot/project-static/docs/development/apps/api/views/index.html +107 -51
  139. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +113 -57
  140. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +122 -66
  141. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +110 -54
  142. nautobot/project-static/docs/development/apps/api/views/notes.html +110 -54
  143. nautobot/project-static/docs/development/apps/api/views/rest-api.html +107 -51
  144. nautobot/project-static/docs/development/apps/api/views/urls.html +107 -51
  145. nautobot/project-static/docs/development/apps/index.html +128 -72
  146. nautobot/project-static/docs/development/apps/migration/code-updates.html +107 -51
  147. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +107 -51
  148. nautobot/project-static/docs/development/apps/migration/from-v1.html +107 -51
  149. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +107 -51
  150. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +107 -51
  151. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +107 -51
  152. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +107 -51
  153. nautobot/project-static/docs/development/apps/porting-from-netbox.html +110 -54
  154. nautobot/project-static/docs/development/core/application-registry.html +242 -144
  155. nautobot/project-static/docs/development/core/best-practices.html +122 -66
  156. nautobot/project-static/docs/development/core/bootstrap-ui.html +107 -51
  157. nautobot/project-static/docs/development/core/caching.html +107 -51
  158. nautobot/project-static/docs/development/core/controllers.html +107 -51
  159. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +113 -57
  160. nautobot/project-static/docs/development/core/generic-views.html +110 -54
  161. nautobot/project-static/docs/development/core/getting-started.html +135 -79
  162. nautobot/project-static/docs/development/core/homepage.html +110 -54
  163. nautobot/project-static/docs/development/core/index.html +107 -51
  164. nautobot/project-static/docs/development/core/model-checklist.html +156 -52
  165. nautobot/project-static/docs/development/core/model-features.html +108 -52
  166. nautobot/project-static/docs/development/core/natural-keys.html +110 -54
  167. nautobot/project-static/docs/development/core/navigation-menu.html +107 -51
  168. nautobot/project-static/docs/development/core/release-checklist.html +107 -51
  169. nautobot/project-static/docs/development/core/role-internals.html +107 -51
  170. nautobot/project-static/docs/development/core/settings.html +107 -51
  171. nautobot/project-static/docs/development/core/style-guide.html +110 -54
  172. nautobot/project-static/docs/development/core/templates.html +113 -57
  173. nautobot/project-static/docs/development/core/testing.html +125 -69
  174. nautobot/project-static/docs/development/core/user-preferences.html +107 -51
  175. nautobot/project-static/docs/development/index.html +107 -51
  176. nautobot/project-static/docs/development/jobs/index.html +504 -172
  177. nautobot/project-static/docs/development/jobs/migration/from-v1.html +111 -55
  178. nautobot/project-static/docs/docker/index.html +3 -3
  179. nautobot/project-static/docs/index.html +125 -69
  180. nautobot/project-static/docs/installation/selinux-troubleshooting.html +3 -3
  181. nautobot/project-static/docs/objects.inv +0 -0
  182. nautobot/project-static/docs/release-notes/index.html +107 -51
  183. nautobot/project-static/docs/release-notes/version-1.0.html +107 -51
  184. nautobot/project-static/docs/release-notes/version-1.1.html +107 -51
  185. nautobot/project-static/docs/release-notes/version-1.2.html +107 -51
  186. nautobot/project-static/docs/release-notes/version-1.3.html +107 -51
  187. nautobot/project-static/docs/release-notes/version-1.4.html +107 -51
  188. nautobot/project-static/docs/release-notes/version-1.5.html +116 -60
  189. nautobot/project-static/docs/release-notes/version-1.6.html +107 -51
  190. nautobot/project-static/docs/release-notes/version-2.0.html +110 -54
  191. nautobot/project-static/docs/release-notes/version-2.1.html +107 -51
  192. nautobot/project-static/docs/release-notes/version-2.2.html +500 -114
  193. nautobot/project-static/docs/requirements.txt +2 -2
  194. nautobot/project-static/docs/search/search_index.json +1 -1
  195. nautobot/project-static/docs/sitemap.xml +262 -262
  196. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  197. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +107 -51
  198. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +107 -51
  199. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +107 -51
  200. nautobot/project-static/docs/user-guide/administration/configuration/index.html +107 -51
  201. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +251 -164
  202. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +113 -57
  203. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +107 -51
  204. nautobot/project-static/docs/user-guide/administration/guides/caching.html +113 -57
  205. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +107 -51
  206. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +107 -51
  207. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +107 -51
  208. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +113 -57
  209. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +107 -51
  210. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +107 -51
  211. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +107 -51
  212. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +171 -112
  213. nautobot/project-static/docs/user-guide/administration/installation/docker.html +13 -8626
  214. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +117 -61
  215. nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +13 -8614
  216. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +252 -165
  217. nautobot/project-static/docs/user-guide/administration/installation/index.html +165 -192
  218. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +411 -691
  219. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +248 -229
  220. nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +13 -8118
  221. nautobot/project-static/docs/user-guide/administration/installation/services.html +350 -240
  222. nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +8684 -0
  223. nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +8672 -0
  224. nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +8176 -0
  225. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +110 -54
  226. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +110 -54
  227. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +155 -99
  228. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +107 -51
  229. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +109 -53
  230. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +107 -51
  231. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +107 -51
  232. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +107 -51
  233. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +107 -51
  234. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +107 -51
  235. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +107 -51
  236. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +117 -58
  237. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +113 -57
  238. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +107 -51
  239. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +107 -51
  240. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +107 -51
  241. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +107 -51
  242. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +110 -54
  243. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +107 -51
  244. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +110 -54
  245. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +110 -54
  246. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +110 -54
  247. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +110 -54
  248. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +107 -51
  249. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +107 -51
  250. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +113 -57
  251. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +110 -54
  252. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +110 -54
  253. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +110 -54
  254. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +110 -54
  255. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +116 -60
  256. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +110 -54
  257. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +110 -54
  258. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +119 -63
  259. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +110 -54
  260. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +110 -54
  261. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +113 -57
  262. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +113 -57
  263. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +113 -57
  264. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +107 -51
  265. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +113 -57
  266. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +107 -51
  267. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +110 -54
  268. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +110 -54
  269. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +107 -51
  270. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +110 -54
  271. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +110 -54
  272. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +107 -51
  273. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +107 -51
  274. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +107 -51
  275. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +110 -54
  276. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +110 -54
  277. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +110 -54
  278. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +110 -54
  279. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +107 -51
  280. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +113 -57
  281. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +110 -54
  282. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +110 -54
  283. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +110 -54
  284. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +125 -69
  285. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +113 -57
  286. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +128 -72
  287. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +110 -54
  288. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +107 -51
  289. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +110 -54
  290. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +227 -60
  291. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +107 -51
  292. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +113 -57
  293. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +107 -51
  294. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +110 -54
  295. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +107 -51
  296. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +107 -51
  297. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +107 -51
  298. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +107 -51
  299. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +113 -57
  300. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +113 -57
  301. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +107 -51
  302. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +113 -57
  303. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +107 -51
  304. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +107 -51
  305. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +107 -51
  306. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +107 -51
  307. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +107 -51
  308. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +107 -51
  309. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +107 -51
  310. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +107 -51
  311. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +107 -51
  312. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +110 -54
  313. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +113 -57
  314. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +107 -51
  315. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +110 -54
  316. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +107 -51
  317. nautobot/project-static/docs/user-guide/index.html +109 -53
  318. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +107 -51
  319. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +113 -57
  320. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +128 -72
  321. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +107 -51
  322. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +125 -69
  323. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +107 -51
  324. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +110 -54
  325. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +125 -69
  326. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +110 -54
  327. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +107 -51
  328. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +107 -51
  329. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +143 -100
  330. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +113 -57
  331. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +113 -57
  332. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +110 -54
  333. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +123 -67
  334. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +107 -51
  335. nautobot/project-static/docs/user-guide/platform-functionality/note.html +110 -54
  336. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +116 -60
  337. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +110 -54
  338. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +131 -75
  339. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +149 -93
  340. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +110 -54
  341. nautobot/project-static/docs/user-guide/platform-functionality/role.html +107 -51
  342. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +116 -60
  343. nautobot/project-static/docs/user-guide/platform-functionality/status.html +119 -63
  344. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +110 -54
  345. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +137 -81
  346. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +110 -54
  347. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +107 -51
  348. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +110 -54
  349. nautobot/project-static/js/forms.js +18 -11
  350. nautobot/tenancy/views.py +2 -6
  351. nautobot/virtualization/views.py +5 -9
  352. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/METADATA +4 -4
  353. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/RECORD +357 -348
  354. nautobot/extras/test_jobs/job_variables.py +0 -93
  355. nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js +0 -29
  356. nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js.map +0 -7
  357. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +0 -1
  358. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +0 -1
  359. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/LICENSE.txt +0 -0
  360. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/NOTICE +0 -0
  361. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/WHEEL +0 -0
  362. {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/entry_points.txt +0 -0
nautobot/apps/jobs.py CHANGED
@@ -12,6 +12,7 @@ from nautobot.extras.jobs import (
12
12
  enqueue_job_hooks,
13
13
  FileVar,
14
14
  get_job,
15
+ get_jobs,
15
16
  IntegerVar,
16
17
  IPAddressVar,
17
18
  IPAddressWithMaskVar,
@@ -40,6 +41,7 @@ __all__ = (
40
41
  "enqueue_job_hooks",
41
42
  "FileVar",
42
43
  "get_job",
44
+ "get_jobs",
43
45
  "GitRepositoryDryRun",
44
46
  "GitRepositorySync",
45
47
  "IntegerVar",
@@ -167,28 +167,31 @@ def is_api_request(request):
167
167
  return request.path_info.startswith(api_path)
168
168
 
169
169
 
170
- def get_view_name(view, suffix=None):
170
+ def get_view_name(view):
171
171
  """
172
172
  Derive the view name from its associated model, if it has one. Fall back to DRF's built-in `get_view_name`.
173
173
  """
174
- if hasattr(view, "queryset"):
174
+ if hasattr(view, "name") and view.name:
175
+ return view.name
176
+ elif hasattr(view, "queryset"):
175
177
  # Determine the model name from the queryset.
176
- name = view.queryset.model._meta.verbose_name
178
+ if hasattr(view, "detail") and view.detail:
179
+ name = view.queryset.model._meta.verbose_name
180
+ else:
181
+ name = view.queryset.model._meta.verbose_name_plural
177
182
  name = " ".join([w[0].upper() + w[1:] for w in name.split()]) # Capitalize each word
178
183
 
179
184
  else:
180
185
  # Replicate DRF's built-in behavior.
181
- name = getattr(view, "name", None)
182
- if name is not None:
183
- return view.name
184
-
185
186
  name = view.__class__.__name__
186
187
  name = formatting.remove_trailing_string(name, "View")
187
188
  name = formatting.remove_trailing_string(name, "ViewSet")
188
189
  name = formatting.camelcase_to_spaces(name)
189
190
 
190
- if suffix:
191
- name += " " + suffix
191
+ # Suffix may be set by some Views, such as a ViewSet.
192
+ suffix = getattr(view, "suffix", None)
193
+ if suffix:
194
+ name += " " + suffix
192
195
 
193
196
  return name
194
197
 
@@ -918,9 +918,9 @@ class CoreConfig(NautobotConfig):
918
918
  super().ready()
919
919
 
920
920
  # Register jobs last after everything else has been done.
921
- from nautobot.core.celery import app, import_jobs_as_celery_tasks
921
+ from nautobot.core.celery import import_jobs
922
922
 
923
- import_jobs_as_celery_tasks(app, database_ready=False)
923
+ import_jobs()
924
924
 
925
925
 
926
926
  class NautobotConstanceConfig(ConstanceConfig):
@@ -1,16 +1,14 @@
1
- from importlib.util import find_spec
2
1
  import json
3
2
  import logging
4
3
  import os
5
4
  from pathlib import Path
6
- import pkgutil
7
5
  import shutil
8
- import sys
9
6
 
10
7
  from celery import Celery, shared_task, signals
11
8
  from celery.app.log import TaskFormatter
12
9
  from celery.utils.log import get_logger
13
10
  from django.conf import settings
11
+ from django.db.utils import ProgrammingError
14
12
  from django.utils.functional import SimpleLazyObject
15
13
  from django.utils.module_loading import import_string
16
14
  from kombu.serialization import register
@@ -19,6 +17,8 @@ from prometheus_client import CollectorRegistry, multiprocess, start_http_server
19
17
  from nautobot.core.celery.control import discard_git_repository, refresh_git_repository # noqa: F401 # unused-import
20
18
  from nautobot.core.celery.encoders import NautobotKombuJSONEncoder
21
19
  from nautobot.core.celery.log import NautobotDatabaseHandler
20
+ from nautobot.core.utils.module_loading import import_modules_privately
21
+ from nautobot.extras.registry import registry
22
22
 
23
23
  logger = logging.getLogger(__name__)
24
24
 
@@ -29,16 +29,6 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "nautobot_config")
29
29
  class NautobotCelery(Celery):
30
30
  task_cls = "nautobot.core.celery.task:NautobotTask"
31
31
 
32
- def register_task(self, task, **options):
33
- """Override the default task name for job classes to allow app provided jobs to use the full module path."""
34
- from nautobot.extras.jobs import Job
35
-
36
- if issubclass(task, Job):
37
- task = task()
38
- task.name = task.registered_name
39
-
40
- return super().register_task(task, **options)
41
-
42
32
 
43
33
  app = NautobotCelery("nautobot")
44
34
 
@@ -53,60 +43,77 @@ app.autodiscover_tasks()
53
43
 
54
44
 
55
45
  @signals.import_modules.connect
56
- def import_jobs_as_celery_tasks(sender, database_ready=True, **kwargs):
46
+ def import_jobs(sender=None, **kwargs):
57
47
  """
58
- Import system Jobs into Celery as well as Jobs from JOBS_ROOT and GIT_ROOT.
48
+ Import system Jobs into Nautobot as well as Jobs from JOBS_ROOT and GIT_ROOT.
49
+
50
+ Note that app-provided jobs are automatically imported at startup time via NautobotAppConfig.ready()
51
+ """
52
+ import nautobot.core.jobs # noqa: F401
53
+
54
+ _import_jobs_from_jobs_root()
59
55
 
60
- Note that app-provided Jobs are automatically imported at startup time via NautobotAppConfig.ready()
56
+ try:
57
+ _import_jobs_from_git_repositories()
58
+ except ProgrammingError: # Database not ready yet, as may be the case on initial startup and migration
59
+ pass
60
+
61
+
62
+ def _import_jobs_from_jobs_root():
63
+ """
64
+ (Re)import all modules in settings.JOBS_ROOT.
61
65
  """
62
- logger.debug("Importing system Jobs")
63
- sender.loader.import_task_module("nautobot.core.jobs")
64
-
65
- jobs_root = settings.JOBS_ROOT
66
- if jobs_root and os.path.exists(jobs_root):
67
- if jobs_root not in sys.path:
68
- sys.path.append(jobs_root)
69
- for _, module_name, _ in pkgutil.iter_modules([jobs_root]):
70
- try:
71
- logger.debug("Importing Jobs from %s in JOBS_ROOT", module_name)
72
- existing_module = find_spec(module_name)
73
- if existing_module is not None:
74
- existing_module_path = os.path.realpath(existing_module.origin)
75
- jobs_root_path = os.path.realpath(jobs_root)
76
- if not existing_module_path.startswith(jobs_root_path):
77
- raise ImportError(
78
- f"JOBS_ROOT Jobs module {module_name} conflicts with existing module {existing_module_path}"
79
- )
80
- sender.loader.import_task_module(module_name)
81
- except Exception as exc:
82
- logger.exception(exc)
83
-
84
- git_root = settings.GIT_ROOT
85
- if git_root and os.path.exists(git_root):
86
- if git_root not in sys.path:
87
- sys.path.append(git_root)
88
-
89
- # We can't detect which Git directories we're *supposed* to auto-load Jobs from if we can't read GitRepository
90
- # records from the DB, unfortunately.
91
- # We work around this in JobModel.job_task to try later loading Git jobs on-the-fly if needed.
92
- if database_ready:
66
+ if not (settings.JOBS_ROOT and os.path.isdir(settings.JOBS_ROOT)):
67
+ return
68
+
69
+ # Flush any previously loaded non-system, non-App Jobs
70
+ for job_class_path in list(registry["jobs"]):
71
+ if job_class_path.startswith("nautobot."):
72
+ # System job
73
+ continue
74
+ if any(job_class_path.startswith(f"{app_name}.") for app_name in settings.PLUGINS):
75
+ # App provided job
76
+ continue
77
+ try:
93
78
  from nautobot.extras.models import GitRepository
94
79
 
95
- # Make sure there are no git clones in GIT_ROOT that *aren't* tracked by a GitRepository;
96
- # for example, maybe a GitRepository was deleted while this worker process wasn't running?
97
- for filename in os.listdir(git_root):
98
- filepath = os.path.join(git_root, filename)
99
- if (
100
- os.path.isdir(filepath)
101
- and os.path.isdir(os.path.join(filepath, ".git"))
102
- and not GitRepository.objects.filter(slug=filename).exists()
103
- ):
104
- logger.warning("Deleting unmanaged (leftover?) Git repository clone at %s", filepath)
105
- shutil.rmtree(filepath)
80
+ if any(
81
+ job_class_path.startswith(f"{repo.slug}.")
82
+ for repo in GitRepository.objects.filter(provided_contents__contains="extras.job")
83
+ ):
84
+ # Git provided job
85
+ continue
86
+ except ProgrammingError: # Database not ready yet, as may be the case on initial startup and migration
87
+ pass
88
+ # Else, it's presumably a JOBS_ROOT job
89
+ del registry["jobs"][job_class_path]
90
+
91
+ # Load all modules in JOBS_ROOT
92
+ import_modules_privately(path=os.path.realpath(settings.JOBS_ROOT))
93
+
94
+
95
+ def _import_jobs_from_git_repositories():
96
+ git_root = os.path.realpath(settings.GIT_ROOT)
97
+ if not (git_root and os.path.exists(git_root)):
98
+ return
99
+
100
+ from nautobot.extras.models import GitRepository
101
+
102
+ # Make sure there are no git clones in GIT_ROOT that *aren't* tracked by a GitRepository;
103
+ # for example, maybe a GitRepository was deleted while this worker process wasn't running?
104
+ for filename in os.listdir(git_root):
105
+ filepath = os.path.join(git_root, filename)
106
+ if (
107
+ os.path.isdir(filepath)
108
+ and os.path.isdir(os.path.join(filepath, ".git"))
109
+ and not GitRepository.objects.filter(slug=filename).exists()
110
+ ):
111
+ logger.warning("Deleting unmanaged (leftover?) Git repository clone at %s", filepath)
112
+ shutil.rmtree(filepath)
106
113
 
107
- # Make sure all GitRepository records that include Jobs have up-to-date git clones, and load their jobs
108
- for repo in GitRepository.objects.all():
109
- refresh_git_repository(state=None, repository_pk=repo.pk, head=repo.current_head)
114
+ # Make sure all GitRepository records that include Jobs have up-to-date git clones, and load their jobs
115
+ for repo in GitRepository.objects.filter(provided_contents__contains="extras.job"):
116
+ refresh_git_repository(state=None, repository_pk=repo.pk, head=repo.current_head)
110
117
 
111
118
 
112
119
  def add_nautobot_log_handler(logger_instance, log_format=None):
@@ -151,11 +158,11 @@ def setup_prometheus(**kwargs):
151
158
  multiprocess_coordination_directory.mkdir(parents=True, exist_ok=True)
152
159
 
153
160
  # Set up the collector registry
154
- registry = CollectorRegistry()
155
- multiprocess.MultiProcessCollector(registry, path=multiprocess_coordination_directory)
161
+ collector_registry = CollectorRegistry()
162
+ multiprocess.MultiProcessCollector(collector_registry, path=multiprocess_coordination_directory)
156
163
  for port in settings.CELERY_WORKER_PROMETHEUS_PORTS:
157
164
  try:
158
- start_http_server(port, registry=registry)
165
+ start_http_server(port, registry=collector_registry)
159
166
  break
160
167
  except OSError:
161
168
  continue
@@ -206,9 +213,13 @@ register("nautobot_json", _dumps, _loads, content_type="application/x-nautobot-j
206
213
  nautobot_task = shared_task
207
214
 
208
215
 
216
+ registry["jobs"] = {}
217
+
218
+
209
219
  def register_jobs(*jobs):
210
- """Helper method to register jobs with Celery"""
220
+ """
221
+ Method to register jobs - with Celery in Nautobot 2.0 through 2.2.2, with Nautobot itself in 2.2.3 and later.
222
+ """
211
223
  for job in jobs:
212
- # TODO: should we only register a job if it corresponds to a Job database record?
213
- logger.debug("Registering job %s.%s", job.__module__, job.__name__)
214
- app.register_task(job)
224
+ if job.class_path not in registry["jobs"]:
225
+ registry["jobs"][job.class_path] = job
@@ -37,6 +37,7 @@ class NautobotDatabaseBackend(DatabaseBackend):
37
37
  "worker": None,
38
38
  }
39
39
  if request and self.app.conf.find_value_for_key("extended", "result"):
40
+ task_name = getattr(request, "task", None)
40
41
  # do not encode args/kwargs as we store these in a JSONField instead of TextField
41
42
  task_args = getattr(request, "args", None)
42
43
  task_kwargs = getattr(request, "kwargs", None)
@@ -54,6 +55,13 @@ class NautobotDatabaseBackend(DatabaseBackend):
54
55
  if traceback is not None:
55
56
  traceback = sanitize(traceback)
56
57
 
58
+ # Preserve the JobResult data behavior from Nautobot 2.0 through 2.2 (wherein the Job itself was the task)
59
+ # by manipulating `task_name` and `task_args` to hide the fact that we are now calling
60
+ # `run_job.apply(args=[JobClass.class_path, ...])` instead of `JobClass.apply(args=[...])`.
61
+ if task_name == "nautobot.extras.jobs.run_job" and task_args:
62
+ task_name = task_args[0]
63
+ task_args = task_args[1:]
64
+
57
65
  extended_props.update(
58
66
  {
59
67
  "task_args": task_args,
@@ -61,7 +69,7 @@ class NautobotDatabaseBackend(DatabaseBackend):
61
69
  "celery_kwargs": celery_kwargs,
62
70
  "job_model_id": properties.get("nautobot_job_job_model_id", None),
63
71
  "scheduled_job_id": properties.get("nautobot_job_scheduled_job_id", None),
64
- "task_name": getattr(request, "task", None),
72
+ "task_name": task_name,
65
73
  "traceback": traceback,
66
74
  "user_id": properties.get("nautobot_job_user_id", None),
67
75
  "worker": getattr(request, "hostname", None),
@@ -13,14 +13,14 @@ def refresh_git_repository(state, repository_pk, head):
13
13
  """
14
14
  Celery worker control event to ensure that all active workers have the correct head for a given Git repository.
15
15
  """
16
- from nautobot.extras.datasources.git import ensure_git_repository, refresh_code_from_repository
16
+ from nautobot.extras.datasources.git import ensure_git_repository, refresh_job_code_from_repository
17
17
  from nautobot.extras.models import GitRepository
18
18
 
19
19
  try:
20
20
  repository = GitRepository.objects.get(pk=repository_pk)
21
21
  # Refresh the repository on disk
22
22
  ensure_git_repository(repository, head=head, logger=logger)
23
- refresh_code_from_repository(repository.slug, consumer=state.consumer if state is not None else None)
23
+ refresh_job_code_from_repository(repository.slug, ignore_import_errors=False)
24
24
 
25
25
  return {"ok": {"head": repository.current_head}}
26
26
  except Exception as exc:
@@ -33,12 +33,9 @@ def discard_git_repository(state, repository_slug):
33
33
  """
34
34
  Celery worker control even to ensure that all active workers unload a given Git repository and delete it from disk.
35
35
  """
36
- from nautobot.extras.datasources.git import refresh_code_from_repository
36
+ from nautobot.extras.datasources.git import refresh_job_code_from_repository
37
37
 
38
38
  filesystem_path = os.path.join(settings.GIT_ROOT, repository_slug)
39
39
  if os.path.isdir(filesystem_path):
40
40
  shutil.rmtree(filesystem_path)
41
- # Unload any code from this repository
42
- refresh_code_from_repository(
43
- repository_slug, consumer=state.consumer if state is not None else None, skip_reimport=True
44
- )
41
+ refresh_job_code_from_repository(repository_slug, skip_reimport=True)
@@ -22,11 +22,13 @@ class NautobotScheduleEntry(ModelEntry):
22
22
  """Initialize the model entry."""
23
23
  self.app = app or current_app._get_current_object()
24
24
  self.name = f"{model.name}_{model.pk}"
25
- self.task = model.task
25
+ self.task = "nautobot.extras.jobs.run_job"
26
26
  try:
27
27
  # Nautobot scheduled jobs pass args/kwargs as constructed objects,
28
28
  # but Celery built-in jobs such as celery.backend_cleanup pass them as JSON to be parsed
29
- self.args = model.args if isinstance(model.args, (tuple, list)) else loads(model.args or "[]")
29
+ self.args = [model.task] + (
30
+ model.args if isinstance(model.args, (tuple, list)) else loads(model.args or "[]")
31
+ )
30
32
  self.kwargs = model.kwargs if isinstance(model.kwargs, dict) else loads(model.kwargs or "{}")
31
33
  except (TypeError, ValueError) as exc:
32
34
  logger.exception("Removing schedule %s for argument deserialization error: %s", self.name, exc)
@@ -1,12 +1,85 @@
1
- from celery import Task
2
-
3
- from nautobot.extras.jobs import get_task_logger
4
-
5
- logger = get_task_logger(__name__)
1
+ from billiard.einfo import ExceptionInfo, ExceptionWithTraceback
2
+ from celery import states, Task
3
+ from celery.exceptions import Retry
4
+ from celery.result import EagerResult
5
+ from celery.utils.functional import maybe_list
6
+ from celery.utils.nodenames import gethostname
7
+ from kombu.utils.uuid import uuid
6
8
 
7
9
 
8
10
  class NautobotTask(Task):
9
11
  """Nautobot extensions to tasks for integrating with Job machinery."""
10
12
 
13
+ def apply(
14
+ self,
15
+ args=None,
16
+ kwargs=None,
17
+ link=None,
18
+ link_error=None,
19
+ task_id=None,
20
+ retries=None,
21
+ throw=None,
22
+ logfile=None,
23
+ loglevel=None,
24
+ headers=None,
25
+ **options,
26
+ ):
27
+ """Fix celery's Task.apply() method to propagate options to the task result just like apply_async does."""
28
+ # trace imports Task, so need to import inline.
29
+ from celery.app.trace import build_tracer
30
+
31
+ app = self._get_app()
32
+ args = args or ()
33
+ kwargs = kwargs or {}
34
+ task_id = task_id or uuid()
35
+ retries = retries or 0
36
+ if throw is None:
37
+ throw = app.conf.task_eager_propagates
38
+
39
+ # Make sure we get the task instance, not class.
40
+ task = app._tasks[self.name]
41
+
42
+ request = {
43
+ "id": task_id,
44
+ "retries": retries,
45
+ "is_eager": True,
46
+ "logfile": logfile,
47
+ "loglevel": loglevel or 0,
48
+ "hostname": gethostname(),
49
+ "callbacks": maybe_list(link),
50
+ "errbacks": maybe_list(link_error),
51
+ "headers": headers,
52
+ "ignore_result": options.get("ignore_result", False),
53
+ "delivery_info": {
54
+ "is_eager": True,
55
+ "exchange": options.get("exchange"),
56
+ "routing_key": options.get("routing_key"),
57
+ "priority": options.get("priority"),
58
+ },
59
+ "properties": options, # <------- this is the one line fix to the overloaded method
60
+ }
61
+ if "stamped_headers" in options:
62
+ request["stamped_headers"] = maybe_list(options["stamped_headers"])
63
+ request["stamps"] = {header: maybe_list(options.get(header, [])) for header in request["stamped_headers"]}
64
+
65
+ tb = None
66
+ tracer = build_tracer(
67
+ task.name,
68
+ task,
69
+ eager=True,
70
+ propagate=throw,
71
+ app=self._get_app(),
72
+ )
73
+ ret = tracer(task_id, args, kwargs, request)
74
+ retval = ret.retval
75
+ if isinstance(retval, ExceptionInfo):
76
+ retval, tb = retval.exception, retval.traceback
77
+ if isinstance(retval, ExceptionWithTraceback):
78
+ retval = retval.exc
79
+ if isinstance(retval, Retry) and retval.sig is not None:
80
+ return retval.sig.apply(retries=retries + 1)
81
+ state = states.SUCCESS if ret.info is None else ret.info.state
82
+ return EagerResult(task_id, retval, state, traceback=tb)
83
+
11
84
 
12
85
  Task = NautobotTask # So that the class path resolves.
@@ -45,7 +45,7 @@ from nautobot.extras.graphql.types import DynamicGroupType, TagType
45
45
  from nautobot.extras.models import ComputedField, CustomField, Relationship
46
46
  from nautobot.extras.registry import registry
47
47
  from nautobot.extras.utils import check_if_key_is_graphql_safe
48
- from nautobot.ipam.graphql.types import IPAddressType, PrefixType
48
+ from nautobot.ipam.graphql.types import IPAddressType, PrefixType, VLANType
49
49
  from nautobot.virtualization.graphql.types import VirtualMachineType, VMInterfaceType
50
50
 
51
51
  logger = logging.getLogger(__name__)
@@ -71,6 +71,7 @@ registry["graphql_types"]["extras.tag"] = TagType
71
71
  registry["graphql_types"]["extras.dynamicgroup"] = DynamicGroupType
72
72
  registry["graphql_types"]["ipam.ipaddress"] = IPAddressType
73
73
  registry["graphql_types"]["ipam.prefix"] = PrefixType
74
+ registry["graphql_types"]["ipam.vlan"] = VLANType
74
75
  registry["graphql_types"]["virtualization.virtualmachine"] = VirtualMachineType
75
76
  registry["graphql_types"]["virtualization.vminterface"] = VMInterfaceType
76
77
 
@@ -50,7 +50,8 @@ class GitRepositorySync(Job):
50
50
  # Given that the above succeeded, tell all workers (including ourself) to call ensure_git_repository()
51
51
  app.control.broadcast("refresh_git_repository", repository_pk=repository.pk, head=repository.current_head)
52
52
  finally:
53
- self.logger.info(f"Repository synchronization completed in {job_result.duration}")
53
+ if job_result.duration:
54
+ self.logger.info("Repository synchronization completed in %s", job_result.duration)
54
55
 
55
56
 
56
57
  class GitRepositoryDryRun(Job):
nautobot/core/settings.py CHANGED
@@ -69,7 +69,7 @@ ALLOWED_URL_SCHEMES = [
69
69
  "xmpp",
70
70
  ]
71
71
 
72
- # Banners to display to users. HTML is allowed.
72
+ # Banners to display to users. Markdown and limited HTML are allowed.
73
73
  if "NAUTOBOT_BANNER_BOTTOM" in os.environ and os.environ["NAUTOBOT_BANNER_BOTTOM"] != "":
74
74
  BANNER_BOTTOM = os.environ["NAUTOBOT_BANNER_BOTTOM"]
75
75
  if "NAUTOBOT_BANNER_LOGIN" in os.environ and os.environ["NAUTOBOT_BANNER_LOGIN"] != "":
@@ -686,15 +686,15 @@ CONSTANCE_CONFIG = {
686
686
  ),
687
687
  "BANNER_BOTTOM": ConstanceConfigItem(
688
688
  default="",
689
- help_text="Custom HTML to display in a banner at the bottom of all pages.",
689
+ help_text="Custom Markdown or limited HTML to display in a banner at the bottom of all pages.",
690
690
  ),
691
691
  "BANNER_LOGIN": ConstanceConfigItem(
692
692
  default="",
693
- help_text="Custom HTML to display in a banner at the top of the login page.",
693
+ help_text="Custom Markdown or limited HTML to display in a banner at the top of the login page.",
694
694
  ),
695
695
  "BANNER_TOP": ConstanceConfigItem(
696
696
  default="",
697
- help_text="Custom HTML to display in a banner at the top of all pages.",
697
+ help_text="Custom Markdown or limited HTML to display in a banner at the top of all pages.",
698
698
  ),
699
699
  "CHANGELOG_RETENTION": ConstanceConfigItem(
700
700
  default=90,
@@ -972,6 +972,8 @@ BRANDING_FILEPATHS = {
972
972
  "NAUTOBOT_BRANDING_FILEPATHS_HEADER_BULLET", None
973
973
  ), # bullet image used for various view headers
974
974
  "nav_bullet": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_NAV_BULLET", None), # bullet image used for nav menu headers
975
+ "css": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_CSS", None), # Custom global CSS
976
+ "javascript": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_JAVASCRIPT", None), # Custom global JavaScript
975
977
  }
976
978
 
977
979
  # Title to use in place of "Nautobot"
@@ -128,24 +128,40 @@ properties:
128
128
  type: "array"
129
129
  BANNER_BOTTOM:
130
130
  default: ""
131
- description: "Custom content to be displayed in a banner at the bottom of the page. HTML is allowed."
131
+ description: >-
132
+ Custom content to be displayed in a banner at the bottom of all Nautobot pages.
133
+ details: |-
134
+ +/- 2.2.4
135
+ Markdown formatting is supported within this message, as well as
136
+ [a limited subset of HTML](../../platform-functionality/template-filters.md#render_markdown).
132
137
  environment_variable: "NAUTOBOT_BANNER_BOTTOM"
133
138
  is_constance_config: true
134
139
  type: "string"
135
140
  BANNER_LOGIN:
136
141
  default: ""
137
- description: "Custom content to be displayed on the login page above the login form. HTML is allowed."
142
+ description: >-
143
+ Custom content to be displayed in a banner on the login page above the login form.
144
+ details: |-
145
+ +/- 2.2.4
146
+ Markdown formatting is supported within this message, as well as
147
+ [a limited subset of HTML](../../platform-functionality/template-filters.md#render_markdown).
138
148
  environment_variable: "NAUTOBOT_BANNER_LOGIN"
139
149
  is_constance_config: true
140
150
  type: "string"
141
151
  BANNER_TOP:
142
152
  default: ""
143
- description: "Custom content to be displayed in a banner at the top of the page. HTML is allowed."
153
+ description: >-
154
+ Custom content to be displayed in a banner at the top of all Nautobot pages.
155
+ details: |-
156
+ +/- 2.2.4
157
+ Markdown formatting is supported within this message, as well as
158
+ [a limited subset of HTML](../../platform-functionality/template-filters.md#render_markdown).
144
159
  environment_variable: "NAUTOBOT_BANNER_TOP"
145
160
  is_constance_config: true
146
161
  type: "string"
147
162
  BRANDING_FILEPATHS:
148
163
  default:
164
+ css: null
149
165
  favicon: null
150
166
  header_bullet: null
151
167
  icon_16: null
@@ -153,57 +169,76 @@ properties:
153
169
  icon_180: null
154
170
  icon_192: null
155
171
  icon_mask: null
172
+ javascript: null
156
173
  logo: null
157
174
  nav_bullet: null
158
175
  description: >-
159
- A set of filepaths relative to the [`MEDIA_ROOT`](#media_root) which locate image assets used for
160
- custom branding. Each of these assets takes the place of the corresponding stock Nautobot asset.
176
+ A set of filepaths relative to the [`MEDIA_ROOT`](#media_root) which locate assets used for
177
+ custom branding of your Nautobot instance.
178
+ With the exception of `css` and `javascript`, which provide the option to add an _additional_ file to Nautobot
179
+ page content, each of the other assets takes the place of the corresponding stock Nautobot asset.
161
180
  This allows for, for instance, providing your own navbar logo and favicon.
162
- If a custom image asset is not provided for any of the above options, the stock Nautobot asset is used.
181
+ If a custom asset is not provided for any of the above options, the stock Nautobot asset is used.
182
+ details: |-
183
+ +++ 2.1.0
184
+ The `header_bullet` and `nav_bullet` assets were added as options.
185
+
186
+ +++ 2.2.4
187
+ The `css` and `javascript` assets were added as options.
163
188
  properties:
189
+ css:
190
+ "$ref": "#/definitions/relative_path"
191
+ default: null
192
+ description: "Custom global CSS file"
193
+ environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_CSS"
164
194
  favicon:
165
195
  "$ref": "#/definitions/relative_path"
166
- default: ""
196
+ default: null
167
197
  description: "Browser favicon"
168
198
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_FAVICON"
169
199
  header_bullet:
170
200
  "$ref": "#/definitions/relative_path"
171
- default: ""
201
+ default: null
172
202
  description: "Bullet image used for various view headers"
173
203
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_HEADER_BULLET"
174
204
  icon_16:
175
205
  "$ref": "#/definitions/relative_path"
176
- default: ""
206
+ default: null
177
207
  description: "16x16px icon"
178
208
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_ICON_16"
179
209
  icon_180:
180
210
  "$ref": "#/definitions/relative_path"
181
- default: ""
211
+ default: null
182
212
  description: "180x180px icon - used for the apple-touch-icon header"
183
213
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_ICON_180"
184
214
  icon_192:
185
215
  "$ref": "#/definitions/relative_path"
186
- default: ""
216
+ default: null
187
217
  description: "192x192px icon"
188
218
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_ICON_192"
189
219
  icon_32:
190
220
  "$ref": "#/definitions/relative_path"
191
- default: ""
221
+ default: null
192
222
  description: "32x32px icon"
193
223
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_ICON_32"
194
224
  icon_mask:
195
225
  "$ref": "#/definitions/relative_path"
196
- default: ""
226
+ default: null
197
227
  description: "Mono-chrome icon used for the mask-icon header"
198
228
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_ICON_MASK"
229
+ javascript:
230
+ "$ref": "#/definitions/relative_path"
231
+ default: null
232
+ description: "Custom global JavaScript file"
233
+ environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_JAVASCRIPT"
199
234
  logo:
200
235
  "$ref": "#/definitions/relative_path"
201
- default: ""
236
+ default: null
202
237
  description: "Navbar logo"
203
238
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_LOGO"
204
239
  nav_bullet:
205
240
  "$ref": "#/definitions/relative_path"
206
- default: ""
241
+ default: null
207
242
  description: "Bullet image used for nav menu headers"
208
243
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_NAV_BULLET"
209
244
  type: "object"
@@ -1135,7 +1170,7 @@ properties:
1135
1170
  !!! note
1136
1171
  The Docker container normally attempts to run migrations on startup; however, if the database is
1137
1172
  in a read-only state the Docker container will fail to start. Setting the environment variable
1138
- [`NAUTOBOT_DOCKER_SKIP_INIT`](../installation/docker.md#nautobot_docker_skip_init) to `true`
1173
+ [`NAUTOBOT_DOCKER_SKIP_INIT`](../installation-extras/docker.md#nautobot_docker_skip_init) to `true`
1139
1174
  will prevent the migrations from occurring.
1140
1175
 
1141
1176
  !!! note