nautobot 2.2.0__py3-none-any.whl → 2.2.1__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (345) hide show
  1. nautobot/__init__.py +31 -0
  2. nautobot/circuits/apps.py +1 -1
  3. nautobot/core/api/routers.py +25 -0
  4. nautobot/core/cli/__init__.py +18 -11
  5. nautobot/core/constants.py +85 -0
  6. nautobot/core/forms/widgets.py +1 -2
  7. nautobot/core/graphql/schema.py +1 -0
  8. nautobot/core/models/__init__.py +1 -0
  9. nautobot/core/settings.py +23 -3
  10. nautobot/core/settings.yaml +20 -0
  11. nautobot/core/signals.py +1 -0
  12. nautobot/core/templates/generic/object_retrieve.html +2 -2
  13. nautobot/core/templates/inc/javascript.html +4 -4
  14. nautobot/core/templates/inc/media.html +2 -2
  15. nautobot/core/templates/nautobot_config.py.j2 +14 -1
  16. nautobot/core/testing/__init__.py +1 -1
  17. nautobot/core/testing/filters.py +1 -1
  18. nautobot/core/tests/integration/test_view_authentication.py +1 -0
  19. nautobot/core/tests/test_views.py +22 -0
  20. nautobot/core/utils/data.py +1 -2
  21. nautobot/core/utils/lookup.py +2 -0
  22. nautobot/core/views/generic.py +1 -3
  23. nautobot/core/views/mixins.py +0 -1
  24. nautobot/core/views/renderers.py +7 -5
  25. nautobot/dcim/apps.py +8 -4
  26. nautobot/dcim/elevations.py +5 -1
  27. nautobot/dcim/tables/devices.py +1 -1
  28. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +12 -4
  29. nautobot/dcim/templates/dcim/device.html +1 -1
  30. nautobot/dcim/templates/dcim/devicefamily_retrieve.html +4 -0
  31. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +1 -1
  32. nautobot/dcim/tests/test_api.py +36 -0
  33. nautobot/dcim/tests/test_signals.py +1 -1
  34. nautobot/dcim/views.py +6 -0
  35. nautobot/extras/api/serializers.py +20 -1
  36. nautobot/extras/apps.py +7 -0
  37. nautobot/extras/context_managers.py +15 -4
  38. nautobot/extras/filters/customfields.py +14 -9
  39. nautobot/extras/filters/mixins.py +6 -1
  40. nautobot/extras/health_checks.py +1 -0
  41. nautobot/extras/jobs.py +1 -0
  42. nautobot/extras/managers.py +1 -2
  43. nautobot/extras/models/contacts.py +1 -0
  44. nautobot/extras/models/customfields.py +25 -2
  45. nautobot/extras/models/datasources.py +1 -0
  46. nautobot/extras/models/mixins.py +1 -0
  47. nautobot/extras/plugins/__init__.py +2 -1
  48. nautobot/extras/querysets.py +1 -2
  49. nautobot/extras/secrets/providers.py +1 -0
  50. nautobot/extras/signals.py +15 -5
  51. nautobot/extras/tasks.py +70 -17
  52. nautobot/extras/tests/test_api.py +0 -4
  53. nautobot/extras/tests/test_customfields.py +72 -9
  54. nautobot/extras/views.py +8 -7
  55. nautobot/ipam/api/serializers.py +10 -0
  56. nautobot/ipam/apps.py +3 -2
  57. nautobot/project-static/docs/404.html +102 -70
  58. nautobot/project-static/docs/apps/index.html +103 -68
  59. nautobot/project-static/docs/apps/nautobot-apps.html +103 -68
  60. nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js → bundle.bd41221c.min.js} +2 -2
  61. nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js.map → bundle.bd41221c.min.js.map} +3 -3
  62. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +1 -0
  63. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +1 -0
  64. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +103 -68
  65. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +103 -68
  66. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +141 -68
  67. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +141 -69
  68. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +103 -68
  69. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +103 -68
  70. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +103 -68
  71. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +103 -68
  72. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +103 -68
  73. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +103 -68
  74. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +103 -68
  75. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +103 -68
  76. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +103 -68
  77. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +103 -68
  78. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +103 -68
  79. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +103 -68
  80. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +103 -68
  81. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +103 -68
  82. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +104 -69
  83. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +103 -68
  84. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +103 -68
  85. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +103 -68
  86. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +103 -68
  87. nautobot/project-static/docs/development/apps/api/configuration-view.html +103 -68
  88. nautobot/project-static/docs/development/apps/api/database-backend-config.html +103 -68
  89. nautobot/project-static/docs/development/apps/api/models/django-admin.html +103 -68
  90. nautobot/project-static/docs/development/apps/api/models/global-search.html +103 -68
  91. nautobot/project-static/docs/development/apps/api/models/graphql.html +103 -68
  92. nautobot/project-static/docs/development/apps/api/models/index.html +103 -68
  93. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +103 -68
  94. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +103 -68
  95. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +103 -68
  96. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +103 -68
  97. nautobot/project-static/docs/development/apps/api/platform-features/index.html +103 -68
  98. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +103 -68
  99. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +103 -68
  100. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +103 -68
  101. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +103 -68
  102. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +103 -68
  103. nautobot/project-static/docs/development/apps/api/prometheus.html +103 -68
  104. nautobot/project-static/docs/development/apps/api/setup.html +103 -68
  105. nautobot/project-static/docs/development/apps/api/testing.html +103 -68
  106. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +103 -68
  107. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +103 -68
  108. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +103 -68
  109. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +103 -68
  110. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +103 -68
  111. nautobot/project-static/docs/development/apps/api/views/base-template.html +103 -68
  112. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +103 -68
  113. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +103 -68
  114. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +103 -68
  115. nautobot/project-static/docs/development/apps/api/views/index.html +103 -68
  116. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +103 -68
  117. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +103 -68
  118. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +103 -68
  119. nautobot/project-static/docs/development/apps/api/views/notes.html +103 -68
  120. nautobot/project-static/docs/development/apps/api/views/rest-api.html +103 -68
  121. nautobot/project-static/docs/development/apps/api/views/urls.html +103 -68
  122. nautobot/project-static/docs/development/apps/index.html +103 -68
  123. nautobot/project-static/docs/development/apps/migration/code-updates.html +103 -68
  124. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +103 -68
  125. nautobot/project-static/docs/development/apps/migration/from-v1.html +103 -68
  126. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +103 -68
  127. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +103 -68
  128. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +103 -68
  129. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +103 -68
  130. nautobot/project-static/docs/development/apps/porting-from-netbox.html +103 -68
  131. nautobot/project-static/docs/development/core/application-registry.html +103 -68
  132. nautobot/project-static/docs/development/core/best-practices.html +121 -76
  133. nautobot/project-static/docs/development/core/bootstrap-ui.html +103 -68
  134. nautobot/project-static/docs/development/core/caching.html +103 -68
  135. nautobot/project-static/docs/development/core/controllers.html +106 -71
  136. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +103 -68
  137. nautobot/project-static/docs/development/core/extending-models.html +13 -8187
  138. nautobot/project-static/docs/development/core/generic-views.html +118 -83
  139. nautobot/project-static/docs/development/core/getting-started.html +103 -68
  140. nautobot/project-static/docs/development/core/homepage.html +121 -86
  141. nautobot/project-static/docs/development/core/index.html +103 -68
  142. nautobot/project-static/docs/development/core/model-checklist.html +8354 -0
  143. nautobot/project-static/docs/development/core/model-features.html +106 -71
  144. nautobot/project-static/docs/development/core/natural-keys.html +103 -68
  145. nautobot/project-static/docs/development/core/navigation-menu.html +103 -68
  146. nautobot/project-static/docs/development/core/release-checklist.html +103 -68
  147. nautobot/project-static/docs/development/core/role-internals.html +103 -68
  148. nautobot/project-static/docs/development/core/settings.html +103 -68
  149. nautobot/project-static/docs/development/core/style-guide.html +103 -68
  150. nautobot/project-static/docs/development/core/templates.html +103 -68
  151. nautobot/project-static/docs/development/core/testing.html +103 -68
  152. nautobot/project-static/docs/development/core/user-preferences.html +103 -68
  153. nautobot/project-static/docs/development/extending-models.html +3 -3
  154. nautobot/project-static/docs/development/index.html +103 -68
  155. nautobot/project-static/docs/development/jobs/index.html +104 -69
  156. nautobot/project-static/docs/development/jobs/migration/from-v1.html +103 -68
  157. nautobot/project-static/docs/index.html +102 -70
  158. nautobot/project-static/docs/objects.inv +0 -0
  159. nautobot/project-static/docs/release-notes/index.html +103 -68
  160. nautobot/project-static/docs/release-notes/version-1.0.html +103 -68
  161. nautobot/project-static/docs/release-notes/version-1.1.html +103 -68
  162. nautobot/project-static/docs/release-notes/version-1.2.html +103 -68
  163. nautobot/project-static/docs/release-notes/version-1.3.html +103 -68
  164. nautobot/project-static/docs/release-notes/version-1.4.html +103 -68
  165. nautobot/project-static/docs/release-notes/version-1.5.html +103 -68
  166. nautobot/project-static/docs/release-notes/version-1.6.html +103 -68
  167. nautobot/project-static/docs/release-notes/version-2.0.html +103 -68
  168. nautobot/project-static/docs/release-notes/version-2.1.html +103 -68
  169. nautobot/project-static/docs/release-notes/version-2.2.html +334 -97
  170. nautobot/project-static/docs/requirements.txt +3 -3
  171. nautobot/project-static/docs/search/search_index.json +1 -1
  172. nautobot/project-static/docs/sitemap.xml +258 -258
  173. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  174. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +103 -68
  175. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +103 -68
  176. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +103 -68
  177. nautobot/project-static/docs/user-guide/administration/configuration/index.html +103 -68
  178. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +168 -68
  179. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +103 -68
  180. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +103 -68
  181. nautobot/project-static/docs/user-guide/administration/guides/caching.html +103 -68
  182. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +103 -68
  183. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +103 -68
  184. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +103 -68
  185. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +107 -68
  186. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +103 -68
  187. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +103 -68
  188. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +106 -71
  189. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +103 -68
  190. nautobot/project-static/docs/user-guide/administration/installation/docker.html +103 -68
  191. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +103 -68
  192. nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +103 -68
  193. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +103 -68
  194. nautobot/project-static/docs/user-guide/administration/installation/index.html +103 -68
  195. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +103 -68
  196. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +103 -68
  197. nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +103 -68
  198. nautobot/project-static/docs/user-guide/administration/installation/services.html +103 -68
  199. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +103 -68
  200. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +103 -68
  201. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +103 -68
  202. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +103 -68
  203. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +103 -68
  204. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +103 -68
  205. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +103 -68
  206. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +103 -68
  207. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +103 -68
  208. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +103 -68
  209. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +103 -68
  210. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +103 -68
  211. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +103 -68
  212. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +103 -68
  213. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +103 -68
  214. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +103 -68
  215. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +103 -68
  216. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +103 -68
  217. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +103 -68
  218. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +103 -68
  219. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +103 -68
  220. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +103 -68
  221. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +103 -68
  222. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +103 -68
  223. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +103 -68
  224. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +103 -68
  225. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +103 -68
  226. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +103 -68
  227. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +103 -68
  228. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +103 -68
  229. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +103 -68
  230. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +103 -68
  231. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +103 -68
  232. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +103 -68
  233. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +103 -68
  234. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +103 -68
  235. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +103 -68
  236. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +103 -68
  237. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +103 -68
  238. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +103 -68
  239. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +103 -68
  240. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +103 -68
  241. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +103 -68
  242. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +103 -68
  243. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +103 -68
  244. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +103 -68
  245. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +103 -68
  246. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +103 -68
  247. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +103 -68
  248. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +103 -68
  249. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +103 -68
  250. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +103 -68
  251. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +103 -68
  252. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +103 -68
  253. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +103 -68
  254. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +103 -68
  255. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +103 -68
  256. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +114 -68
  257. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +114 -68
  258. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +103 -68
  259. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +103 -68
  260. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +103 -68
  261. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +103 -68
  262. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +103 -68
  263. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +103 -68
  264. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +103 -68
  265. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +103 -68
  266. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +103 -68
  267. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +103 -68
  268. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +103 -68
  269. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +103 -68
  270. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +103 -68
  271. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +103 -68
  272. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +103 -68
  273. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +103 -68
  274. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +103 -68
  275. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +103 -68
  276. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +103 -68
  277. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +103 -68
  278. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +103 -68
  279. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +103 -68
  280. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +103 -68
  281. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +103 -68
  282. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +103 -68
  283. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +103 -68
  284. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +103 -68
  285. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +103 -68
  286. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +103 -68
  287. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +103 -68
  288. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +103 -68
  289. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +103 -68
  290. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +103 -68
  291. nautobot/project-static/docs/user-guide/index.html +103 -68
  292. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +103 -68
  293. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +103 -68
  294. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +103 -68
  295. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +103 -68
  296. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +103 -68
  297. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +103 -68
  298. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +103 -68
  299. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +103 -68
  300. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +103 -68
  301. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +103 -68
  302. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +103 -68
  303. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +103 -68
  304. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +103 -68
  305. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +103 -68
  306. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +103 -68
  307. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +103 -68
  308. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +103 -68
  309. nautobot/project-static/docs/user-guide/platform-functionality/note.html +103 -68
  310. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +103 -68
  311. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +103 -68
  312. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +103 -68
  313. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +103 -68
  314. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +103 -68
  315. nautobot/project-static/docs/user-guide/platform-functionality/role.html +103 -68
  316. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +103 -68
  317. nautobot/project-static/docs/user-guide/platform-functionality/status.html +103 -68
  318. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +103 -68
  319. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +103 -68
  320. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +103 -68
  321. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +103 -68
  322. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +103 -68
  323. nautobot/project-static/jquery/jquery-3.7.1.min.js +2 -0
  324. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_444444_256x240.png +0 -0
  325. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_555555_256x240.png +0 -0
  326. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777620_256x240.png +0 -0
  327. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777777_256x240.png +0 -0
  328. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_cc0000_256x240.png +0 -0
  329. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_ffffff_256x240.png +0 -0
  330. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.css +7 -0
  331. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.js +6 -0
  332. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.structure.min.css +5 -0
  333. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/jquery-ui.theme.min.css +1 -1
  334. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/METADATA +22 -22
  335. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/RECORD +339 -338
  336. nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css +0 -1
  337. nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css.map +0 -1
  338. nautobot/project-static/jquery/jquery-3.6.0.min.js +0 -2
  339. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.css +0 -7
  340. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.js +0 -6
  341. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.structure.min.css +0 -5
  342. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/LICENSE.txt +0 -0
  343. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/NOTICE +0 -0
  344. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/WHEEL +0 -0
  345. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/entry_points.txt +0 -0
