nautobot 2.4.10__py3-none-any.whl → 2.4.12__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.
- nautobot/circuits/templates/circuits/circuittermination_retrieve.html +1 -114
- nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +1 -1
- nautobot/circuits/views.py +76 -6
- nautobot/cloud/navigation.py +1 -1
- nautobot/cloud/tests/test_views.py +13 -1
- nautobot/cloud/views.py +39 -9
- nautobot/core/celery/__init__.py +21 -0
- nautobot/core/celery/encoders.py +3 -0
- nautobot/core/forms/forms.py +4 -1
- nautobot/core/jobs/bulk_actions.py +8 -8
- nautobot/core/jobs/cleanup.py +11 -0
- nautobot/core/management/commands/generate_test_data.py +2 -1
- nautobot/core/templates/components/panel/header_extra_content_table.html +12 -1
- nautobot/core/templates/components/panel/panel.html +4 -0
- nautobot/core/templates/generic/object_retrieve.html +2 -1
- nautobot/core/testing/mixins.py +19 -1
- nautobot/core/testing/views.py +104 -8
- nautobot/core/tests/test_jobs.py +20 -4
- nautobot/core/tests/test_utils.py +17 -0
- nautobot/core/tests/test_views.py +2 -2
- nautobot/core/tests/test_views_utils.py +53 -2
- nautobot/core/ui/object_detail.py +5 -1
- nautobot/core/utils/lookup.py +4 -2
- nautobot/core/utils/module_loading.py +23 -0
- nautobot/core/views/generic.py +2 -12
- nautobot/core/views/mixins.py +19 -1
- nautobot/core/views/renderers.py +4 -13
- nautobot/core/views/utils.py +16 -0
- nautobot/dcim/api/serializers.py +13 -0
- nautobot/dcim/api/urls.py +1 -0
- nautobot/dcim/api/views.py +20 -0
- nautobot/dcim/apps.py +1 -0
- nautobot/dcim/factory.py +11 -0
- nautobot/dcim/filters/__init__.py +116 -0
- nautobot/dcim/filters/mixins.py +2 -1
- nautobot/dcim/forms.py +205 -19
- nautobot/dcim/migrations/0070_modulefamily_models.py +92 -0
- nautobot/dcim/models/__init__.py +2 -0
- nautobot/dcim/models/device_component_templates.py +14 -0
- nautobot/dcim/models/device_components.py +13 -1
- nautobot/dcim/models/devices.py +72 -0
- nautobot/dcim/navigation.py +16 -0
- nautobot/dcim/tables/__init__.py +2 -0
- nautobot/dcim/tables/devices.py +50 -0
- nautobot/dcim/tables/devicetypes.py +35 -1
- nautobot/dcim/tables/template_code.py +2 -0
- nautobot/dcim/templates/dcim/controller/base.html +1 -9
- nautobot/dcim/templates/dcim/controller_retrieve.html +2 -83
- nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +2 -25
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +1 -90
- nautobot/dcim/templates/dcim/inc/cable_toggle_buttons.html +1 -1
- nautobot/dcim/templates/dcim/interfaceredundancygroup_retrieve.html +1 -63
- nautobot/dcim/templates/dcim/location.html +2 -249
- nautobot/dcim/templates/dcim/location_edit.html +2 -38
- nautobot/dcim/templates/dcim/location_retrieve.html +249 -0
- nautobot/dcim/templates/dcim/location_update.html +38 -0
- nautobot/dcim/templates/dcim/module_update.html +1 -0
- nautobot/dcim/templates/dcim/modulebay_retrieve.html +93 -1
- nautobot/dcim/templates/dcim/modulefamily_retrieve.html +31 -0
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +6 -0
- nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -160
- nautobot/dcim/templates/dcim/virtualchassis.html +2 -51
- nautobot/dcim/templates/dcim/virtualchassis_add.html +2 -22
- nautobot/dcim/templates/dcim/virtualchassis_create.html +22 -0
- nautobot/dcim/templates/dcim/virtualchassis_edit.html +2 -93
- nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +51 -0
- nautobot/dcim/templates/dcim/virtualchassis_update.html +93 -0
- nautobot/dcim/tests/test_api.py +35 -0
- nautobot/dcim/tests/test_filters.py +102 -3
- nautobot/dcim/tests/test_models.py +146 -0
- nautobot/dcim/tests/test_views.py +70 -97
- nautobot/dcim/urls.py +5 -80
- nautobot/dcim/views.py +584 -342
- nautobot/extras/api/views.py +9 -2
- nautobot/extras/datasources/git.py +9 -1
- nautobot/extras/forms/forms.py +9 -5
- nautobot/extras/jobs.py +4 -2
- nautobot/extras/jobs_ui.py +208 -0
- nautobot/extras/models/datasources.py +5 -8
- nautobot/extras/models/jobs.py +5 -0
- nautobot/extras/models/tags.py +4 -0
- nautobot/extras/plugins/__init__.py +3 -0
- nautobot/extras/tables.py +40 -3
- nautobot/extras/templates/extras/configcontext.html +2 -220
- nautobot/extras/templates/extras/configcontext_edit.html +2 -50
- nautobot/extras/templates/extras/configcontext_retrieve.html +2 -0
- nautobot/extras/templates/extras/configcontext_update.html +50 -0
- nautobot/extras/templates/extras/configcontextschema.html +2 -48
- nautobot/extras/templates/extras/configcontextschema_edit.html +2 -19
- nautobot/extras/templates/extras/configcontextschema_retrieve.html +48 -0
- nautobot/extras/templates/extras/configcontextschema_update.html +19 -0
- nautobot/extras/templates/extras/inc/configcontext_data.html +1 -0
- nautobot/extras/templates/extras/inc/configcontext_format.html +6 -0
- nautobot/extras/templates/extras/job_detail.html +1 -326
- nautobot/extras/templates/extras/job_edit.html +12 -6
- nautobot/extras/templates/extras/tag.html +2 -52
- nautobot/extras/templates/extras/tag_edit.html +2 -15
- nautobot/extras/templates/extras/tag_retrieve.html +2 -0
- nautobot/extras/templates/extras/tag_update.html +15 -0
- nautobot/extras/templates/extras/team_retrieve.html +2 -2
- nautobot/extras/tests/test_api.py +15 -15
- nautobot/extras/tests/test_filters.py +4 -4
- nautobot/extras/tests/test_jobs.py +23 -10
- nautobot/extras/tests/test_models.py +19 -8
- nautobot/extras/tests/test_plugins.py +6 -3
- nautobot/extras/tests/test_views.py +66 -11
- nautobot/extras/urls.py +4 -134
- nautobot/extras/views.py +186 -178
- nautobot/ipam/models.py +19 -4
- nautobot/ipam/tables.py +19 -0
- nautobot/ipam/templates/ipam/vlan.html +2 -84
- nautobot/ipam/templates/ipam/vlan_edit.html +2 -24
- nautobot/ipam/templates/ipam/vlan_retrieve.html +84 -0
- nautobot/ipam/templates/ipam/vlan_update.html +24 -0
- nautobot/ipam/tests/test_views.py +5 -0
- nautobot/ipam/urls.py +1 -21
- nautobot/ipam/views.py +45 -70
- nautobot/project-static/docs/404.html +33 -10
- nautobot/project-static/docs/apps/index.html +33 -10
- nautobot/project-static/docs/apps/nautobot-apps.html +33 -10
- nautobot/project-static/docs/assets/javascripts/{bundle.13a4f30d.min.js → bundle.56ea9cef.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.13a4f30d.min.js.map → bundle.56ea9cef.min.js.map} +2 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +122 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +33 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +33 -10
- nautobot/project-static/docs/development/apps/api/configuration-view.html +33 -10
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +33 -10
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +33 -10
- nautobot/project-static/docs/development/apps/api/models/global-search.html +33 -10
- nautobot/project-static/docs/development/apps/api/models/graphql.html +33 -10
- nautobot/project-static/docs/development/apps/api/models/index.html +33 -10
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +42 -10
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +33 -10
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +33 -10
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +33 -10
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +33 -10
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +33 -10
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +33 -10
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +33 -10
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +34 -11
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +33 -10
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +33 -10
- nautobot/project-static/docs/development/apps/api/prometheus.html +33 -10
- nautobot/project-static/docs/development/apps/api/setup.html +33 -10
- nautobot/project-static/docs/development/apps/api/testing.html +33 -10
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +33 -10
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +33 -10
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +33 -10
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +33 -10
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +33 -10
- nautobot/project-static/docs/development/apps/api/views/base-template.html +33 -10
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +33 -10
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +33 -10
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +33 -10
- nautobot/project-static/docs/development/apps/api/views/index.html +33 -10
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +33 -10
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +33 -10
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +33 -10
- nautobot/project-static/docs/development/apps/api/views/notes.html +33 -10
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +33 -10
- nautobot/project-static/docs/development/apps/api/views/urls.html +33 -10
- nautobot/project-static/docs/development/apps/index.html +33 -10
- nautobot/project-static/docs/development/apps/migration/code-updates.html +33 -10
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +33 -10
- nautobot/project-static/docs/development/apps/migration/from-v1.html +33 -10
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +33 -10
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +33 -10
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +33 -10
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +33 -10
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +33 -10
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +33 -10
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +33 -10
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +33 -10
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +33 -10
- nautobot/project-static/docs/development/core/application-registry.html +33 -10
- nautobot/project-static/docs/development/core/best-practices.html +33 -10
- nautobot/project-static/docs/development/core/bootstrap-ui.html +33 -10
- nautobot/project-static/docs/development/core/caching.html +33 -10
- nautobot/project-static/docs/development/core/controllers.html +33 -10
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +33 -10
- nautobot/project-static/docs/development/core/generic-views.html +33 -10
- nautobot/project-static/docs/development/core/getting-started.html +33 -10
- nautobot/project-static/docs/development/core/homepage.html +33 -10
- nautobot/project-static/docs/development/core/index.html +33 -10
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +33 -10
- nautobot/project-static/docs/development/core/model-checklist.html +33 -10
- nautobot/project-static/docs/development/core/model-features.html +33 -10
- nautobot/project-static/docs/development/core/natural-keys.html +33 -10
- nautobot/project-static/docs/development/core/navigation-menu.html +33 -10
- nautobot/project-static/docs/development/core/release-checklist.html +33 -10
- nautobot/project-static/docs/development/core/role-internals.html +33 -10
- nautobot/project-static/docs/development/core/settings.html +33 -10
- nautobot/project-static/docs/development/core/style-guide.html +33 -10
- nautobot/project-static/docs/development/core/templates.html +33 -10
- nautobot/project-static/docs/development/core/testing.html +33 -10
- nautobot/project-static/docs/development/core/ui-component-framework.html +33 -10
- nautobot/project-static/docs/development/core/user-preferences.html +33 -10
- nautobot/project-static/docs/development/index.html +33 -10
- nautobot/project-static/docs/development/jobs/getting-started.html +33 -10
- nautobot/project-static/docs/development/jobs/index.html +33 -10
- nautobot/project-static/docs/development/jobs/installation.html +33 -10
- nautobot/project-static/docs/development/jobs/job-extensions.html +33 -10
- nautobot/project-static/docs/development/jobs/job-logging.html +33 -10
- nautobot/project-static/docs/development/jobs/job-patterns.html +33 -10
- nautobot/project-static/docs/development/jobs/job-structure.html +33 -10
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +33 -10
- nautobot/project-static/docs/development/jobs/testing.html +33 -10
- nautobot/project-static/docs/index.html +33 -10
- nautobot/project-static/docs/insert-analytics.sh +36 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +33 -10
- nautobot/project-static/docs/overview/design_philosophy.html +33 -10
- nautobot/project-static/docs/release-notes/index.html +33 -10
- nautobot/project-static/docs/release-notes/version-1.0.html +33 -10
- nautobot/project-static/docs/release-notes/version-1.1.html +33 -10
- nautobot/project-static/docs/release-notes/version-1.2.html +33 -10
- nautobot/project-static/docs/release-notes/version-1.3.html +33 -10
- nautobot/project-static/docs/release-notes/version-1.4.html +33 -10
- nautobot/project-static/docs/release-notes/version-1.5.html +33 -10
- nautobot/project-static/docs/release-notes/version-1.6.html +33 -10
- nautobot/project-static/docs/release-notes/version-2.0.html +33 -10
- nautobot/project-static/docs/release-notes/version-2.1.html +33 -10
- nautobot/project-static/docs/release-notes/version-2.2.html +33 -10
- nautobot/project-static/docs/release-notes/version-2.3.html +33 -10
- nautobot/project-static/docs/release-notes/version-2.4.html +363 -10
- nautobot/project-static/docs/requirements.txt +1 -1
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +302 -298
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +33 -10
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +33 -10
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +33 -10
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +33 -10
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +33 -10
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +33 -10
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +33 -10
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +33 -10
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +33 -10
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +33 -10
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +33 -10
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +33 -10
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +33 -10
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +33 -10
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +33 -10
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +33 -10
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +33 -10
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +33 -10
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +33 -10
- nautobot/project-static/docs/user-guide/administration/installation/index.html +33 -10
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +33 -10
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +33 -10
- nautobot/project-static/docs/user-guide/administration/installation/services.html +33 -10
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +33 -10
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +33 -10
- nautobot/project-static/docs/user-guide/administration/security/index.html +33 -10
- nautobot/project-static/docs/user-guide/administration/security/notices.html +33 -10
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +33 -10
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +33 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +33 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +33 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +33 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +33 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +33 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +33 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +33 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +33 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +45 -22
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +37 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +37 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +37 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +10261 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +36 -13
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +33 -10
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +44 -18
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +33 -10
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +33 -10
- nautobot/project-static/docs/user-guide/index.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +39 -11
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +33 -10
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +33 -10
- nautobot/tenancy/tables.py +2 -0
- nautobot/virtualization/tests/test_views.py +1 -1
- nautobot/wireless/forms.py +0 -1
- nautobot/wireless/models.py +1 -1
- nautobot/wireless/navigation.py +1 -1
- nautobot/wireless/tables.py +18 -3
- {nautobot-2.4.10.dist-info → nautobot-2.4.12.dist-info}/METADATA +4 -4
- {nautobot-2.4.10.dist-info → nautobot-2.4.12.dist-info}/RECORD +439 -419
- /nautobot/dcim/templates/dcim/{platform_edit.html → platform_create.html} +0 -0
- /nautobot/extras/test_jobs/{pass.py → pass_job.py} +0 -0
- {nautobot-2.4.10.dist-info → nautobot-2.4.12.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.10.dist-info → nautobot-2.4.12.dist-info}/NOTICE +0 -0
- {nautobot-2.4.10.dist-info → nautobot-2.4.12.dist-info}/WHEEL +0 -0
- {nautobot-2.4.10.dist-info → nautobot-2.4.12.dist-info}/entry_points.txt +0 -0
nautobot/extras/api/views.py
CHANGED
|
@@ -512,12 +512,19 @@ class JobViewSetBase(
|
|
|
512
512
|
serializer_class = serializers.JobSerializer
|
|
513
513
|
filterset_class = filters.JobFilterSet
|
|
514
514
|
|
|
515
|
+
def get_object(self):
|
|
516
|
+
"""Get the Job instance and reload the job class to ensure we have the latest version of the job code."""
|
|
517
|
+
obj = super().get_object()
|
|
518
|
+
get_job(obj.class_path, reload=True)
|
|
519
|
+
|
|
520
|
+
return obj
|
|
521
|
+
|
|
515
522
|
@extend_schema(responses={"200": serializers.JobVariableSerializer(many=True)})
|
|
516
523
|
@action(detail=True, filterset_class=None)
|
|
517
524
|
def variables(self, request, *args, **kwargs):
|
|
518
525
|
"""Get details of the input variables that may/must be specified to run a particular Job."""
|
|
519
526
|
job_model = self.get_object()
|
|
520
|
-
job_class =
|
|
527
|
+
job_class = job_model.job_class
|
|
521
528
|
if job_class is None:
|
|
522
529
|
raise Http404
|
|
523
530
|
variables_dict = job_class._get_vars()
|
|
@@ -599,7 +606,7 @@ class JobViewSetBase(
|
|
|
599
606
|
"One of these two flags must be removed before this job can be scheduled or run."
|
|
600
607
|
)
|
|
601
608
|
|
|
602
|
-
job_class =
|
|
609
|
+
job_class = job_model.job_class
|
|
603
610
|
if job_class is None:
|
|
604
611
|
raise MethodNotAllowed(
|
|
605
612
|
request.method, detail="This job's source code could not be located and cannot be run"
|
|
@@ -17,7 +17,7 @@ from git import InvalidGitRepositoryError, Repo
|
|
|
17
17
|
import yaml
|
|
18
18
|
|
|
19
19
|
from nautobot.core.utils.git import GitRepo
|
|
20
|
-
from nautobot.core.utils.module_loading import import_modules_privately
|
|
20
|
+
from nautobot.core.utils.module_loading import check_name_safe_to_import_privately, import_modules_privately
|
|
21
21
|
from nautobot.dcim.models import Device, DeviceRedundancyGroup, DeviceType, Location, Platform
|
|
22
22
|
from nautobot.extras.choices import (
|
|
23
23
|
LogLevelChoices,
|
|
@@ -725,6 +725,14 @@ def refresh_job_code_from_repository(repository_slug, skip_reimport=False, ignor
|
|
|
725
725
|
ignore_import_errors (bool): If True, any exceptions raised in the import will be caught and logged.
|
|
726
726
|
If False, exceptions will be re-raised after logging.
|
|
727
727
|
"""
|
|
728
|
+
# Enforced during GitRepository.clean() but just in case someone created a bad record without cleaning:
|
|
729
|
+
permitted, reason = check_name_safe_to_import_privately(repository_slug)
|
|
730
|
+
if not permitted:
|
|
731
|
+
logger.error("The repository_slug %r is invalid as it is %s", repository_slug, reason)
|
|
732
|
+
if ignore_import_errors:
|
|
733
|
+
return
|
|
734
|
+
raise ValueError(f"The repository_slug {repository_slug!r} is invalid as it is {reason}")
|
|
735
|
+
|
|
728
736
|
# Unload any previous version of this module and its submodules if present
|
|
729
737
|
for job_class_path in list(registry["jobs"]):
|
|
730
738
|
if job_class_path.startswith(f"{repository_slug}."):
|
nautobot/extras/forms/forms.py
CHANGED
|
@@ -914,13 +914,13 @@ class ExternalIntegrationBulkEditForm(NautobotBulkEditForm):
|
|
|
914
914
|
secrets_group = DynamicModelChoiceField(required=False, queryset=SecretsGroup.objects.all())
|
|
915
915
|
verify_ssl = forms.NullBooleanField(required=False, label="Verify SSL", widget=BulkEditNullBooleanSelect)
|
|
916
916
|
timeout = forms.IntegerField(required=False, min_value=0)
|
|
917
|
-
extra_config =
|
|
917
|
+
extra_config = JSONField(required=False, widget=forms.Textarea, help_text="JSON data")
|
|
918
918
|
http_method = forms.ChoiceField(
|
|
919
919
|
required=False,
|
|
920
920
|
label="HTTP Method",
|
|
921
921
|
choices=add_blank_choice(WebhookHttpMethodChoices),
|
|
922
922
|
)
|
|
923
|
-
headers =
|
|
923
|
+
headers = JSONField(required=False, widget=forms.Textarea, help_text="Headers for the HTTP request")
|
|
924
924
|
|
|
925
925
|
class Meta:
|
|
926
926
|
model = ExternalIntegration
|
|
@@ -1487,7 +1487,6 @@ class JobQueueBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
|
|
|
1487
1487
|
class Meta:
|
|
1488
1488
|
model = JobQueue
|
|
1489
1489
|
nullable_fields = [
|
|
1490
|
-
"secrets_group",
|
|
1491
1490
|
"description",
|
|
1492
1491
|
"tenant",
|
|
1493
1492
|
]
|
|
@@ -1910,8 +1909,8 @@ class RelationshipBulkEditForm(BootstrapMixin, CustomFieldModelBulkEditFormMixin
|
|
|
1910
1909
|
)
|
|
1911
1910
|
source_hidden = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect)
|
|
1912
1911
|
destination_hidden = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect)
|
|
1913
|
-
source_filter =
|
|
1914
|
-
destination_filter =
|
|
1912
|
+
source_filter = JSONField(required=False, widget=forms.Textarea, help_text="Filter for the source")
|
|
1913
|
+
destination_filter = JSONField(required=False, widget=forms.Textarea, help_text="Filter for the destination")
|
|
1915
1914
|
source_type = CSVContentTypeField(
|
|
1916
1915
|
queryset=ContentType.objects.filter(FeatureQuery("relationships").get_query()), required=False
|
|
1917
1916
|
)
|
|
@@ -2256,6 +2255,8 @@ class WebhookBulkEditForm(BootstrapMixin, NoteModelBulkEditFormMixin):
|
|
|
2256
2255
|
secret = forms.CharField(required=False, max_length=CHARFIELD_MAX_LENGTH)
|
|
2257
2256
|
ca_file_path = forms.CharField(required=False, max_length=4096)
|
|
2258
2257
|
http_content_type = forms.CharField(required=False, max_length=CHARFIELD_MAX_LENGTH)
|
|
2258
|
+
additional_headers = forms.CharField(required=False, widget=forms.Textarea)
|
|
2259
|
+
body_template = forms.CharField(required=False, widget=forms.Textarea)
|
|
2259
2260
|
|
|
2260
2261
|
# Choice field
|
|
2261
2262
|
http_method = forms.ChoiceField(
|
|
@@ -2279,6 +2280,8 @@ class WebhookBulkEditForm(BootstrapMixin, NoteModelBulkEditFormMixin):
|
|
|
2279
2280
|
"type_delete",
|
|
2280
2281
|
"http_method",
|
|
2281
2282
|
"http_content_type",
|
|
2283
|
+
"additional_headers",
|
|
2284
|
+
"body_template",
|
|
2282
2285
|
"ssl_verification",
|
|
2283
2286
|
"ca_file_path",
|
|
2284
2287
|
"payload_url",
|
|
@@ -2286,6 +2289,7 @@ class WebhookBulkEditForm(BootstrapMixin, NoteModelBulkEditFormMixin):
|
|
|
2286
2289
|
"add_content_types",
|
|
2287
2290
|
"remove_content_types",
|
|
2288
2291
|
)
|
|
2292
|
+
nullable_fields = ("additional_headers",)
|
|
2289
2293
|
|
|
2290
2294
|
|
|
2291
2295
|
class WebhookForm(BootstrapMixin, forms.ModelForm):
|
nautobot/extras/jobs.py
CHANGED
|
@@ -17,6 +17,7 @@ from celery.exceptions import Ignore, Reject
|
|
|
17
17
|
from celery.utils.log import get_task_logger
|
|
18
18
|
from db_file_storage.form_widgets import DBClearableFileInput
|
|
19
19
|
from django import forms
|
|
20
|
+
from django.apps import apps
|
|
20
21
|
from django.conf import settings
|
|
21
22
|
from django.contrib.auth import get_user_model
|
|
22
23
|
from django.core.cache import cache
|
|
@@ -1142,8 +1143,9 @@ def get_job(class_path, reload=False):
|
|
|
1142
1143
|
# System job - not reloadable
|
|
1143
1144
|
reload = False
|
|
1144
1145
|
if any(class_path.startswith(f"{app_name}.") for app_name in settings.PLUGINS):
|
|
1145
|
-
# App provided job -
|
|
1146
|
-
|
|
1146
|
+
# App provided job - only reload if the app provides dynamic jobs
|
|
1147
|
+
app_config = apps.get_app_config(class_path.split(".")[0])
|
|
1148
|
+
reload = getattr(app_config, "provides_dynamic_jobs", False)
|
|
1147
1149
|
jobs = get_jobs(reload=reload)
|
|
1148
1150
|
return jobs.get(class_path, None)
|
|
1149
1151
|
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
from django.template import Context
|
|
2
|
+
from django.template.loader import render_to_string
|
|
3
|
+
from django.utils.html import format_html, format_html_join
|
|
4
|
+
from django.utils.safestring import mark_safe
|
|
5
|
+
|
|
6
|
+
from nautobot.core.templatetags import helpers
|
|
7
|
+
from nautobot.core.ui.object_detail import Button, KeyValueTablePanel, ObjectFieldsPanel
|
|
8
|
+
from nautobot.core.views.utils import get_obj_from_context
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class JobRunScheduleButton(Button):
|
|
12
|
+
"""
|
|
13
|
+
A custom button for running or scheduling a job.
|
|
14
|
+
|
|
15
|
+
This button is rendered only if the user has the 'extras.run_job' permission.
|
|
16
|
+
It also disables itself (via HTML 'disabled' attribute) if the related object is not
|
|
17
|
+
installed or not enabled.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def get_extra_context(self, context):
|
|
21
|
+
"""Inject dynamic attributes (e.g. 'disabled') based on object state into the rendering context."""
|
|
22
|
+
extra_context = super().get_extra_context(context)
|
|
23
|
+
obj = context.get("object")
|
|
24
|
+
if not obj.installed or not obj.enabled:
|
|
25
|
+
if extra_context["attributes"] is None:
|
|
26
|
+
extra_context["attributes"] = {}
|
|
27
|
+
extra_context["attributes"]["disabled"] = "disabled"
|
|
28
|
+
return extra_context
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class JobKeyValueOverrideValueTablePanel(KeyValueTablePanel):
|
|
32
|
+
"""A table panel for displaying key-value pairs of job-related attributes, along with any override values defined on the job object."""
|
|
33
|
+
|
|
34
|
+
def _render_overridden_text(self, text):
|
|
35
|
+
"""
|
|
36
|
+
Render a simple overridden value inside a muted <span>, with a customizable prefix.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
value (str): The content to display.
|
|
40
|
+
prefix (str): The label shown before the value (default: 'default is').
|
|
41
|
+
"""
|
|
42
|
+
return format_html('<span class="text-muted">overridden; default is {}</span>', mark_safe(text)) # noqa: S308
|
|
43
|
+
|
|
44
|
+
def _render_overridden_block(self, content):
|
|
45
|
+
"""
|
|
46
|
+
Render a more complex block of HTML content (like rendered markdown or JSON)
|
|
47
|
+
in a div with a muted label indicating it's an overridden value.
|
|
48
|
+
"""
|
|
49
|
+
return format_html('<div class="text-muted">overridden; default is:<br>{}</div>', content)
|
|
50
|
+
|
|
51
|
+
def render_description_default(self, default_value):
|
|
52
|
+
"""
|
|
53
|
+
Render a description field's default value as markdown.
|
|
54
|
+
|
|
55
|
+
If the default value is a string, it is rendered as markdown;
|
|
56
|
+
otherwise, a placeholder is shown.
|
|
57
|
+
"""
|
|
58
|
+
rendered = (
|
|
59
|
+
helpers.render_markdown(default_value)
|
|
60
|
+
if isinstance(default_value, str)
|
|
61
|
+
else helpers.placeholder(default_value)
|
|
62
|
+
)
|
|
63
|
+
return self._render_overridden_block(rendered)
|
|
64
|
+
|
|
65
|
+
def render_time_limit_default(self, default_value, system_default_value, override=True):
|
|
66
|
+
"""
|
|
67
|
+
Render a time limit value, falling back to the system default if needed.
|
|
68
|
+
"""
|
|
69
|
+
message = "{} seconds" if default_value > 0 else "{} seconds (system default)"
|
|
70
|
+
value = default_value if default_value > 0 else system_default_value
|
|
71
|
+
if not override:
|
|
72
|
+
return message.format(value)
|
|
73
|
+
return self._render_overridden_text(message.format(value))
|
|
74
|
+
|
|
75
|
+
def render_job_queues_default(self, obj):
|
|
76
|
+
"""
|
|
77
|
+
Render the job's default task queues as JSON.
|
|
78
|
+
|
|
79
|
+
Attempts to retrieve the `task_queues` from the job's class and render
|
|
80
|
+
it using a JSON template. Falls back to a placeholder on error.
|
|
81
|
+
"""
|
|
82
|
+
try:
|
|
83
|
+
data = obj.job_class.task_queues
|
|
84
|
+
rendered = render_to_string("extras/inc/json_data.html", {"data": data, "format": "json"})
|
|
85
|
+
except Exception:
|
|
86
|
+
rendered = helpers.placeholder(None)
|
|
87
|
+
return self._render_overridden_block(rendered)
|
|
88
|
+
|
|
89
|
+
def render_default_job_queue_default(self, obj):
|
|
90
|
+
"""
|
|
91
|
+
Render the default job queue name from the job class.
|
|
92
|
+
|
|
93
|
+
Retrieves the first queue from `task_queues` if available.
|
|
94
|
+
Falls back to a placeholder if no queues are present.
|
|
95
|
+
"""
|
|
96
|
+
try:
|
|
97
|
+
queue = obj.job_class.task_queues[0]
|
|
98
|
+
except (AttributeError, IndexError, TypeError):
|
|
99
|
+
queue = helpers.placeholder("not specified")
|
|
100
|
+
return self._render_overridden_text(queue)
|
|
101
|
+
|
|
102
|
+
def render_boolean_default(self, default_value):
|
|
103
|
+
"""Render a boolean default value using a standardized visual format."""
|
|
104
|
+
return self._render_overridden_text(helpers.render_boolean(default_value))
|
|
105
|
+
|
|
106
|
+
def render_override_value(self, key, obj):
|
|
107
|
+
"""Render the override value for a given key on a job object."""
|
|
108
|
+
override_attr = f"{key}_override"
|
|
109
|
+
|
|
110
|
+
if not getattr(obj, override_attr, None):
|
|
111
|
+
return ""
|
|
112
|
+
|
|
113
|
+
if not obj.installed:
|
|
114
|
+
return self._render_overridden_text("default is unknown (not currently installed)")
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
default_value = getattr(obj.job_class, key)
|
|
118
|
+
except Exception:
|
|
119
|
+
default_value = "unknown"
|
|
120
|
+
|
|
121
|
+
renderers = {
|
|
122
|
+
"description": self.render_description_default,
|
|
123
|
+
"soft_time_limit": lambda v: self.render_time_limit_default(
|
|
124
|
+
v, helpers.settings_or_config("CELERY_TASK_SOFT_TIME_LIMIT")
|
|
125
|
+
),
|
|
126
|
+
"time_limit": lambda v: self.render_time_limit_default(
|
|
127
|
+
v, helpers.settings_or_config("CELERY_TASK_TIME_LIMIT")
|
|
128
|
+
),
|
|
129
|
+
"job_queues": lambda _: self.render_job_queues_default(obj),
|
|
130
|
+
"default_job_queue": lambda _: self.render_default_job_queue_default(obj),
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if key in renderers:
|
|
134
|
+
return renderers[key](default_value)
|
|
135
|
+
|
|
136
|
+
if isinstance(default_value, bool):
|
|
137
|
+
return self.render_boolean_default(default_value)
|
|
138
|
+
|
|
139
|
+
return self._render_overridden_text(f'"{default_value}"')
|
|
140
|
+
|
|
141
|
+
def render_job_queues_list(self, value):
|
|
142
|
+
"""Renders a <ul> HTML list of job queues with hyperlinks, or a placeholder if none exist."""
|
|
143
|
+
if not value or not value.exists():
|
|
144
|
+
return helpers.placeholder(None)
|
|
145
|
+
|
|
146
|
+
items = format_html_join("\n", "<li>{}</li>", ((helpers.hyperlinked_object(q),) for q in value.all()))
|
|
147
|
+
return format_html("<ul>{}</ul>", items)
|
|
148
|
+
|
|
149
|
+
def render_body_content(self, context: Context):
|
|
150
|
+
"""Render the body content of the panel as a table of key-value rows, including any override information."""
|
|
151
|
+
data = self.get_data(context)
|
|
152
|
+
obj = get_obj_from_context(context)
|
|
153
|
+
|
|
154
|
+
if not data:
|
|
155
|
+
return format_html('<tr><td colspan="2">{}</td></tr>', helpers.placeholder(data))
|
|
156
|
+
|
|
157
|
+
result = format_html("")
|
|
158
|
+
panel_label = helpers.slugify(self.label or "")
|
|
159
|
+
for key, value in data.items():
|
|
160
|
+
key_display = self.render_key(key, value, context)
|
|
161
|
+
override_value_display = self.render_override_value(key, obj)
|
|
162
|
+
if value_display := self.render_value(key, value, context):
|
|
163
|
+
if value_display is helpers.HTML_NONE:
|
|
164
|
+
value_tag = value_display
|
|
165
|
+
else:
|
|
166
|
+
value_tag = format_html(
|
|
167
|
+
"""
|
|
168
|
+
<span class="hover_copy">
|
|
169
|
+
<span id="{unique_id}_value_{key}">{value}</span>
|
|
170
|
+
<button class="btn btn-inline btn-default hover_copy_button" data-clipboard-target="#{unique_id}_value_{key}">
|
|
171
|
+
<span class="mdi mdi-content-copy"></span>
|
|
172
|
+
</button>
|
|
173
|
+
</span>
|
|
174
|
+
""",
|
|
175
|
+
# key might not be globally unique in a page, but is unique to a panel;
|
|
176
|
+
# Hence we add the panel label to make it globally unique to the page
|
|
177
|
+
unique_id=panel_label,
|
|
178
|
+
key=helpers.slugify(key),
|
|
179
|
+
value=value_display,
|
|
180
|
+
)
|
|
181
|
+
result += format_html(
|
|
182
|
+
"<tr><td>{}</td><td>{}</td><td>{}</td></tr>",
|
|
183
|
+
key_display,
|
|
184
|
+
value_tag,
|
|
185
|
+
override_value_display,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
return result
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class JobObjectFieldsPanel(ObjectFieldsPanel, JobKeyValueOverrideValueTablePanel):
|
|
192
|
+
"""
|
|
193
|
+
ObjectFieldsPanel that renders its fields in a 3-column layout.
|
|
194
|
+
Inherits behavior from ObjectFieldsPanel but overrides rendering with JobKeyValueOverrideValueTablePanel.
|
|
195
|
+
"""
|
|
196
|
+
|
|
197
|
+
def render_value(self, key, value, context: Context):
|
|
198
|
+
if key == "job_queues":
|
|
199
|
+
return self.render_job_queues_list(value)
|
|
200
|
+
if key == "soft_time_limit":
|
|
201
|
+
value = self.render_time_limit_default(
|
|
202
|
+
value, helpers.settings_or_config("CELERY_TASK_SOFT_TIME_LIMIT"), override=False
|
|
203
|
+
)
|
|
204
|
+
if key == "time_limit":
|
|
205
|
+
value = self.render_time_limit_default(
|
|
206
|
+
value, helpers.settings_or_config("CELERY_TASK_TIME_LIMIT"), override=False
|
|
207
|
+
)
|
|
208
|
+
return super().render_value(key, value, context)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Models for representing external data sources."""
|
|
2
2
|
|
|
3
3
|
from contextlib import contextmanager
|
|
4
|
-
from importlib.util import find_spec
|
|
5
4
|
import logging
|
|
6
5
|
import os
|
|
7
6
|
import shutil
|
|
@@ -17,7 +16,8 @@ from nautobot.core.models.fields import AutoSlugField, LaxURLField, slugify_dash
|
|
|
17
16
|
from nautobot.core.models.generics import PrimaryModel
|
|
18
17
|
from nautobot.core.models.validators import EnhancedURLValidator
|
|
19
18
|
from nautobot.core.utils.git import GitRepo
|
|
20
|
-
from nautobot.
|
|
19
|
+
from nautobot.core.utils.module_loading import check_name_safe_to_import_privately
|
|
20
|
+
from nautobot.extras.utils import extras_features
|
|
21
21
|
|
|
22
22
|
logger = logging.getLogger(__name__)
|
|
23
23
|
|
|
@@ -105,12 +105,9 @@ class GitRepository(PrimaryModel):
|
|
|
105
105
|
)
|
|
106
106
|
|
|
107
107
|
if not self.present_in_database:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
raise ValidationError(
|
|
112
|
-
f'Please choose a different slug, as "{self.slug}" is an installed Python package or module.'
|
|
113
|
-
)
|
|
108
|
+
permitted, reason = check_name_safe_to_import_privately(self.slug)
|
|
109
|
+
if not permitted:
|
|
110
|
+
raise ValidationError({"slug": f"Please choose a different slug; {self.slug!r} is {reason}"})
|
|
114
111
|
|
|
115
112
|
if self.provided_contents:
|
|
116
113
|
q = models.Q()
|
nautobot/extras/models/jobs.py
CHANGED
|
@@ -1383,6 +1383,11 @@ class ScheduledJob(BaseModel):
|
|
|
1383
1383
|
if job_model.time_limit > 0:
|
|
1384
1384
|
celery_kwargs["time_limit"] = job_model.time_limit
|
|
1385
1385
|
|
|
1386
|
+
# We do this because when a job creates an approval workflow, a scheduled job is also created.
|
|
1387
|
+
# If the scheduled job has an "immediate" interval, the scheduler will not send this task.
|
|
1388
|
+
# since TYPE_IMMEDIATELY is not a valid value in JobExecutionType.SCHEDULE_CHOICES
|
|
1389
|
+
if interval == JobExecutionType.TYPE_IMMEDIATELY:
|
|
1390
|
+
interval = JobExecutionType.TYPE_FUTURE
|
|
1386
1391
|
# 2.0 TODO: To revisit this as part of a larger Jobs cleanup in 2.0.
|
|
1387
1392
|
#
|
|
1388
1393
|
# We pass in task and job_model here partly for forward/backward compatibility logic, and
|
nautobot/extras/models/tags.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from django.contrib.contenttypes.models import ContentType
|
|
2
2
|
from django.db import models
|
|
3
|
+
from django.utils.html import format_html
|
|
3
4
|
from taggit.models import GenericUUIDTaggedItemBase
|
|
4
5
|
|
|
5
6
|
from nautobot.core.choices import ColorChoices
|
|
@@ -65,6 +66,9 @@ class Tag(
|
|
|
65
66
|
class Meta:
|
|
66
67
|
ordering = ["name"]
|
|
67
68
|
|
|
69
|
+
def get_color_display(self):
|
|
70
|
+
return format_html('<span class="label color-block" style="background-color: #{}"> </span>', self.color)
|
|
71
|
+
|
|
68
72
|
def validate_content_types_removal(self, content_types_id):
|
|
69
73
|
"""Validate content_types to be removed are not tagged to a model"""
|
|
70
74
|
errors = {}
|
|
@@ -81,6 +81,9 @@ class NautobotAppConfig(NautobotConfig):
|
|
|
81
81
|
config_view_name = None
|
|
82
82
|
docs_view_name = None
|
|
83
83
|
|
|
84
|
+
# Dynamic jobs. Set to True if the app's job code should be reloaded at runtime
|
|
85
|
+
provides_dynamic_jobs = False
|
|
86
|
+
|
|
84
87
|
# Default integration paths. Plugin authors can override these to customize the paths to
|
|
85
88
|
# integrated components.
|
|
86
89
|
banner_function = "banner.banner"
|
nautobot/extras/tables.py
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
from django.conf import settings
|
|
2
|
+
from django.db.models import QuerySet
|
|
2
3
|
from django.utils.html import format_html, format_html_join
|
|
3
4
|
import django_tables2 as tables
|
|
5
|
+
from django_tables2.data import TableData
|
|
6
|
+
from django_tables2.rows import BoundRows
|
|
4
7
|
from django_tables2.utils import Accessor
|
|
5
8
|
from jsonschema.exceptions import ValidationError as JSONSchemaValidationError
|
|
6
9
|
|
|
10
|
+
from nautobot.core.models.querysets import count_related
|
|
7
11
|
from nautobot.core.tables import (
|
|
8
12
|
BaseTable,
|
|
9
13
|
BooleanColumn,
|
|
@@ -19,7 +23,7 @@ from nautobot.core.tables import (
|
|
|
19
23
|
from nautobot.core.templatetags.helpers import render_boolean, render_json, render_markdown
|
|
20
24
|
from nautobot.tenancy.tables import TenantColumn
|
|
21
25
|
|
|
22
|
-
from .choices import MetadataTypeDataTypeChoices
|
|
26
|
+
from .choices import LogLevelChoices, MetadataTypeDataTypeChoices
|
|
23
27
|
from .models import (
|
|
24
28
|
ComputedField,
|
|
25
29
|
ConfigContext,
|
|
@@ -891,7 +895,7 @@ class JobResultTable(BaseTable):
|
|
|
891
895
|
)
|
|
892
896
|
summary = tables.Column(
|
|
893
897
|
empty_values=(),
|
|
894
|
-
verbose_name="
|
|
898
|
+
verbose_name="Summary",
|
|
895
899
|
orderable=False,
|
|
896
900
|
attrs={"td": {"class": "text-nowrap report-stats"}},
|
|
897
901
|
)
|
|
@@ -901,6 +905,40 @@ class JobResultTable(BaseTable):
|
|
|
901
905
|
)
|
|
902
906
|
actions = ButtonsColumn(JobResult, buttons=("delete",), prepend_template=JOB_RESULT_BUTTONS)
|
|
903
907
|
|
|
908
|
+
def __init__(self, *args, **kwargs):
|
|
909
|
+
super().__init__(*args, **kwargs)
|
|
910
|
+
# Only calculate log counts for "summary" column if it's actually visible.
|
|
911
|
+
if "summary" in self.columns and self.columns["summary"].visible and isinstance(self.data.data, QuerySet):
|
|
912
|
+
self.data = TableData.from_data(
|
|
913
|
+
self.data.data.annotate(
|
|
914
|
+
debug_log_count=count_related(
|
|
915
|
+
JobLogEntry, "job_result", filter_dict={"log_level": LogLevelChoices.LOG_DEBUG}
|
|
916
|
+
),
|
|
917
|
+
success_log_count=count_related(
|
|
918
|
+
JobLogEntry, "job_result", filter_dict={"log_level": LogLevelChoices.LOG_SUCCESS}
|
|
919
|
+
),
|
|
920
|
+
info_log_count=count_related(
|
|
921
|
+
JobLogEntry, "job_result", filter_dict={"log_level": LogLevelChoices.LOG_INFO}
|
|
922
|
+
),
|
|
923
|
+
warning_log_count=count_related(
|
|
924
|
+
JobLogEntry, "job_result", filter_dict={"log_level": LogLevelChoices.LOG_WARNING}
|
|
925
|
+
),
|
|
926
|
+
error_log_count=count_related(
|
|
927
|
+
JobLogEntry,
|
|
928
|
+
"job_result",
|
|
929
|
+
filter_dict={
|
|
930
|
+
"log_level__in": [
|
|
931
|
+
LogLevelChoices.LOG_FAILURE,
|
|
932
|
+
LogLevelChoices.LOG_ERROR,
|
|
933
|
+
LogLevelChoices.LOG_CRITICAL,
|
|
934
|
+
],
|
|
935
|
+
},
|
|
936
|
+
),
|
|
937
|
+
)
|
|
938
|
+
)
|
|
939
|
+
self.data.set_table(self)
|
|
940
|
+
self.rows = BoundRows(data=self.data, table=self, pinned_data=self.pinned_data)
|
|
941
|
+
|
|
904
942
|
def render_summary(self, record):
|
|
905
943
|
"""
|
|
906
944
|
Define custom rendering for the summary column.
|
|
@@ -940,7 +978,6 @@ class JobResultTable(BaseTable):
|
|
|
940
978
|
"job_model",
|
|
941
979
|
"user",
|
|
942
980
|
"status",
|
|
943
|
-
"summary",
|
|
944
981
|
"actions",
|
|
945
982
|
)
|
|
946
983
|
|