nautobot 2.2.5__py3-none-any.whl → 2.2.7__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/apps/api.py +2 -0
- nautobot/apps/models.py +2 -0
- nautobot/core/api/fields.py +13 -0
- nautobot/core/api/mixins.py +6 -1
- nautobot/core/api/schema.py +3 -1
- nautobot/core/api/serializers.py +7 -1
- nautobot/core/celery/__init__.py +1 -1
- nautobot/core/management/commands/generate_test_data.py +128 -158
- nautobot/core/models/fields.py +15 -0
- nautobot/core/tests/runner.py +10 -0
- nautobot/core/tests/test_utils.py +48 -1
- nautobot/core/utils/git.py +121 -49
- nautobot/core/utils/module_loading.py +10 -2
- nautobot/dcim/factory.py +1 -1
- nautobot/dcim/tests/test_models.py +2 -0
- nautobot/extras/datasources/git.py +133 -135
- nautobot/extras/datasources/utils.py +3 -0
- nautobot/extras/filters/__init__.py +1 -0
- nautobot/extras/forms/forms.py +16 -3
- nautobot/extras/jobs.py +9 -1
- nautobot/extras/migrations/0107_laxurlfield.py +28 -0
- nautobot/extras/migrations/0108_jobbutton_enabled.py +17 -0
- nautobot/extras/models/datasources.py +6 -4
- nautobot/extras/models/groups.py +9 -2
- nautobot/extras/models/jobs.py +30 -0
- nautobot/extras/models/models.py +2 -4
- nautobot/extras/tables.py +3 -0
- nautobot/extras/templates/extras/jobbutton_retrieve.html +6 -2
- nautobot/extras/templatetags/job_buttons.py +2 -2
- nautobot/extras/tests/git_data/01-valid-files/__init__.py +0 -0
- nautobot/extras/tests/git_data/01-valid-files/config_context_schemas/schema-1.yaml +18 -0
- nautobot/extras/tests/git_data/01-valid-files/config_contexts/context.yaml +12 -0
- nautobot/extras/tests/git_data/01-valid-files/config_contexts/devices/test-device.json +3 -0
- nautobot/extras/tests/git_data/01-valid-files/config_contexts/locations/Test Location.json +7 -0
- nautobot/extras/tests/git_data/01-valid-files/export_templates/dcim/device/template.j2 +3 -0
- nautobot/extras/tests/git_data/01-valid-files/export_templates/dcim/device/template2.html +4 -0
- nautobot/extras/tests/git_data/01-valid-files/export_templates/ipam/vlan/template.j2 +3 -0
- nautobot/extras/tests/git_data/01-valid-files/jobs/__init__.py +5 -0
- nautobot/extras/tests/git_data/01-valid-files/jobs/my_job.py +16 -0
- nautobot/extras/tests/git_data/02-invalid-files/__init__.py +0 -0
- nautobot/extras/tests/git_data/02-invalid-files/config_context_schemas/badschema1.json +2 -0
- nautobot/extras/tests/git_data/02-invalid-files/config_context_schemas/badschema2.json +1 -0
- nautobot/extras/tests/git_data/02-invalid-files/config_contexts/badcontext1.json +2 -0
- nautobot/extras/tests/git_data/02-invalid-files/config_contexts/badcontext2.json +1 -0
- nautobot/extras/tests/git_data/02-invalid-files/config_contexts/badcontext3.json +3 -0
- nautobot/extras/tests/git_data/02-invalid-files/config_contexts/devices/nosuchdevice.json +1 -0
- nautobot/extras/tests/git_data/02-invalid-files/dcim/template.j2 +0 -0
- nautobot/extras/tests/git_data/02-invalid-files/devices/template.j2 +0 -0
- nautobot/extras/tests/git_data/02-invalid-files/export_templates/dcim/nosuchmodel/template.j2 +3 -0
- nautobot/extras/tests/git_data/02-invalid-files/export_templates/nosuchapp/device/template.j2 +3 -0
- nautobot/extras/tests/git_data/02-invalid-files/jobs/__init__.py +2 -0
- nautobot/extras/tests/git_data/02-invalid-files/jobs/importerror.py +1 -0
- nautobot/extras/tests/git_data/02-invalid-files/jobs/syntaxerror.py +1 -0
- nautobot/extras/tests/git_helper.py +76 -0
- nautobot/extras/tests/test_api.py +28 -11
- nautobot/extras/tests/test_datasources.py +94 -276
- nautobot/extras/tests/test_dynamicgroups.py +8 -1
- nautobot/extras/tests/test_models.py +8 -3
- nautobot/extras/tests/test_views.py +21 -7
- nautobot/extras/views.py +1 -1
- nautobot/ipam/api/serializers.py +46 -16
- nautobot/ipam/api/views.py +29 -16
- nautobot/ipam/filters.py +9 -1
- nautobot/ipam/forms.py +8 -0
- nautobot/ipam/tables.py +1 -1
- nautobot/ipam/tests/test_api.py +15 -20
- nautobot/ipam/tests/test_filters.py +15 -0
- nautobot/project-static/docs/404.html +83 -8
- nautobot/project-static/docs/apps/index.html +96 -10
- nautobot/project-static/docs/apps/nautobot-apps.html +96 -10
- nautobot/project-static/docs/assets/app-icons/icon-CapacityMetrics.svg +1 -0
- nautobot/project-static/docs/assets/app-icons/icon-CircuitMaintenance.png +0 -0
- nautobot/project-static/docs/assets/javascripts/{bundle.ebd0bdb7.min.js → bundle.fe8b6f2b.min.js} +4 -4
- nautobot/project-static/docs/assets/javascripts/{bundle.ebd0bdb7.min.js.map → bundle.fe8b6f2b.min.js.map} +3 -3
- nautobot/project-static/docs/assets/javascripts/glightbox.min.js +1 -0
- nautobot/project-static/docs/assets/stylesheets/glightbox.min.css +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +156 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +106 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +96 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +143 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +96 -10
- nautobot/project-static/docs/development/apps/api/configuration-view.html +96 -10
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +96 -10
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +96 -10
- nautobot/project-static/docs/development/apps/api/models/global-search.html +96 -10
- nautobot/project-static/docs/development/apps/api/models/graphql.html +96 -10
- nautobot/project-static/docs/development/apps/api/models/index.html +96 -10
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +96 -10
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +96 -10
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +96 -10
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +96 -10
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +96 -10
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +96 -10
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +96 -10
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +96 -10
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +96 -10
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +96 -10
- nautobot/project-static/docs/development/apps/api/prometheus.html +96 -10
- nautobot/project-static/docs/development/apps/api/setup.html +96 -10
- nautobot/project-static/docs/development/apps/api/testing.html +96 -10
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +96 -10
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +96 -10
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +96 -10
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +96 -10
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +96 -10
- nautobot/project-static/docs/development/apps/api/views/base-template.html +96 -10
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +96 -10
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +96 -10
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +96 -10
- nautobot/project-static/docs/development/apps/api/views/index.html +96 -10
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +96 -10
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +96 -10
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +96 -10
- nautobot/project-static/docs/development/apps/api/views/notes.html +96 -10
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +96 -10
- nautobot/project-static/docs/development/apps/api/views/urls.html +96 -10
- nautobot/project-static/docs/development/apps/index.html +96 -10
- nautobot/project-static/docs/development/apps/migration/code-updates.html +97 -11
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +96 -10
- nautobot/project-static/docs/development/apps/migration/from-v1.html +96 -10
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +96 -10
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +96 -10
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +96 -10
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +96 -10
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +96 -10
- nautobot/project-static/docs/development/core/application-registry.html +96 -10
- nautobot/project-static/docs/development/core/best-practices.html +96 -10
- nautobot/project-static/docs/development/core/bootstrap-ui.html +96 -10
- nautobot/project-static/docs/development/core/caching.html +96 -10
- nautobot/project-static/docs/development/core/controllers.html +96 -10
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +96 -10
- nautobot/project-static/docs/development/core/generic-views.html +96 -10
- nautobot/project-static/docs/development/core/getting-started.html +98 -13
- nautobot/project-static/docs/development/core/homepage.html +96 -10
- nautobot/project-static/docs/development/core/index.html +96 -10
- nautobot/project-static/docs/development/core/model-checklist.html +96 -10
- nautobot/project-static/docs/development/core/model-features.html +96 -10
- nautobot/project-static/docs/development/core/natural-keys.html +96 -10
- nautobot/project-static/docs/development/core/navigation-menu.html +96 -10
- nautobot/project-static/docs/development/core/release-checklist.html +96 -10
- nautobot/project-static/docs/development/core/role-internals.html +96 -10
- nautobot/project-static/docs/development/core/settings.html +96 -10
- nautobot/project-static/docs/development/core/style-guide.html +96 -10
- nautobot/project-static/docs/development/core/templates.html +96 -10
- nautobot/project-static/docs/development/core/testing.html +109 -11
- nautobot/project-static/docs/development/core/user-preferences.html +96 -10
- nautobot/project-static/docs/development/index.html +96 -10
- nautobot/project-static/docs/development/jobs/index.html +96 -10
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +96 -10
- nautobot/project-static/docs/index.html +13 -8362
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +8229 -0
- nautobot/project-static/docs/overview/design_philosophy.html +8158 -0
- nautobot/project-static/docs/overview/index.html +8230 -0
- nautobot/project-static/docs/release-notes/index.html +96 -10
- nautobot/project-static/docs/release-notes/version-1.0.html +96 -10
- nautobot/project-static/docs/release-notes/version-1.1.html +96 -10
- nautobot/project-static/docs/release-notes/version-1.2.html +96 -10
- nautobot/project-static/docs/release-notes/version-1.3.html +96 -10
- nautobot/project-static/docs/release-notes/version-1.4.html +96 -10
- nautobot/project-static/docs/release-notes/version-1.5.html +96 -10
- nautobot/project-static/docs/release-notes/version-1.6.html +96 -10
- nautobot/project-static/docs/release-notes/version-2.0.html +96 -10
- nautobot/project-static/docs/release-notes/version-2.1.html +96 -10
- nautobot/project-static/docs/release-notes/version-2.2.html +516 -131
- nautobot/project-static/docs/requirements.txt +2 -1
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +268 -258
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +96 -10
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +96 -10
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +96 -10
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +96 -10
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +96 -10
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +96 -10
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +96 -10
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +96 -10
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +96 -10
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +96 -10
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +96 -10
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +96 -10
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +96 -10
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +96 -10
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +96 -10
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +96 -10
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +96 -10
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +96 -10
- nautobot/project-static/docs/user-guide/administration/installation/index.html +96 -10
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +96 -10
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +96 -10
- nautobot/project-static/docs/user-guide/administration/installation/services.html +96 -10
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +96 -10
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +96 -10
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +96 -10
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +96 -10
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +96 -10
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +96 -10
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +96 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +96 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +96 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +96 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +96 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +96 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +96 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +96 -10
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-location-changes.yaml +1 -1
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +97 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +96 -10
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +96 -10
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +96 -10
- nautobot/project-static/docs/user-guide/index.html +99 -13
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +97 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +101 -14
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +96 -10
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +96 -10
- nautobot/project-static/js/connection_toggles.js +7 -6
- {nautobot-2.2.5.dist-info → nautobot-2.2.7.dist-info}/METADATA +2 -2
- {nautobot-2.2.5.dist-info → nautobot-2.2.7.dist-info}/RECORD +344 -311
- nautobot/extras/tests/test_git.py +0 -23
- {nautobot-2.2.5.dist-info → nautobot-2.2.7.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.5.dist-info → nautobot-2.2.7.dist-info}/NOTICE +0 -0
- {nautobot-2.2.5.dist-info → nautobot-2.2.7.dist-info}/WHEEL +0 -0
- {nautobot-2.2.5.dist-info → nautobot-2.2.7.dist-info}/entry_points.txt +0 -0
nautobot/extras/forms/forms.py
CHANGED
|
@@ -27,6 +27,7 @@ from nautobot.core.forms import (
|
|
|
27
27
|
DynamicModelMultipleChoiceField,
|
|
28
28
|
JSONArrayFormField,
|
|
29
29
|
JSONField,
|
|
30
|
+
LaxURLField,
|
|
30
31
|
MultipleContentTypeField,
|
|
31
32
|
SlugField,
|
|
32
33
|
StaticSelect2,
|
|
@@ -687,7 +688,7 @@ class PasswordInputWithPlaceholder(forms.PasswordInput):
|
|
|
687
688
|
class GitRepositoryForm(NautobotModelForm):
|
|
688
689
|
slug = SlugField(help_text="Filesystem-friendly unique shorthand")
|
|
689
690
|
|
|
690
|
-
remote_url =
|
|
691
|
+
remote_url = LaxURLField(
|
|
691
692
|
required=True,
|
|
692
693
|
label="Remote URL",
|
|
693
694
|
help_text="Only http:// and https:// URLs are presently supported",
|
|
@@ -738,7 +739,7 @@ class GitRepositoryBulkEditForm(NautobotBulkEditForm):
|
|
|
738
739
|
queryset=GitRepository.objects.all(),
|
|
739
740
|
widget=forms.MultipleHiddenInput(),
|
|
740
741
|
)
|
|
741
|
-
remote_url =
|
|
742
|
+
remote_url = LaxURLField(
|
|
742
743
|
label="Remote URL",
|
|
743
744
|
required=False,
|
|
744
745
|
)
|
|
@@ -1012,6 +1013,10 @@ class JobHookForm(BootstrapMixin, forms.ModelForm):
|
|
|
1012
1013
|
content_types = MultipleContentTypeField(
|
|
1013
1014
|
queryset=ChangeLoggedModelsQuery().as_queryset(), required=True, label="Content Type(s)"
|
|
1014
1015
|
)
|
|
1016
|
+
job = DynamicModelChoiceField(
|
|
1017
|
+
queryset=Job.objects.filter(is_job_hook_receiver=True),
|
|
1018
|
+
query_params={"is_job_hook_receiver": True},
|
|
1019
|
+
)
|
|
1015
1020
|
|
|
1016
1021
|
class Meta:
|
|
1017
1022
|
model = JobHook
|
|
@@ -1179,14 +1184,19 @@ class JobButtonForm(BootstrapMixin, forms.ModelForm):
|
|
|
1179
1184
|
api_url="/api/extras/content-types/",
|
|
1180
1185
|
),
|
|
1181
1186
|
)
|
|
1187
|
+
job = DynamicModelChoiceField(
|
|
1188
|
+
queryset=Job.objects.filter(is_job_button_receiver=True),
|
|
1189
|
+
query_params={"is_job_button_receiver": True},
|
|
1190
|
+
)
|
|
1182
1191
|
|
|
1183
1192
|
class Meta:
|
|
1184
1193
|
model = JobButton
|
|
1185
1194
|
fields = (
|
|
1186
1195
|
"content_types",
|
|
1187
1196
|
"name",
|
|
1188
|
-
"text",
|
|
1189
1197
|
"job",
|
|
1198
|
+
"enabled",
|
|
1199
|
+
"text",
|
|
1190
1200
|
"weight",
|
|
1191
1201
|
"group_name",
|
|
1192
1202
|
"button_class",
|
|
@@ -1206,6 +1216,9 @@ class JobButtonBulkEditForm(BootstrapMixin, BulkEditForm):
|
|
|
1206
1216
|
),
|
|
1207
1217
|
required=False,
|
|
1208
1218
|
)
|
|
1219
|
+
enabled = forms.NullBooleanField(
|
|
1220
|
+
required=False, widget=BulkEditNullBooleanSelect, help_text="Whether this job button appears in the UI"
|
|
1221
|
+
)
|
|
1209
1222
|
weight = forms.IntegerField(required=False)
|
|
1210
1223
|
group_name = forms.CharField(required=False)
|
|
1211
1224
|
|
nautobot/extras/jobs.py
CHANGED
|
@@ -1168,6 +1168,14 @@ def enqueue_job_hooks(object_change):
|
|
|
1168
1168
|
job_hooks = JobHook.objects.filter(content_types=content_type, enabled=True, **{action_flag: True})
|
|
1169
1169
|
|
|
1170
1170
|
# Enqueue the jobs related to the job_hooks
|
|
1171
|
+
get_jobs(reload=True)
|
|
1171
1172
|
for job_hook in job_hooks:
|
|
1172
1173
|
job_model = job_hook.job
|
|
1173
|
-
|
|
1174
|
+
if not job_model.installed or not job_model.enabled:
|
|
1175
|
+
logger.warning(
|
|
1176
|
+
"JobHook %s is enabled, but the underlying Job %s is not installed and enabled", job_hook, job_model
|
|
1177
|
+
)
|
|
1178
|
+
elif get_job(job_model.class_path) is None:
|
|
1179
|
+
logger.error("JobHook %s is enabled, but the underlying Job implementation is missing", job_hook)
|
|
1180
|
+
else:
|
|
1181
|
+
JobResult.enqueue_job(job_model, object_change.user, object_change=object_change.pk)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Generated by Django 3.2.25 on 2024-06-17 13:24
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
import nautobot.core.models.fields
|
|
6
|
+
import nautobot.core.models.validators
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Migration(migrations.Migration):
|
|
10
|
+
dependencies = [
|
|
11
|
+
("extras", "0106_populate_default_statuses_and_roles_for_contact_associations"),
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
operations = [
|
|
15
|
+
migrations.AlterField(
|
|
16
|
+
model_name="externalintegration",
|
|
17
|
+
name="remote_url",
|
|
18
|
+
field=nautobot.core.models.fields.LaxURLField(max_length=500),
|
|
19
|
+
),
|
|
20
|
+
migrations.AlterField(
|
|
21
|
+
model_name="gitrepository",
|
|
22
|
+
name="remote_url",
|
|
23
|
+
field=nautobot.core.models.fields.LaxURLField(
|
|
24
|
+
max_length=255,
|
|
25
|
+
validators=[nautobot.core.models.validators.EnhancedURLValidator(schemes=["http", "https"])],
|
|
26
|
+
),
|
|
27
|
+
),
|
|
28
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Generated by Django 3.2.25 on 2024-06-17 19:06
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("extras", "0107_laxurlfield"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AddField(
|
|
13
|
+
model_name="jobbutton",
|
|
14
|
+
name="enabled",
|
|
15
|
+
field=models.BooleanField(default=True),
|
|
16
|
+
),
|
|
17
|
+
]
|
|
@@ -6,18 +6,19 @@ import os
|
|
|
6
6
|
from django.conf import settings
|
|
7
7
|
from django.core.exceptions import ValidationError
|
|
8
8
|
from django.core.serializers.json import DjangoJSONEncoder
|
|
9
|
-
from django.core.validators import URLValidator
|
|
10
9
|
from django.db import models
|
|
11
10
|
|
|
12
11
|
from nautobot.core.constants import CHARFIELD_MAX_LENGTH
|
|
13
|
-
from nautobot.core.models.fields import AutoSlugField, slugify_dashes_to_underscores
|
|
12
|
+
from nautobot.core.models.fields import AutoSlugField, LaxURLField, slugify_dashes_to_underscores
|
|
14
13
|
from nautobot.core.models.generics import PrimaryModel
|
|
14
|
+
from nautobot.core.models.validators import EnhancedURLValidator
|
|
15
15
|
from nautobot.extras.utils import check_if_key_is_graphql_safe, extras_features
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@extras_features(
|
|
19
19
|
"config_context_owners",
|
|
20
20
|
"export_template_owners",
|
|
21
|
+
"graphql",
|
|
21
22
|
"job_results",
|
|
22
23
|
"webhooks",
|
|
23
24
|
)
|
|
@@ -34,15 +35,16 @@ class GitRepository(PrimaryModel):
|
|
|
34
35
|
slugify_function=slugify_dashes_to_underscores,
|
|
35
36
|
)
|
|
36
37
|
|
|
37
|
-
remote_url =
|
|
38
|
+
remote_url = LaxURLField(
|
|
38
39
|
max_length=CHARFIELD_MAX_LENGTH,
|
|
39
40
|
# For the moment we don't support ssh:// and git:// URLs
|
|
40
41
|
help_text="Only HTTP and HTTPS URLs are presently supported",
|
|
41
|
-
validators=[
|
|
42
|
+
validators=[EnhancedURLValidator(schemes=["http", "https"])],
|
|
42
43
|
)
|
|
43
44
|
branch = models.CharField(
|
|
44
45
|
max_length=CHARFIELD_MAX_LENGTH,
|
|
45
46
|
default="main",
|
|
47
|
+
help_text="Branch, tag, or commit",
|
|
46
48
|
)
|
|
47
49
|
|
|
48
50
|
current_head = models.CharField(
|
nautobot/extras/models/groups.py
CHANGED
|
@@ -597,10 +597,17 @@ class DynamicGroup(OrganizationalModel):
|
|
|
597
597
|
query |= filter_field.generate_query(gq_value)
|
|
598
598
|
|
|
599
599
|
# For vanilla multiple-choice filters, we want all values in a set union (boolean OR)
|
|
600
|
-
# because we want ANY of the filter values to match.
|
|
600
|
+
# because we want ANY of the filter values to match. Unless the filter field is explicitly
|
|
601
|
+
# conjoining the values, in which case we want a set intersection (boolean AND). We know this isn't right
|
|
602
|
+
# since the resulting query actually does tag.name == tag_1 AND tag.name == tag_2, but django_filter does
|
|
603
|
+
# not use Q evaluation for conjoined filters. This function is only used for the display, and the display
|
|
604
|
+
# is good enough to get the point across.
|
|
601
605
|
elif isinstance(filter_field, django_filters.MultipleChoiceFilter):
|
|
602
606
|
for v in value:
|
|
603
|
-
|
|
607
|
+
if filter_field.conjoined:
|
|
608
|
+
query &= models.Q(**filter_field.get_filter_predicate(v))
|
|
609
|
+
else:
|
|
610
|
+
query |= models.Q(**filter_field.get_filter_predicate(v))
|
|
604
611
|
|
|
605
612
|
# The method `get_filter_predicate()` is only available on instances or subclasses
|
|
606
613
|
# of `MultipleChoiceFilter`, so we must construct a lookup if a filter is not
|
nautobot/extras/models/jobs.py
CHANGED
|
@@ -318,6 +318,25 @@ class Job(PrimaryModel):
|
|
|
318
318
|
{"approval_required": "A job that may have sensitive variables cannot be marked as requiring approval"}
|
|
319
319
|
)
|
|
320
320
|
|
|
321
|
+
def save(self, *args, **kwargs):
|
|
322
|
+
"""When a Job is uninstalled, auto-disable all associated JobButtons, JobHooks, and ScheduledJobs."""
|
|
323
|
+
super().save(*args, **kwargs)
|
|
324
|
+
if not self.installed:
|
|
325
|
+
if self.is_job_button_receiver:
|
|
326
|
+
for jb in JobButton.objects.filter(job=self, enabled=True):
|
|
327
|
+
logger.info("Disabling JobButton %s derived from %s", jb, self)
|
|
328
|
+
jb.enabled = False
|
|
329
|
+
jb.save()
|
|
330
|
+
if self.is_job_hook_receiver:
|
|
331
|
+
for jh in JobHook.objects.filter(job=self, enabled=True):
|
|
332
|
+
logger.info("Disabling JobHook %s derived from %s", jh, self)
|
|
333
|
+
jh.enabled = False
|
|
334
|
+
jh.save()
|
|
335
|
+
for sj in ScheduledJob.objects.filter(job_model=self, enabled=True):
|
|
336
|
+
logger.info("Disabling ScheduledJob %s derived from %s", sj, self)
|
|
337
|
+
sj.enabled = False
|
|
338
|
+
sj.save()
|
|
339
|
+
|
|
321
340
|
|
|
322
341
|
@extras_features("graphql")
|
|
323
342
|
class JobHook(OrganizationalModel):
|
|
@@ -363,6 +382,9 @@ class JobHook(OrganizationalModel):
|
|
|
363
382
|
if not self.type_create and not self.type_delete and not self.type_update:
|
|
364
383
|
raise ValidationError("You must select at least one type: create, update, and/or delete.")
|
|
365
384
|
|
|
385
|
+
if self.enabled and not (self.job.installed and self.job.enabled):
|
|
386
|
+
raise ValidationError({"enabled": "The selected Job is not installed and enabled"})
|
|
387
|
+
|
|
366
388
|
@classmethod
|
|
367
389
|
def check_for_conflicts(
|
|
368
390
|
cls, instance=None, content_types=None, job=None, type_create=None, type_update=None, type_delete=None
|
|
@@ -375,6 +397,7 @@ class JobHook(OrganizationalModel):
|
|
|
375
397
|
"""
|
|
376
398
|
|
|
377
399
|
conflicts = {}
|
|
400
|
+
|
|
378
401
|
job_hook_error_msg = "A job hook already exists for {action} on {content_type} to job {job}"
|
|
379
402
|
|
|
380
403
|
if instance is not None and instance.present_in_database:
|
|
@@ -783,6 +806,7 @@ class JobButton(BaseModel, ChangeLoggedModel, NotesMixin):
|
|
|
783
806
|
help_text="The object type(s) to which this job button applies.",
|
|
784
807
|
)
|
|
785
808
|
name = models.CharField(max_length=CHARFIELD_MAX_LENGTH, unique=True)
|
|
809
|
+
enabled = models.BooleanField(default=True)
|
|
786
810
|
text = models.CharField(
|
|
787
811
|
max_length=500,
|
|
788
812
|
help_text="Jinja2 template code for button text. Reference the object as <code>{{ obj }}</code> such as <code>{{ obj.platform.name }}</code>. Buttons which render as empty text will not be displayed.",
|
|
@@ -817,6 +841,12 @@ class JobButton(BaseModel, ChangeLoggedModel, NotesMixin):
|
|
|
817
841
|
def __str__(self):
|
|
818
842
|
return self.name
|
|
819
843
|
|
|
844
|
+
def clean(self):
|
|
845
|
+
super().clean()
|
|
846
|
+
|
|
847
|
+
if self.enabled and not (self.job.installed and self.job.enabled):
|
|
848
|
+
raise ValidationError({"enabled": "The selected Job is not installed and enabled"})
|
|
849
|
+
|
|
820
850
|
|
|
821
851
|
class ScheduledJobs(models.Model):
|
|
822
852
|
"""Helper table for tracking updates to scheduled tasks.
|
nautobot/extras/models/models.py
CHANGED
|
@@ -22,9 +22,8 @@ from rest_framework.utils.encoders import JSONEncoder
|
|
|
22
22
|
|
|
23
23
|
from nautobot.core.constants import CHARFIELD_MAX_LENGTH
|
|
24
24
|
from nautobot.core.models import BaseManager, BaseModel
|
|
25
|
-
from nautobot.core.models.fields import ForeignKeyWithAutoRelatedName
|
|
25
|
+
from nautobot.core.models.fields import ForeignKeyWithAutoRelatedName, LaxURLField
|
|
26
26
|
from nautobot.core.models.generics import OrganizationalModel, PrimaryModel
|
|
27
|
-
from nautobot.core.models.validators import EnhancedURLValidator
|
|
28
27
|
from nautobot.core.utils.data import deepmerge, render_jinja2
|
|
29
28
|
from nautobot.extras.choices import (
|
|
30
29
|
ButtonClassChoices,
|
|
@@ -442,10 +441,9 @@ class ExternalIntegration(PrimaryModel):
|
|
|
442
441
|
"""Model for tracking integrations with external applications."""
|
|
443
442
|
|
|
444
443
|
name = models.CharField(max_length=CHARFIELD_MAX_LENGTH, unique=True)
|
|
445
|
-
remote_url =
|
|
444
|
+
remote_url = LaxURLField(
|
|
446
445
|
max_length=500,
|
|
447
446
|
verbose_name="Remote URL",
|
|
448
|
-
validators=[EnhancedURLValidator()],
|
|
449
447
|
)
|
|
450
448
|
secrets_group = models.ForeignKey(
|
|
451
449
|
null=True,
|
nautobot/extras/tables.py
CHANGED
|
@@ -818,6 +818,7 @@ class JobButtonTable(BaseTable):
|
|
|
818
818
|
pk = ToggleColumn()
|
|
819
819
|
name = tables.Column(linkify=True)
|
|
820
820
|
job = tables.Column(linkify=True)
|
|
821
|
+
enabled = BooleanColumn()
|
|
821
822
|
confirmation = BooleanColumn()
|
|
822
823
|
content_types = ContentTypesColumn(truncate_words=15)
|
|
823
824
|
|
|
@@ -829,6 +830,7 @@ class JobButtonTable(BaseTable):
|
|
|
829
830
|
"content_types",
|
|
830
831
|
"text",
|
|
831
832
|
"job",
|
|
833
|
+
"enabled",
|
|
832
834
|
"group_name",
|
|
833
835
|
"weight",
|
|
834
836
|
"button_class",
|
|
@@ -841,6 +843,7 @@ class JobButtonTable(BaseTable):
|
|
|
841
843
|
"group_name",
|
|
842
844
|
"weight",
|
|
843
845
|
"job",
|
|
846
|
+
"enabled",
|
|
844
847
|
"confirmation",
|
|
845
848
|
)
|
|
846
849
|
|
|
@@ -32,19 +32,23 @@
|
|
|
32
32
|
</tr>
|
|
33
33
|
<tr>
|
|
34
34
|
<td>Text</td>
|
|
35
|
-
<td><
|
|
35
|
+
<td><pre>{{ object.text }}</pre></td>
|
|
36
36
|
</tr>
|
|
37
37
|
<tr>
|
|
38
38
|
<td>Job</td>
|
|
39
39
|
<td><a href="{% url 'extras:job_run_by_class_path' class_path=object.job.class_path %}">{{ object.job }}</a></td>
|
|
40
40
|
</tr>
|
|
41
|
+
<tr>
|
|
42
|
+
<td>Enabled</td>
|
|
43
|
+
<td>{{ object.enabled|render_boolean }}</td>
|
|
44
|
+
</tr>
|
|
41
45
|
<tr>
|
|
42
46
|
<td>Button Class</td>
|
|
43
47
|
<td><button class="btn btn-{{ object.button_class }}">{{ object.button_class | title }}</button></td>
|
|
44
48
|
</tr>
|
|
45
49
|
<tr>
|
|
46
50
|
<td>Confirmation</td>
|
|
47
|
-
<td
|
|
51
|
+
<td>{{ object.confirmation|render_boolean}}</td>
|
|
48
52
|
</tr>
|
|
49
53
|
</table>
|
|
50
54
|
</div>
|
|
@@ -127,7 +127,7 @@ def _render_job_button_for_obj(job_button, obj, context, content_type):
|
|
|
127
127
|
"object": obj,
|
|
128
128
|
"job": job_button.job,
|
|
129
129
|
"hidden_inputs": hidden_inputs,
|
|
130
|
-
"disabled": "" if has_run_perm else "disabled",
|
|
130
|
+
"disabled": "" if (has_run_perm and job_button.job.installed and job_button.job.enabled) else "disabled",
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
if job_button.confirmation:
|
|
@@ -149,7 +149,7 @@ def job_buttons(context, obj):
|
|
|
149
149
|
"""
|
|
150
150
|
content_type = ContentType.objects.get_for_model(obj)
|
|
151
151
|
# We will enforce "run" permission later in deciding which buttons to show as disabled.
|
|
152
|
-
buttons = JobButton.objects.filter(content_types=content_type)
|
|
152
|
+
buttons = JobButton.objects.filter(content_types=content_type, enabled=True)
|
|
153
153
|
if not buttons:
|
|
154
154
|
return SAFE_EMPTY_STR
|
|
155
155
|
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
_metadata:
|
|
3
|
+
name: "Config Context Schema 1"
|
|
4
|
+
description: "Schema for defining first names, last names, and ages."
|
|
5
|
+
data_schema:
|
|
6
|
+
title: "Person"
|
|
7
|
+
type: "object"
|
|
8
|
+
properties:
|
|
9
|
+
firstName:
|
|
10
|
+
type: "string"
|
|
11
|
+
description: "The person's first name."
|
|
12
|
+
lastName:
|
|
13
|
+
type: "string"
|
|
14
|
+
description: "The person's last name."
|
|
15
|
+
age:
|
|
16
|
+
description: "Age in years which must be equal to or greater than zero."
|
|
17
|
+
type: "integer"
|
|
18
|
+
minimum: 0
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
_metadata:
|
|
3
|
+
name: "Frobozz 1000 NTP servers"
|
|
4
|
+
weight: 1500
|
|
5
|
+
description: "NTP servers for Frobozz 1000 devices **only**"
|
|
6
|
+
is_active: true
|
|
7
|
+
config_context_schema: "Config Context Schema 1"
|
|
8
|
+
device_types:
|
|
9
|
+
- model: "Frobozz 1000"
|
|
10
|
+
ntp-servers:
|
|
11
|
+
- "172.16.10.22"
|
|
12
|
+
- "172.16.10.33"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from nautobot.extras.jobs import Job, JobButtonReceiver, JobHookReceiver
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MyJob(Job):
|
|
5
|
+
def run(self):
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MyJobHookReceiver(JobHookReceiver):
|
|
10
|
+
def receive_job_hook(self, change, action, changed_object):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MyJobButtonReceiver(JobButtonReceiver):
|
|
15
|
+
def receive_job_button(self, obj):
|
|
16
|
+
pass
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import nosuchmodule
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
print(
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import os.path
|
|
6
|
+
import shutil
|
|
7
|
+
import tempfile
|
|
8
|
+
|
|
9
|
+
from git import Repo
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
SOURCE_DIR = os.path.join(os.path.dirname(__file__), "git_data")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_and_populate_git_repository(target_path):
|
|
18
|
+
"""
|
|
19
|
+
Create a Git repository in `target_path` and populate it with commits and tags based on contents of `SOURCE_DIR`.
|
|
20
|
+
|
|
21
|
+
An initial commit will always be created, containing no tracked files, and will be given the tag `empty-repo`.
|
|
22
|
+
After that, each subdir under `SOURCE_DIR` will be used as the basis for a single commit to the repo, so given:
|
|
23
|
+
|
|
24
|
+
nautobot/extras/tests/git_data
|
|
25
|
+
├── 01-valid-files
|
|
26
|
+
│ ├── config_context_schemas
|
|
27
|
+
│ │ └── schema-1.yaml
|
|
28
|
+
│ └── config_contexts
|
|
29
|
+
│ └── context.yaml
|
|
30
|
+
└── 02-invalid-files
|
|
31
|
+
└── config_context_schemas
|
|
32
|
+
├── badschema1.json
|
|
33
|
+
└── badschema2.json
|
|
34
|
+
|
|
35
|
+
...after the initial empty commit, the next commit would contain files `config_context_schemas/schema-1.yaml` and
|
|
36
|
+
`config_contexts/context.yaml`, and would be given the tag `valid-files`. The next commit would remove those files
|
|
37
|
+
but add the files `config_context_schemas/badschema1.json` and `config_context_schemas/badschema2.json`, and would
|
|
38
|
+
be tagged as `invalid-files`.
|
|
39
|
+
|
|
40
|
+
Note that each commit is fully defined by the files in the appropriate subdirectory; if you want a file to exist
|
|
41
|
+
across multiple separate commits, it must exist in multiple subdirectories. Use of symlinks is encouraged in such
|
|
42
|
+
a scenario.
|
|
43
|
+
"""
|
|
44
|
+
os.makedirs(target_path, exist_ok=True)
|
|
45
|
+
repo = Repo.init(target_path, initial_branch="main")
|
|
46
|
+
repo.config_writer().set_value("user", "name", "Nautobot Automation").release()
|
|
47
|
+
repo.config_writer().set_value("user", "email", "nautobot@nautobot.com").release()
|
|
48
|
+
|
|
49
|
+
repo.index.commit("Empty commit")
|
|
50
|
+
repo.create_tag("empty-repo", message="Nothing here yet")
|
|
51
|
+
|
|
52
|
+
# Create a commit matching each subdirectory in the git_data directory
|
|
53
|
+
for dirname in sorted(os.listdir(SOURCE_DIR)):
|
|
54
|
+
# Clean up from any previous commit
|
|
55
|
+
for root, _, files in os.walk(target_path):
|
|
56
|
+
if ".git" in root:
|
|
57
|
+
continue
|
|
58
|
+
for filename in files:
|
|
59
|
+
repo.index.remove([os.path.join(root, filename)])
|
|
60
|
+
os.remove(os.path.join(root, filename))
|
|
61
|
+
|
|
62
|
+
shutil.copytree(os.path.join(SOURCE_DIR, dirname), target_path, dirs_exist_ok=True)
|
|
63
|
+
for root, _, files in os.walk(target_path):
|
|
64
|
+
if ".git" in root:
|
|
65
|
+
continue
|
|
66
|
+
for filename in files:
|
|
67
|
+
repo.index.add([os.path.join(root, filename)])
|
|
68
|
+
repo.index.commit(dirname)
|
|
69
|
+
# Directory "01-valid-files" --> tag "valid-files" so that we won't break tests if we renumber the directories
|
|
70
|
+
repo.create_tag(dirname[3:], message=f"Tag based on {dirname} files")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
if __name__ == "__main__":
|
|
74
|
+
directory_path = tempfile.TemporaryDirectory().name # pylint: disable=consider-using-with
|
|
75
|
+
print(f"Creating test Git repository in {directory_path}...")
|
|
76
|
+
create_and_populate_git_repository(directory_path)
|