nautobot/__init__.py CHANGED
@@ -1,4 +1,35 @@
1
1
  from importlib import metadata
2
+ import logging
3
+ import os
4
+
5
+ import django
2
6
 
3
7
  # Primary package version
4
8
  __version__ = metadata.version(__name__)
9
+
10
+ # Sentinel to make sure we only initialize once.
11
+ __initialized = False
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ def setup(config_path=None):
17
+ """Similar to `django.setup()`, this configures Django with the appropriate Nautobot settings data."""
18
+ from nautobot.core.cli import get_config_path, load_settings
19
+
20
+ global __initialized
21
+
22
+ if __initialized:
23
+ return
24
+
25
+ if config_path is None:
26
+ config_path = get_config_path()
27
+
28
+ # Point Django to our 'nautobot_config' pseudo-module that we'll load from the provided config path
29
+ os.environ["DJANGO_SETTINGS_MODULE"] = "nautobot_config"
30
+
31
+ load_settings(config_path)
32
+ django.setup()
33
+
34
+ logger.info("Nautobot initialized!")
35
+ __initialized = True
nautobot/circuits/apps.py CHANGED
@@ -5,8 +5,8 @@ class CircuitsConfig(NautobotConfig):
5
5
  name = "nautobot.circuits"
6
6
  verbose_name = "Circuits"
7
7
  searchable_models = [
8
- "provider",
9
8
  "circuit",
9
+ "provider",
10
10
  "providernetwork",
11
11
  ]
12
12
 
@@ -27,6 +27,31 @@ class OrderedDefaultRouter(DefaultRouter):
27
27
  }
28
28
  )
29
29
 
30
+ def register(self, prefix, viewset, basename=None):
31
+ """
32
+ Override DRF's BaseRouter.register() to bypass an unnecessary restriction added in version 3.15.0.
33
+
34
+ (Reference: https://github.com/encode/django-rest-framework/pull/8438)
35
+ """
36
+ if basename is None:
37
+ basename = self.get_default_basename(viewset)
38
+
39
+ # DRF:
40
+ # if self.is_already_registered(basename):
41
+ # msg = (f'Router with basename "{basename}" is already registered. '
42
+ # f'Please provide a unique basename for viewset "{viewset}"')
43
+ # raise ImproperlyConfigured(msg)
44
+ #
45
+ # We bypass this because we have at least one use case (/api/extras/jobs/) where we are *intentionally*
46
+ # registering two viewsets with the same basename, but have carefully defined them so as not to conflict.
47
+
48
+ # resuming standard DRF code...
49
+ self.registry.append((prefix, viewset, basename))
50
+
51
+ # invalidate the urls cache
52
+ if hasattr(self, "_urls"):
53
+ del self._urls
54
+
30
55
  def get_api_root_view(self, api_urls=None):
31
56
  """
32
57
  Wrap DRF's DefaultRouter to return an alphabetized list of endpoints.
@@ -13,7 +13,6 @@ from django.core.management import CommandError, CommandParser, execute_from_com
13
13
  from django.core.management.utils import get_random_secret_key
14
14
  from jinja2 import BaseLoader, Environment
15
15
 
16
- from nautobot import __version__
17
16
  from nautobot.core.settings_funcs import is_truthy
18
17
  from nautobot.extras.plugins.utils import load_plugins
19
18
 
@@ -126,7 +125,7 @@ def _preprocess_settings(settings, config_path):
126
125
  load_plugins(settings)
127
126
 
128
127
 
129
- def _load_settings(config_path):
128
+ def load_settings(config_path):
130
129
  """Load nautobot_config.py or its equivalent into memory as a `nautobot_config` pseudo-module."""
131
130
  if not os.path.exists(config_path):
132
131
  raise FileNotFoundError(
@@ -154,6 +153,8 @@ class _VersionAction(argparse.Action):
154
153
  super().__init__(*args, **kwargs)
155
154
 
156
155
  def __call__(self, parser, namespace, values, option_string):
156
+ from nautobot import __version__
157
+
157
158
  print(f"Nautobot version: {__version__}")
158
159
  print(f"Django version: {django.__version__}")
159
160
  print(f"Configuration file: {namespace.config_path}")
@@ -215,13 +216,9 @@ def _init_settings(args):
215
216
  print(f"Configuration file created at {config_path}")
216
217
 
217
218
 
218
- def main():
219
- """Run administrative tasks."""
220
- # Point Django to our 'nautobot_config' pseudo-module that we'll load from the provided config path
221
- os.environ["DJANGO_SETTINGS_MODULE"] = "nautobot_config"
222
-
223
- # Default config path based on NAUTOBOT_CONFIG or NAUTOBOT_ROOT environment variables
224
- config_path = os.getenv(
219
+ def get_config_path():
220
+ """Get the default Nautobot config file path based on the NAUTOBOT_CONFIG or NAUTOBOT_ROOT environment variables."""
221
+ return os.getenv(
225
222
  "NAUTOBOT_CONFIG",
226
223
  os.path.join(
227
224
  os.getenv("NAUTOBOT_ROOT", os.path.expanduser("~/.nautobot")),
@@ -229,13 +226,23 @@ def main():
229
226
  ),
230
227
  )
231
228
 
229
+
230
+ def main():
231
+ """Run administrative tasks."""
232
+ # Point Django to our 'nautobot_config' pseudo-module that we'll load from the provided config path
233
+ os.environ["DJANGO_SETTINGS_MODULE"] = "nautobot_config"
234
+
235
+ default_config_path = get_config_path()
236
+
232
237
  # Intercept certain CLI parameters and arguments before they reach Django
233
238
  parser = CommandParser(
234
239
  description=DESCRIPTION,
235
240
  usage=USAGE,
236
241
  formatter_class=_VerboseHelpFormatter,
237
242
  )
238
- parser.add_argument("-c", "--config-path", default=config_path, help="Path to the Nautobot configuration file")
243
+ parser.add_argument(
244
+ "-c", "--config-path", default=default_config_path, help="Path to the Nautobot configuration file"
245
+ )
239
246
  parser.add_argument("--version", action=_VersionAction, help="Show version numbers and exit")
240
247
 
241
248
  # Parse out the `--config` argument here and capture the rest of the CLI args
@@ -282,7 +289,7 @@ def main():
282
289
  raise
283
290
 
284
291
  # If we get here, it's a regular Django management command - so load in the nautobot_config.py then hand off
285
- _load_settings(args.config_path)
292
+ load_settings(args.config_path)
286
293
  execute_from_command_line([sys.argv[0], *unparsed_args])
287
294
 
288
295
 
@@ -104,4 +104,89 @@ COMPOSITE_KEY_SEPARATOR = ";"
104
104
  # For the natural slug separator, it's much simpler and we can just go with "_".
105
105
  NATURAL_SLUG_SEPARATOR = "_"
106
106
 
107
+ # For config settings that contain a list of things.
108
+ # As environment variables only allow string types, these need to be split into the final list.
109
+ CONFIG_SETTING_SEPARATOR = ","
110
+
107
111
  CHARFIELD_MAX_LENGTH = 255
112
+
113
+ # Models excluded from the global search list
114
+ GLOBAL_SEARCH_EXCLUDE_LIST = [
115
+ "anotherexamplemodel",
116
+ "cablepath",
117
+ "circuittermination",
118
+ "circuittype",
119
+ "clustergroup",
120
+ "clustertype",
121
+ "computedfield",
122
+ "configcontext",
123
+ "configcontextschema",
124
+ "consoleport",
125
+ "consoleporttemplate",
126
+ "consoleserverport",
127
+ "consoleserverporttemplate",
128
+ "contactassociation",
129
+ "controllermanageddevicegroup",
130
+ "customfield",
131
+ "customfieldchoice",
132
+ "customlink",
133
+ "devicebay",
134
+ "devicebaytemplate",
135
+ "devicetypetosoftwareimagefile",
136
+ "dynamicgroupmembership",
137
+ "exporttemplate",
138
+ "fileattachment",
139
+ "fileproxy",
140
+ "frontport",
141
+ "frontporttemplate",
142
+ "graphqlquery",
143
+ "healthchecktestmodel",
144
+ "imageattachment",
145
+ "interface",
146
+ "interfaceredundancygroup",
147
+ "interfaceredundancygroupassociation",
148
+ "interfacetemplate",
149
+ "inventoryitem",
150
+ "ipaddresstointerface",
151
+ "job",
152
+ "jobbutton",
153
+ "jobhook",
154
+ "joblogentry",
155
+ "jobresult",
156
+ "locationtype",
157
+ "manufacturer",
158
+ "note",
159
+ "objectchange",
160
+ "platform",
161
+ "poweroutlet",
162
+ "poweroutlettemplate",
163
+ "powerpanel",
164
+ "powerport",
165
+ "powerporttemplate",
166
+ "prefixlocationassignment",
167
+ "rackreservation",
168
+ "rearport",
169
+ "rearporttemplate",
170
+ "relationship",
171
+ "relationshipassociation",
172
+ "rir",
173
+ "role",
174
+ "routetarget",
175
+ "scheduledjob",
176
+ "scheduledjobs",
177
+ "secret",
178
+ "secretsgroup",
179
+ "secretsgroupassociation",
180
+ "service",
181
+ "softwareimagefile",
182
+ "status",
183
+ "tag",
184
+ "taggeditem",
185
+ "tenantgroup",
186
+ "vlangroup",
187
+ "vlanlocationassignment",
188
+ "vminterface",
189
+ "vrfdeviceassignment",
190
+ "vrfprefixassignment",
191
+ "webhook",
192
+ ]
@@ -182,8 +182,7 @@ class APISelect(SelectWithDisabled):
182
182
  # ModelChoiceIterator.__iter__() yields a tuple of (value, label)
183
183
  # using this approach first yield a tuple of (null(value), null_option(label))
184
184
  yield "null", self.null_options
185
- for item in super().__iter__():
186
- yield item
185
+ yield from super().__iter__()
187
186
 
188
187
  null_option = self.attrs.get("data-null-option")
189
188
  self.choices = ModelChoiceIteratorWithNullOption(field=self.choices.field, null_option=null_option)
@@ -1,4 +1,5 @@
1
1
  """Schema module for GraphQL."""
2
+
2
3
  from collections import OrderedDict
3
4
  import logging
4
5
 
@@ -55,6 +55,7 @@ class BaseModel(models.Model):
55
55
  )
56
56
 
57
57
  objects = BaseManager.from_queryset(RestrictedQuerySet)()
58
+ is_contact_associable_model = True
58
59
 
59
60
  class Meta:
60
61
  abstract = True
nautobot/core/settings.py CHANGED
@@ -10,6 +10,7 @@ import django.forms
10
10
  from django.utils.safestring import mark_safe
11
11
 
12
12
  from nautobot import __version__
13
+ from nautobot.core.constants import CONFIG_SETTING_SEPARATOR as _CONFIG_SETTING_SEPARATOR
13
14
  from nautobot.core.settings_funcs import ConstanceConfigItem, is_truthy, parse_redis_connection
14
15
 
15
16
  #
@@ -152,6 +153,9 @@ if "NAUTOBOT_MAX_PAGE_SIZE" in os.environ and os.environ["NAUTOBOT_MAX_PAGE_SIZE
152
153
  # Metrics
153
154
  METRICS_ENABLED = is_truthy(os.getenv("NAUTOBOT_METRICS_ENABLED", "False"))
154
155
  METRICS_AUTHENTICATED = is_truthy(os.getenv("NAUTOBOT_METRICS_AUTHENTICATED", "False"))
156
+ METRICS_DISABLED_APPS = []
157
+ if "NAUTOBOT_METRICS_DISABLED_APPS" in os.environ and os.environ["NAUTOBOT_METRICS_DISABLED_APPS"] != "":
158
+ METRICS_DISABLED_APPS = os.getenv("NAUTOBOT_METRICS_DISABLED_APPS", "").split(_CONFIG_SETTING_SEPARATOR)
155
159
 
156
160
  # Napalm
157
161
  NAPALM_ARGS = {}
@@ -166,7 +170,7 @@ if "NAUTOBOT_PAGINATE_COUNT" in os.environ and os.environ["NAUTOBOT_PAGINATE_COU
166
170
  # The options displayed in the web interface dropdown to limit the number of objects per page.
167
171
  # Default is [25, 50, 100, 250, 500, 1000]
168
172
  if "NAUTOBOT_PER_PAGE_DEFAULTS" in os.environ and os.environ["NAUTOBOT_PER_PAGE_DEFAULTS"] != "":
169
- PER_PAGE_DEFAULTS = [int(val) for val in os.environ["NAUTOBOT_PER_PAGE_DEFAULTS"].split(",")]
173
+ PER_PAGE_DEFAULTS = [int(val) for val in os.environ["NAUTOBOT_PER_PAGE_DEFAULTS"].split(_CONFIG_SETTING_SEPARATOR)]
170
174
 
171
175
  # Plugins
172
176
  PLUGINS = []
@@ -188,6 +192,13 @@ if (
188
192
  ):
189
193
  RACK_ELEVATION_DEFAULT_UNIT_WIDTH = int(os.environ["NAUTOBOT_RACK_ELEVATION_DEFAULT_UNIT_WIDTH"])
190
194
 
195
+ # Enable two-digit format for the rack unit numbering in rack elevations.
196
+ if (
197
+ "NAUTOBOT_RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT" in os.environ
198
+ and os.environ["NAUTOBOT_RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT"] != ""
199
+ ):
200
+ RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT = is_truthy(os.environ["NAUTOBOT_RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT"])
201
+
191
202
  # How frequently to check for a new Nautobot release on GitHub, and the URL to check for this information.
192
203
  # Defaults to disabled (no URL) and check every 24 hours when enabled
193
204
  if "NAUTOBOT_RELEASE_CHECK_TIMEOUT" in os.environ and os.environ["NAUTOBOT_RELEASE_CHECK_TIMEOUT"] != "":
@@ -769,6 +780,11 @@ CONSTANCE_CONFIG = {
769
780
  "RACK_ELEVATION_DEFAULT_UNIT_WIDTH": ConstanceConfigItem(
770
781
  default=230, help_text="Default width (in pixels) of a rack unit in a rack elevation diagram", field_type=int
771
782
  ),
783
+ "RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT": ConstanceConfigItem(
784
+ default=False,
785
+ help_text="Enables two-digit format for the rack unit numbering in a rack elevation diagram",
786
+ field_type=bool,
787
+ ),
772
788
  "RELEASE_CHECK_TIMEOUT": ConstanceConfigItem(
773
789
  default=24 * 3600,
774
790
  help_text="Number of seconds (must be at least 3600, or one hour) to cache the result of a release check "
@@ -800,7 +816,11 @@ CONSTANCE_CONFIG_FIELDSETS = {
800
816
  "Natural Keys": ["DEVICE_NAME_AS_NATURAL_KEY", "LOCATION_NAME_AS_NATURAL_KEY"],
801
817
  "Pagination": ["PAGINATE_COUNT", "MAX_PAGE_SIZE", "PER_PAGE_DEFAULTS"],
802
818
  "Performance": ["DYNAMIC_GROUPS_MEMBER_CACHE_TIMEOUT", "JOB_CREATE_FILE_MAX_SIZE"],
803
- "Rack Elevation Rendering": ["RACK_ELEVATION_DEFAULT_UNIT_HEIGHT", "RACK_ELEVATION_DEFAULT_UNIT_WIDTH"],
819
+ "Rack Elevation Rendering": [
820
+ "RACK_ELEVATION_DEFAULT_UNIT_HEIGHT",
821
+ "RACK_ELEVATION_DEFAULT_UNIT_WIDTH",
822
+ "RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT",
823
+ ],
804
824
  "Release Checking": ["RELEASE_CHECK_URL", "RELEASE_CHECK_TIMEOUT"],
805
825
  "User Interface": ["SUPPORT_MESSAGE"],
806
826
  "Debugging": ["ALLOW_REQUEST_PROFILING"],
@@ -914,7 +934,7 @@ CELERY_TASK_TIME_LIMIT = int(os.getenv("NAUTOBOT_CELERY_TASK_TIME_LIMIT", str(10
914
934
  CELERY_WORKER_PROMETHEUS_PORTS = []
915
935
  if os.getenv("NAUTOBOT_CELERY_WORKER_PROMETHEUS_PORTS"):
916
936
  CELERY_WORKER_PROMETHEUS_PORTS = [
917
- int(value) for value in os.getenv("NAUTOBOT_CELERY_WORKER_PROMETHEUS_PORTS").split(",")
937
+ int(value) for value in os.getenv("NAUTOBOT_CELERY_WORKER_PROMETHEUS_PORTS").split(_CONFIG_SETTING_SEPARATOR)
918
938
  ]
919
939
 
920
940
  # These settings define the custom nautobot serialization encoding as an accepted data encoding format
@@ -1171,6 +1171,19 @@ properties:
1171
1171
  "Guide to Nautobot Prometheus metrics": "../guides/prometheus-metrics.md"
1172
1172
  type: "boolean"
1173
1173
  version_added: "2.1.5"
1174
+ METRICS_DISABLED_APPS:
1175
+ default: []
1176
+ description: >-
1177
+ A list of app names for which Prometheus metrics should be disabled.
1178
+ (If provided as an environment variable, it should be a comma-separated string, for example
1179
+ `NAUTOBOT_METRICS_DISABLED_APPS="nautobot_ssot, nautobot_device_lifecycle_mgmt"`.)
1180
+ environment_variable: "NAUTOBOT_METRICS_DISABLED_APPS"
1181
+ items:
1182
+ type: "string"
1183
+ see_also:
1184
+ "Guide to Nautobot Prometheus metrics": "../guides/prometheus-metrics.md"
1185
+ type: "array"
1186
+ version_added: "2.2.1"
1174
1187
  METRICS_ENABLED:
1175
1188
  default: false
1176
1189
  description: "Toggle the availability of Prometheus-compatible metrics at `/metrics`."
@@ -1376,6 +1389,13 @@ properties:
1376
1389
  environment_variable: "NAUTOBOT_RACK_ELEVATION_DEFAULT_UNIT_WIDTH"
1377
1390
  is_constance_config: true
1378
1391
  type: "integer"
1392
+ RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT:
1393
+ default: false
1394
+ description: "Enables two-digit format for the rack unit numbering in a rack elevation diagram."
1395
+ environment_variable: "NAUTOBOT_RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT"
1396
+ is_constance_config: true
1397
+ type: "boolean"
1398
+ version_added: "2.2.1"
1379
1399
  REDIS_LOCK_TIMEOUT:
1380
1400
  default: 600
1381
1401
  description: >-
nautobot/core/signals.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """Custom signals and handlers for the core Nautobot application."""
2
+
2
3
  import contextlib
3
4
  from functools import wraps
4
5
  import inspect
@@ -87,7 +87,7 @@
87
87
  Advanced
88
88
  </a>
89
89
  </li>
90
- {% if is_contact_associatable_model %}
90
+ {% if object.is_contact_associable_model %}
91
91
  <li role="presentation"{% if request.GET.tab == 'contacts' %} class="active"{% endif %}>
92
92
  <a href="{{ object.get_absolute_url }}#contacts" onclick="switch_tab(this.href)" aria-controls="contacts" role="tab" data-toggle="tab">
93
93
  Contacts
@@ -159,7 +159,7 @@
159
159
  </div>
160
160
  </div>
161
161
  </div>
162
- {% if is_contact_associatable_model %}
162
+ {% if object.is_contact_associable_model %}
163
163
  <div id="contacts" role="tabpanel" class="tab-pane {% if request.GET.tab == 'contacts' %}active{% else %}fade{% endif %}">
164
164
  <div class="row">
165
165
  <div class="col-md-12">
@@ -2,10 +2,10 @@
2
2
  {% load plugins %}
3
3
  {% load static %}
4
4
 
5
- <script src="{% static 'jquery/jquery-3.6.0.min.js' %}"
6
- onerror="window.location='{% url 'media_failure' %}?filename=jquery/jquery-3.6.0.min.js'"></script>
7
- <script src="{% static 'jquery-ui-1.13.1/jquery-ui.min.js' %}"
8
- onerror="window.location='{% url 'media_failure' %}?filename=jquery-ui-1.13.1/jquery-ui.min.js'"></script>
5
+ <script src="{% static 'jquery/jquery-3.7.1.min.js' %}"
6
+ onerror="window.location='{% url 'media_failure' %}?filename=jquery/jquery-3.7.1.min.js'"></script>
7
+ <script src="{% static 'jquery-ui-1.13.2/jquery-ui.min.js' %}"
8
+ onerror="window.location='{% url 'media_failure' %}?filename=jquery-ui-1.13.2/jquery-ui.min.js'"></script>
9
9
  <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"
10
10
  onerror="window.location='{% url 'media_failure' %}?filename=bootstrap-3.4.1-dist/js/bootstrap.min.js'"></script>
11
11
  <script src="{% static 'select2-4.0.13/select2.min.js' %}"
@@ -11,8 +11,8 @@
11
11
  href="{% static 'materialdesignicons-6.5.95/css/materialdesignicons.min.css' %}"
12
12
  onerror="window.location='{% url 'media_failure' %}?filename=materialdesignicons-6.5.95/css/materialdesignicons.min.css'">
13
13
  <link rel="stylesheet"
14
- href="{% static 'jquery-ui-1.13.1/jquery-ui.min.css' %}"
15
- onerror="window.location='{% url 'media_failure' %}?filename=jquery-ui-1.13.1/jquery-ui.min.css'">
14
+ href="{% static 'jquery-ui-1.13.2/jquery-ui.min.css' %}"
15
+ onerror="window.location='{% url 'media_failure' %}?filename=jquery-ui-1.13.2/jquery-ui.min.css'">
16
16
  <link rel="stylesheet"
17
17
  href="{% static 'select2-4.0.13/select2.min.css' %}"
18
18
  onerror="window.location='{% url 'media_failure' %}?filename=select2-4.0.13/select2.min.css'">
@@ -415,6 +415,11 @@ INSTALLATION_METRICS_ENABLED = is_truthy(os.getenv("NAUTOBOT_INSTALLATION_METRIC
415
415
  #
416
416
  # METRICS_AUTHENTICATED = is_truthy(os.getenv("NAUTOBOT_METRICS_AUTHENTICATED", "False"))
417
417
 
418
+ # Disable app metrics for specific apps
419
+ #
420
+ # if "NAUTOBOT_METRICS_DISABLED_APPS" in os.environ and os.environ["NAUTOBOT_METRICS_DISABLED_APPS"] != "":
421
+ # METRICS_DISABLED_APPS = os.getenv("NAUTOBOT_METRICS_DISABLED_APPS", "").split(",")
422
+
418
423
  # Credentials that Nautobot will uses to authenticate to devices when connecting via NAPALM.
419
424
  #
420
425
  # NAPALM_USERNAME = os.getenv("NAUTOBOT_NAPALM_USERNAME", "")
@@ -472,6 +477,14 @@ INSTALLATION_METRICS_ENABLED = is_truthy(os.getenv("NAUTOBOT_INSTALLATION_METRIC
472
477
  # ):
473
478
  # RACK_ELEVATION_DEFAULT_UNIT_WIDTH = int(os.environ["NAUTOBOT_RACK_ELEVATION_DEFAULT_UNIT_WIDTH"])
474
479
 
480
+ # Enable two-digit format for the rack unit numbering in rack elevations.
481
+ #
482
+ # if (
483
+ # "NAUTOBOT_RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT" in os.environ
484
+ # and os.environ["NAUTOBOT_RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT"] != ""
485
+ # ):
486
+ # RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT = is_truthy(os.environ["NAUTOBOT_RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT"])
487
+
475
488
  # Sets an age out timer of redis lock. This is NOT implicitly applied to locks, must be added
476
489
  # to a lock creation as `timeout=settings.REDIS_LOCK_TIMEOUT`
477
490
  #
@@ -509,7 +522,7 @@ INSTALLATION_METRICS_ENABLED = is_truthy(os.getenv("NAUTOBOT_INSTALLATION_METRIC
509
522
  # class path of the storage driver in STORAGE_BACKEND and any configuration options in STORAGE_CONFIG.
510
523
  # These default to None and {} respectively.
511
524
  #
512
- # STORAGE_BACKEND = 'storages.backends.s3boto3.S3Boto3Storage'
525
+ # STORAGE_BACKEND = 'storages.backends.s3.S3Storage'
513
526
  # STORAGE_CONFIG = {
514
527
  # 'AWS_ACCESS_KEY_ID': 'Key ID',
515
528
  # 'AWS_SECRET_ACCESS_KEY': 'Secret',
@@ -109,7 +109,7 @@ def get_job_class_and_model(module, name, source="local"):
109
109
 
110
110
 
111
111
  @tag("unit")
112
- class TransactionTestCase(_TransactionTestCase, NautobotTestCaseMixin):
112
+ class TransactionTestCase(NautobotTestCaseMixin, _TransactionTestCase):
113
113
  """
114
114
  Base test case class using the TransactionTestCase for unit testing
115
115
  """
@@ -44,7 +44,7 @@ class FilterTestCases:
44
44
  # randomly break out of loop after 2 values have been selected
45
45
  if len(test_values) > 1 and random.choice([True, False]): # noqa: S311 # suspicious-non-cryptographic-random-usage
46
46
  break
47
- if value[field_name] and value["count"] <= qs_count:
47
+ if value[field_name] and value["count"] < qs_count:
48
48
  qs_count -= value["count"]
49
49
  test_values.append(str(value[field_name]))
50
50
 
@@ -54,6 +54,7 @@ class AuthenticationEnforcedTestCase(TestCase):
54
54
  url.startswith(path)
55
55
  for path in [
56
56
  "/complete/", # social auth
57
+ "/health/string/", # health-check
57
58
  "/login/", # social auth
58
59
  "/media/", # MEDIA_ROOT
59
60
  "/plugins/example-app/docs/", # STATIC_ROOT
@@ -2,6 +2,7 @@ import re
2
2
  from unittest import mock
3
3
  import urllib.parse
4
4
 
5
+ from django.apps import apps
5
6
  from django.contrib.contenttypes.models import ContentType
6
7
  from django.core.files.uploadedfile import SimpleUploadedFile
7
8
  from django.test import override_settings, RequestFactory
@@ -9,6 +10,7 @@ from django.test.utils import override_script_prefix
9
10
  from django.urls import get_script_prefix, reverse
10
11
  from prometheus_client.parser import text_string_to_metric_families
11
12
 
13
+ from nautobot.core.constants import GLOBAL_SEARCH_EXCLUDE_LIST
12
14
  from nautobot.core.testing import TestCase
13
15
  from nautobot.core.testing.api import APITestCase
14
16
  from nautobot.core.utils.permissions import get_permission_for_model
@@ -71,6 +73,26 @@ class HomeViewTestCase(TestCase):
71
73
  response = self.client.get(f"{url}?{urllib.parse.urlencode(params)}")
72
74
  self.assertHttpStatus(response, 200)
73
75
 
76
+ def test_appropriate_models_included_in_global_search(self):
77
+ # Gather core app configs
78
+ existing_models = []
79
+ global_searchable_models = []
80
+ for app_name in ["circuits", "dcim", "extras", "ipam", "tenancy", "virtualization"]:
81
+ app_config = apps.get_app_config(app_name)
82
+ existing_models += [model._meta.model_name for model in app_config.get_models()]
83
+ global_searchable_models += app_config.searchable_models
84
+
85
+ # Remove those models that are not searchable
86
+ existing_models = [model for model in existing_models if model not in GLOBAL_SEARCH_EXCLUDE_LIST]
87
+ existing_models.sort()
88
+
89
+ # See if there are any models that are missing from global search
90
+ difference = [model for model in existing_models if model not in global_searchable_models]
91
+ if difference:
92
+ self.fail(
93
+ f'Existing model/models {",".join(difference)} are not included in the searchable_models attribute of the app config.\nIf you do not want the models to be searchable, please include them in the GLOBAL_SEARCH_EXCLUDE_LIST constant in nautobot.core.constants.'
94
+ )
95
+
74
96
  def make_request(self):
75
97
  url = reverse("home")
76
98
  response = self.client.get(url)
@@ -51,8 +51,7 @@ def flatten_iterable(iterable):
51
51
  """
52
52
  for i in iterable:
53
53
  if hasattr(i, "__iter__") and not isinstance(i, str):
54
- for j in flatten_iterable(i):
55
- yield j
54
+ yield from flatten_iterable(i)
56
55
  else:
57
56
  yield i
58
57
 
@@ -335,6 +335,8 @@ def get_url_for_url_pattern(url_pattern):
335
335
  url = re.sub(r"<str:\w+>", "string", url)
336
336
  # "/dcim/locations/<uuid:pk>/"
337
337
  url = re.sub(r"<uuid:\w+>", "00000000-0000-0000-0000-000000000000", url)
338
+ # "/api/circuits/<drf_format_suffix:format>"
339
+ url = re.sub(r"<drf_format_suffix:\w+>", ".json", url)
338
340
  # tokens in regexp-style router urls, including REST and NautobotUIViewSet:
339
341
  # "/extras/^external-integrations/(?P<pk>[^/.]+)/$"
340
342
  # "/api/virtualization/^interfaces/(?P<pk>[^/.]+)/$"
@@ -77,7 +77,6 @@ class ObjectView(ObjectPermissionRequiredMixin, View):
77
77
 
78
78
  queryset = None
79
79
  template_name = None
80
- is_contact_associatable_model = True
81
80
 
82
81
  def get_required_permission(self):
83
82
  return get_permission_for_model(self.queryset.model, "view")
@@ -136,7 +135,6 @@ class ObjectView(ObjectPermissionRequiredMixin, View):
136
135
  content_type = ContentType.objects.get_for_model(self.queryset.model)
137
136
  context = {
138
137
  "object": instance,
139
- "is_contact_associatable_model": self.is_contact_associatable_model,
140
138
  "content_type": content_type,
141
139
  "verbose_name": self.queryset.model._meta.verbose_name,
142
140
  "verbose_name_plural": self.queryset.model._meta.verbose_name_plural,
@@ -144,7 +142,7 @@ class ObjectView(ObjectPermissionRequiredMixin, View):
144
142
  "last_updated_by": last_updated_by,
145
143
  **self.get_extra_context(request, instance),
146
144
  }
147
- if self.is_contact_associatable_model:
145
+ if instance.is_contact_associable_model:
148
146
  paginate = {"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
149
147
  associations = (
150
148
  ContactAssociation.objects.filter(
@@ -226,7 +226,6 @@ class NautobotViewSetMixin(GenericViewSet, AccessMixin, GetReturnURLMixin, FormV
226
226
  create_form_class = None
227
227
  update_form_class = None
228
228
  parser_classes = [FormParser, MultiPartParser]
229
- is_contact_associatable_model = True
230
229
  queryset = None
231
230
  # serializer_class has to be specified to eliminate the need to override retrieve() in the RetrieveModelMixin for now.
232
231
  serializer_class = None
@@ -145,7 +145,6 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
145
145
  view = renderer_context["view"]
146
146
  request = renderer_context["request"]
147
147
  # Check if queryset attribute is set before doing anything
148
- is_contact_associatable_model = view.is_contact_associatable_model
149
148
  queryset = view.alter_queryset(request)
150
149
  model = queryset.model
151
150
  form_class = view.get_form_class()
@@ -222,7 +221,6 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
222
221
 
223
222
  context = {
224
223
  "content_type": content_type,
225
- "is_contact_associatable_model": is_contact_associatable_model,
226
224
  "form": form,
227
225
  "filter_form": filter_form,
228
226
  "dynamic_filter_form": self.get_dynamic_filter_form(view, request, filterset_class=view.filterset_class),
@@ -244,9 +242,13 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
244
242
 
245
243
  context["created_by"] = created_by
246
244
  context["last_updated_by"] = last_updated_by
247
- associated_contacts = instance.associated_contacts.restrict(request.user, "view").order_by("role__name")
248
- if is_contact_associatable_model:
249
- context["associated_contacts_table"] = AssociatedContactsTable(data=associated_contacts)
245
+ if instance.is_contact_associable_model:
246
+ paginate = {"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
247
+ associations = instance.associated_contacts.restrict(request.user, "view").order_by("role__name")
248
+ associations_table = AssociatedContactsTable(associations, orderable=False)
249
+ RequestConfig(request, paginate).configure(associations_table)
250
+ associations_table.columns.show("pk")
251
+ context["associated_contacts_table"] = associations_table
250
252
  else:
251
253
  context["associated_contacts_table"] = None
252
254
  context.update(view.get_extra_context(request, instance))