nautobot 2.0.5__py3-none-any.whl → 2.1.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/circuits/navigation.py +0 -25
- nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -9
- nautobot/circuits/templates/circuits/providernetwork_retrieve.html +0 -2
- nautobot/circuits/tests/test_filters.py +1 -0
- nautobot/core/api/serializers.py +15 -5
- nautobot/core/api/views.py +18 -19
- nautobot/core/choices.py +1 -1
- nautobot/core/filters.py +12 -4
- nautobot/core/jobs/__init__.py +125 -3
- nautobot/core/management/commands/generate_test_data.py +4 -1
- nautobot/core/models/fields.py +12 -2
- nautobot/core/settings.py +8 -7
- nautobot/core/templates/base_django.html +2 -2
- nautobot/core/templates/buttons/export.html +57 -30
- nautobot/core/templates/generic/object_list.html +2 -2
- nautobot/core/templates/generic/object_retrieve.html +8 -1
- nautobot/core/templates/home.html +5 -5
- nautobot/core/templates/inc/created_updated.html +2 -2
- nautobot/core/templates/inc/footer.html +2 -2
- nautobot/core/templates/inc/javascript.html +0 -10
- nautobot/core/templates/inc/media.html +2 -0
- nautobot/core/templates/inc/nav_menu.html +66 -68
- nautobot/core/templates/inc/object_details_advanced_panel.html +19 -0
- nautobot/core/templates/nautobot_config.py.j2 +10 -4
- nautobot/core/templates/panel_table.html +1 -1
- nautobot/core/templates/template.css +89 -0
- nautobot/core/templates/utilities/templatetags/table_config_form.html +1 -0
- nautobot/core/templatetags/buttons.py +7 -2
- nautobot/core/testing/views.py +34 -4
- nautobot/core/tests/integration/test_home.py +1 -43
- nautobot/core/tests/integration/test_navbar.py +10 -64
- nautobot/core/tests/integration/test_plugin_home.py +4 -5
- nautobot/core/tests/integration/test_plugin_navbar.py +20 -16
- nautobot/core/tests/integration/test_theme.py +4 -0
- nautobot/core/tests/test_api.py +14 -66
- nautobot/core/tests/test_filters.py +127 -0
- nautobot/core/tests/test_forms.py +1 -1
- nautobot/core/tests/test_graphql.py +165 -2
- nautobot/core/tests/test_jobs.py +112 -0
- nautobot/core/tests/test_openapi.py +6 -0
- nautobot/core/tests/test_views.py +11 -85
- nautobot/core/urls.py +6 -1
- nautobot/core/utils/lookup.py +28 -0
- nautobot/core/utils/requests.py +2 -3
- nautobot/core/views/__init__.py +3 -4
- nautobot/core/views/generic.py +9 -4
- nautobot/core/views/mixins.py +4 -2
- nautobot/core/views/renderers.py +5 -0
- nautobot/dcim/models/device_components.py +1 -0
- nautobot/dcim/navigation.py +10 -165
- nautobot/dcim/templates/dcim/location.html +1 -1
- nautobot/dcim/tests/features/locations.feature +143 -0
- nautobot/dcim/tests/test_api.py +1 -1
- nautobot/dcim/tests/test_filters.py +11 -3
- nautobot/extras/admin.py +1 -1
- nautobot/extras/api/serializers.py +33 -0
- nautobot/extras/api/urls.py +6 -0
- nautobot/extras/api/views.py +45 -6
- nautobot/extras/factory.py +28 -2
- nautobot/extras/filters/__init__.py +52 -0
- nautobot/extras/filters/mixins.py +4 -29
- nautobot/extras/forms/forms.py +43 -0
- nautobot/extras/jobs.py +31 -9
- nautobot/extras/migrations/0100_fileproxy_job_result.py +32 -0
- nautobot/extras/migrations/0101_externalintegration.py +61 -0
- nautobot/extras/migrations/0102_set_null_objectchange_contenttype.py +32 -0
- nautobot/extras/models/__init__.py +2 -0
- nautobot/extras/models/change_logging.py +2 -2
- nautobot/extras/models/models.py +96 -16
- nautobot/extras/navigation.py +17 -29
- nautobot/extras/signals.py +15 -0
- nautobot/extras/tables.py +27 -0
- nautobot/extras/templates/extras/externalintegration_retrieve.html +37 -0
- nautobot/extras/templates/extras/inc/jobresult.html +24 -0
- nautobot/extras/templates/extras/jobresult.html +24 -0
- nautobot/extras/test_jobs/file_output.py +16 -0
- nautobot/extras/tests/test_api.py +92 -0
- nautobot/extras/tests/test_filters.py +64 -2
- nautobot/extras/tests/test_jobs.py +39 -0
- nautobot/extras/tests/test_models.py +34 -0
- nautobot/extras/tests/test_views.py +22 -2
- nautobot/extras/urls.py +1 -0
- nautobot/extras/views.py +15 -0
- nautobot/ipam/forms.py +16 -0
- nautobot/ipam/models.py +3 -0
- nautobot/ipam/navigation.py +2 -59
- nautobot/ipam/templates/ipam/ipaddress.html +0 -9
- nautobot/ipam/templates/ipam/prefix.html +0 -9
- nautobot/ipam/tests/features/prefixes.feature +134 -0
- nautobot/ipam/tests/test_filters.py +5 -10
- nautobot/ipam/tests/test_views.py +8 -1
- nautobot/ipam/views.py +3 -0
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css +191 -191
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +874 -881
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
- nautobot/project-static/css/base.css +135 -99
- nautobot/project-static/css/dark.css +65 -6
- nautobot/project-static/docs/404.html +44 -16
- nautobot/project-static/docs/apps/index.html +44 -16
- nautobot/project-static/docs/apps/nautobot-apps.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1597 -1457
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +45 -17
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +353 -432
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +66 -38
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2154 -2307
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +807 -691
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +58 -30
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +3600 -3456
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +101 -75
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +3083 -3019
- nautobot/project-static/docs/development/apps/api/configuration-view.html +44 -16
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +44 -16
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +44 -16
- nautobot/project-static/docs/development/apps/api/models/global-search.html +44 -16
- nautobot/project-static/docs/development/apps/api/models/graphql.html +44 -16
- nautobot/project-static/docs/development/apps/api/models/index.html +44 -16
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +44 -16
- nautobot/project-static/docs/development/apps/api/prometheus.html +44 -16
- nautobot/project-static/docs/development/apps/api/setup.html +44 -16
- nautobot/project-static/docs/development/apps/api/testing.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-detail-views.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/tabs.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/base-template.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/index.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/notes.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/urls.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/view-overrides.html +44 -16
- nautobot/project-static/docs/development/apps/index.html +44 -16
- nautobot/project-static/docs/development/apps/migration/code-updates.html +44 -16
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +44 -16
- nautobot/project-static/docs/development/apps/migration/from-v1.html +44 -16
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +44 -16
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +44 -16
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +44 -16
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +44 -16
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +44 -16
- nautobot/project-static/docs/development/core/application-registry.html +44 -16
- nautobot/project-static/docs/development/core/best-practices.html +44 -16
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +44 -16
- nautobot/project-static/docs/development/core/extending-models.html +44 -16
- nautobot/project-static/docs/development/core/generic-views.html +44 -16
- nautobot/project-static/docs/development/core/getting-started.html +44 -16
- nautobot/project-static/docs/development/core/homepage.html +44 -16
- nautobot/project-static/docs/development/core/index.html +44 -16
- nautobot/project-static/docs/development/core/model-features.html +44 -16
- nautobot/project-static/docs/development/core/natural-keys.html +44 -16
- nautobot/project-static/docs/development/core/navigation-menu.html +44 -21
- nautobot/project-static/docs/development/core/react-ui.html +44 -16
- nautobot/project-static/docs/development/core/release-checklist.html +44 -16
- nautobot/project-static/docs/development/core/role-internals.html +44 -16
- nautobot/project-static/docs/development/core/style-guide.html +44 -16
- nautobot/project-static/docs/development/core/templates.html +44 -16
- nautobot/project-static/docs/development/core/testing.html +44 -16
- nautobot/project-static/docs/development/core/user-preferences.html +44 -16
- nautobot/project-static/docs/development/index.html +44 -16
- nautobot/project-static/docs/development/jobs/index.html +280 -234
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +44 -16
- nautobot/project-static/docs/index.html +44 -16
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/release-notes/index.html +47 -19
- nautobot/project-static/docs/release-notes/version-1.0.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.1.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.2.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.3.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.4.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.5.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.6.html +44 -16
- nautobot/project-static/docs/release-notes/version-2.0.html +47 -19
- nautobot/project-static/docs/release-notes/version-2.1.html +5724 -0
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +247 -237
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +44 -16
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +44 -16
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +44 -16
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +44 -16
- nautobot/project-static/docs/user-guide/administration/configuration/node-configuration.html +44 -16
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +109 -43
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +48 -19
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/index.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/services.html +44 -16
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +44 -16
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +44 -16
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +44 -16
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +44 -16
- nautobot/project-static/docs/user-guide/index.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +110 -16
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +47 -19
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +5359 -0
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +47 -19
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +113 -44
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +44 -16
- nautobot/project-static/fonts/UFL.txt +96 -0
- nautobot/project-static/fonts/Ubuntu-Bold.woff2 +0 -0
- nautobot/project-static/fonts/Ubuntu-BoldItalic.woff2 +0 -0
- nautobot/project-static/fonts/Ubuntu-Italic.woff2 +0 -0
- nautobot/project-static/fonts/Ubuntu-Medium.woff2 +0 -0
- nautobot/project-static/fonts/Ubuntu-MediumItalic.woff2 +0 -0
- nautobot/project-static/fonts/Ubuntu-Regular.woff2 +0 -0
- nautobot/project-static/fonts/UbuntuMono-Bold.woff2 +0 -0
- nautobot/project-static/fonts/UbuntuMono-BoldItalic.woff2 +0 -0
- nautobot/project-static/fonts/UbuntuMono-Italic.woff2 +0 -0
- nautobot/project-static/fonts/UbuntuMono-Regular.woff2 +0 -0
- nautobot/project-static/img/dark-theme.png +0 -0
- nautobot/project-static/img/light-theme.png +0 -0
- nautobot/project-static/img/nautobot_chevron.svg +5 -0
- nautobot/project-static/img/nautobot_chevron_header.svg +5 -0
- nautobot/project-static/img/system-theme.png +0 -0
- nautobot/tenancy/navigation.py +0 -13
- nautobot/ui/package-lock.json +2 -2
- nautobot/ui/package.json +1 -1
- nautobot/users/admin.py +44 -0
- nautobot/users/migrations/0007_alter_objectpermission_object_types.py +33 -0
- nautobot/users/models.py +3 -2
- nautobot/virtualization/navigation.py +1 -33
- nautobot/virtualization/tests/test_api.py +1 -1
- nautobot/virtualization/tests/test_filters.py +1 -1
- {nautobot-2.0.5.dist-info → nautobot-2.1.0b1.dist-info}/METADATA +1 -1
- {nautobot-2.0.5.dist-info → nautobot-2.1.0b1.dist-info}/RECORD +376 -351
- {nautobot-2.0.5.dist-info → nautobot-2.1.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.0.5.dist-info → nautobot-2.1.0b1.dist-info}/WHEEL +0 -0
- {nautobot-2.0.5.dist-info → nautobot-2.1.0b1.dist-info}/entry_points.txt +0 -0
|
@@ -51,6 +51,8 @@ from nautobot.extras.models import (
|
|
|
51
51
|
DynamicGroup,
|
|
52
52
|
DynamicGroupMembership,
|
|
53
53
|
ExportTemplate,
|
|
54
|
+
ExternalIntegration,
|
|
55
|
+
FileProxy,
|
|
54
56
|
GitRepository,
|
|
55
57
|
GraphQLQuery,
|
|
56
58
|
ImageAttachment,
|
|
@@ -293,6 +295,28 @@ class ExportTemplateSerializer(RelationshipModelSerializerMixin, ValidatedModelS
|
|
|
293
295
|
return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.owner, "owner")
|
|
294
296
|
|
|
295
297
|
|
|
298
|
+
#
|
|
299
|
+
# External integrations
|
|
300
|
+
#
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class ExternalIntegrationSerializer(NautobotModelSerializer):
|
|
304
|
+
class Meta:
|
|
305
|
+
model = ExternalIntegration
|
|
306
|
+
fields = "__all__"
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
#
|
|
310
|
+
# File proxies
|
|
311
|
+
#
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
class FileProxySerializer(BaseModelSerializer):
|
|
315
|
+
class Meta:
|
|
316
|
+
model = FileProxy
|
|
317
|
+
exclude = ["file"]
|
|
318
|
+
|
|
319
|
+
|
|
296
320
|
#
|
|
297
321
|
# Git repositories
|
|
298
322
|
#
|
|
@@ -444,6 +468,15 @@ class JobResultSerializer(CustomFieldModelSerializerMixin, BaseModelSerializer):
|
|
|
444
468
|
class Meta:
|
|
445
469
|
model = JobResult
|
|
446
470
|
fields = "__all__"
|
|
471
|
+
extra_kwargs = {
|
|
472
|
+
"files": {"read_only": True},
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
def get_field_names(self, declared_fields, info):
|
|
476
|
+
"""Add reverse relation to related FileProxy objects."""
|
|
477
|
+
fields = list(super().get_field_names(declared_fields, info))
|
|
478
|
+
self.extend_field_names(fields, "files")
|
|
479
|
+
return fields
|
|
447
480
|
|
|
448
481
|
|
|
449
482
|
class JobRunResponseSerializer(serializers.Serializer):
|
nautobot/extras/api/urls.py
CHANGED
|
@@ -31,6 +31,12 @@ router.register("dynamic-group-memberships", views.DynamicGroupMembershipViewSet
|
|
|
31
31
|
# Export templates
|
|
32
32
|
router.register("export-templates", views.ExportTemplateViewSet)
|
|
33
33
|
|
|
34
|
+
# External integrations
|
|
35
|
+
router.register("external-integrations", views.ExternalIntegrationViewSet)
|
|
36
|
+
|
|
37
|
+
# File proxies
|
|
38
|
+
router.register("file-proxies", views.FileProxyViewSet)
|
|
39
|
+
|
|
34
40
|
# Git repositories
|
|
35
41
|
router.register("git-repositories", views.GitRepositoryViewSet)
|
|
36
42
|
|
nautobot/extras/api/views.py
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
from datetime import timedelta
|
|
2
|
+
|
|
2
3
|
from django.conf import settings
|
|
3
4
|
from django.contrib.contenttypes.models import ContentType
|
|
4
5
|
from django.forms import ValidationError as FormsValidationError
|
|
5
|
-
from django.http import Http404
|
|
6
|
+
from django.http import FileResponse, Http404
|
|
6
7
|
from django.shortcuts import get_object_or_404
|
|
7
8
|
from django.utils import timezone
|
|
8
9
|
from drf_spectacular.types import OpenApiTypes
|
|
9
|
-
from drf_spectacular.utils import extend_schema, extend_schema_view
|
|
10
|
+
from drf_spectacular.utils import OpenApiParameter, extend_schema, extend_schema_view
|
|
10
11
|
from graphene_django.views import GraphQLView
|
|
11
12
|
from graphql import GraphQLError
|
|
12
|
-
from rest_framework import status
|
|
13
|
+
from rest_framework import mixins, status, viewsets
|
|
13
14
|
from rest_framework.decorators import action
|
|
14
15
|
from rest_framework.exceptions import MethodNotAllowed, PermissionDenied, ValidationError
|
|
15
16
|
from rest_framework.parsers import JSONParser, MultiPartParser
|
|
16
17
|
from rest_framework.permissions import IsAuthenticated
|
|
17
18
|
from rest_framework.response import Response
|
|
18
19
|
from rest_framework.routers import APIRootView
|
|
19
|
-
from rest_framework import mixins, viewsets
|
|
20
20
|
|
|
21
21
|
from nautobot.core.api.authentication import TokenPermissions
|
|
22
22
|
from nautobot.core.api.utils import get_serializer_for_model
|
|
@@ -38,10 +38,14 @@ from nautobot.extras.models import (
|
|
|
38
38
|
ComputedField,
|
|
39
39
|
ConfigContext,
|
|
40
40
|
ConfigContextSchema,
|
|
41
|
+
CustomField,
|
|
42
|
+
CustomFieldChoice,
|
|
43
|
+
CustomLink,
|
|
41
44
|
DynamicGroup,
|
|
42
45
|
DynamicGroupMembership,
|
|
43
|
-
CustomLink,
|
|
44
46
|
ExportTemplate,
|
|
47
|
+
ExternalIntegration,
|
|
48
|
+
FileProxy,
|
|
45
49
|
GitRepository,
|
|
46
50
|
GraphQLQuery,
|
|
47
51
|
ImageAttachment,
|
|
@@ -64,9 +68,9 @@ from nautobot.extras.models import (
|
|
|
64
68
|
TaggedItem,
|
|
65
69
|
Webhook,
|
|
66
70
|
)
|
|
67
|
-
from nautobot.extras.models import CustomField, CustomFieldChoice
|
|
68
71
|
from nautobot.extras.secrets.exceptions import SecretError
|
|
69
72
|
from nautobot.extras.utils import get_worker_count
|
|
73
|
+
|
|
70
74
|
from . import serializers
|
|
71
75
|
|
|
72
76
|
|
|
@@ -321,6 +325,41 @@ class ExportTemplateViewSet(NotesViewSetMixin, ModelViewSet):
|
|
|
321
325
|
filterset_class = filters.ExportTemplateFilterSet
|
|
322
326
|
|
|
323
327
|
|
|
328
|
+
#
|
|
329
|
+
# External integrations
|
|
330
|
+
#
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class ExternalIntegrationViewSet(NautobotModelViewSet):
|
|
334
|
+
queryset = ExternalIntegration.objects.select_related("secrets_group")
|
|
335
|
+
serializer_class = serializers.ExternalIntegrationSerializer
|
|
336
|
+
filterset_class = filters.ExternalIntegrationFilterSet
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
#
|
|
340
|
+
# File proxies
|
|
341
|
+
#
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
class FileProxyViewSet(ReadOnlyModelViewSet):
|
|
345
|
+
queryset = FileProxy.objects.select_related("job_result")
|
|
346
|
+
serializer_class = serializers.FileProxySerializer
|
|
347
|
+
filterset_class = filters.FileProxyFilterSet
|
|
348
|
+
|
|
349
|
+
@extend_schema(
|
|
350
|
+
methods=["get"],
|
|
351
|
+
responses=OpenApiTypes.BINARY,
|
|
352
|
+
)
|
|
353
|
+
@action(
|
|
354
|
+
detail=True,
|
|
355
|
+
methods=["get"],
|
|
356
|
+
)
|
|
357
|
+
def download(self, request, *args, **kwargs):
|
|
358
|
+
"""Download the specified FileProxy."""
|
|
359
|
+
file_proxy = self.get_object()
|
|
360
|
+
return FileResponse(file_proxy.file.open("rb"), as_attachment=True)
|
|
361
|
+
|
|
362
|
+
|
|
324
363
|
#
|
|
325
364
|
# Git repositories
|
|
326
365
|
#
|
nautobot/extras/factory.py
CHANGED
|
@@ -3,11 +3,37 @@ import factory
|
|
|
3
3
|
import faker
|
|
4
4
|
|
|
5
5
|
from nautobot.core.choices import ColorChoices
|
|
6
|
-
from nautobot.core.factory import
|
|
7
|
-
|
|
6
|
+
from nautobot.core.factory import (
|
|
7
|
+
get_random_instances,
|
|
8
|
+
NautobotBoolIterator,
|
|
9
|
+
OrganizationalModelFactory,
|
|
10
|
+
PrimaryModelFactory,
|
|
11
|
+
UniqueFaker,
|
|
12
|
+
)
|
|
13
|
+
from nautobot.extras.models import ExternalIntegration, Role, Status, Tag
|
|
8
14
|
from nautobot.extras.utils import FeatureQuery, RoleModelsQuery, TaggableClassesQuery
|
|
9
15
|
|
|
10
16
|
|
|
17
|
+
class ExternalIntegrationFactory(PrimaryModelFactory):
|
|
18
|
+
"""ExternalIntegration model factory."""
|
|
19
|
+
|
|
20
|
+
class Meta:
|
|
21
|
+
model = ExternalIntegration
|
|
22
|
+
|
|
23
|
+
class Params:
|
|
24
|
+
has_extra_config = NautobotBoolIterator()
|
|
25
|
+
|
|
26
|
+
name = UniqueFaker("bs")
|
|
27
|
+
remote_url = factory.Faker("url", schemes=["http", "https", "ssh"])
|
|
28
|
+
verify_ssl = factory.Faker("boolean")
|
|
29
|
+
timeout = factory.Faker("pyint", min_value=0, max_value=300)
|
|
30
|
+
extra_config = factory.Maybe(
|
|
31
|
+
"has_extra_config",
|
|
32
|
+
factory.Faker("pydict", allowed_types=[bool, int, str]),
|
|
33
|
+
None,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
11
37
|
class RoleFactory(OrganizationalModelFactory):
|
|
12
38
|
"""Role model factory."""
|
|
13
39
|
|
|
@@ -9,6 +9,7 @@ from nautobot.core.filters import (
|
|
|
9
9
|
ContentTypeMultipleChoiceFilter,
|
|
10
10
|
MultiValueUUIDFilter,
|
|
11
11
|
NaturalKeyOrPKMultipleChoiceFilter,
|
|
12
|
+
RelatedMembershipBooleanFilter,
|
|
12
13
|
SearchFilter,
|
|
13
14
|
)
|
|
14
15
|
from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
|
|
@@ -52,6 +53,8 @@ from nautobot.extras.models import (
|
|
|
52
53
|
DynamicGroup,
|
|
53
54
|
DynamicGroupMembership,
|
|
54
55
|
ExportTemplate,
|
|
56
|
+
ExternalIntegration,
|
|
57
|
+
FileProxy,
|
|
55
58
|
GitRepository,
|
|
56
59
|
GraphQLQuery,
|
|
57
60
|
ImageAttachment,
|
|
@@ -101,6 +104,7 @@ __all__ = (
|
|
|
101
104
|
"DynamicGroupFilterSet",
|
|
102
105
|
"DynamicGroupMembershipFilterSet",
|
|
103
106
|
"ExportTemplateFilterSet",
|
|
107
|
+
"FileProxyFilterSet",
|
|
104
108
|
"GitRepositoryFilterSet",
|
|
105
109
|
"GraphQLQueryFilterSet",
|
|
106
110
|
"ImageAttachmentFilterSet",
|
|
@@ -484,6 +488,54 @@ class ExportTemplateFilterSet(BaseFilterSet):
|
|
|
484
488
|
fields = ["id", "content_type", "owner_content_type", "owner_object_id", "name"]
|
|
485
489
|
|
|
486
490
|
|
|
491
|
+
#
|
|
492
|
+
# External integrations
|
|
493
|
+
#
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
class ExternalIntegrationFilterSet(NautobotFilterSet):
|
|
497
|
+
has_secrets_group = RelatedMembershipBooleanFilter(
|
|
498
|
+
field_name="secrets_group",
|
|
499
|
+
label="Has secrets group",
|
|
500
|
+
)
|
|
501
|
+
secrets_group = NaturalKeyOrPKMultipleChoiceFilter(
|
|
502
|
+
queryset=SecretsGroup.objects.all(),
|
|
503
|
+
label="Secrets group (ID or name)",
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
class Meta:
|
|
507
|
+
model = ExternalIntegration
|
|
508
|
+
fields = "__all__"
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
#
|
|
512
|
+
# File proxies
|
|
513
|
+
#
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
class FileProxyFilterSet(BaseFilterSet):
|
|
517
|
+
q = SearchFilter(
|
|
518
|
+
filter_predicates={
|
|
519
|
+
"name": "icontains",
|
|
520
|
+
"job_result__job_model__name": "icontains",
|
|
521
|
+
},
|
|
522
|
+
)
|
|
523
|
+
job = NaturalKeyOrPKMultipleChoiceFilter(
|
|
524
|
+
field_name="job_result__job_model",
|
|
525
|
+
to_field_name="name",
|
|
526
|
+
queryset=Job.objects.all(),
|
|
527
|
+
label="Job (name or ID)",
|
|
528
|
+
)
|
|
529
|
+
job_result_id = django_filters.ModelMultipleChoiceFilter(
|
|
530
|
+
queryset=JobResult.objects.all(),
|
|
531
|
+
label="Job Result (ID)",
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
class Meta:
|
|
535
|
+
model = FileProxy
|
|
536
|
+
fields = ["id", "name", "uploaded_at", "job", "job_result_id"]
|
|
537
|
+
|
|
538
|
+
|
|
487
539
|
#
|
|
488
540
|
# Datasources (Git)
|
|
489
541
|
#
|
|
@@ -291,19 +291,13 @@ class RelationshipModelFilterSetMixin(django_filters.FilterSet):
|
|
|
291
291
|
|
|
292
292
|
|
|
293
293
|
class RoleFilter(NaturalKeyOrPKMultipleChoiceFilter):
|
|
294
|
-
"""
|
|
294
|
+
"""Filter field used for filtering Role fields."""
|
|
295
295
|
|
|
296
296
|
def __init__(self, *args, **kwargs):
|
|
297
|
-
kwargs.setdefault("field_name", "role")
|
|
298
297
|
kwargs.setdefault("queryset", Role.objects.all())
|
|
299
|
-
kwargs.setdefault("to_field_name", "name")
|
|
300
298
|
kwargs.setdefault("label", "Role (name or ID)")
|
|
301
|
-
|
|
302
299
|
super().__init__(*args, **kwargs)
|
|
303
300
|
|
|
304
|
-
def get_queryset(self, request):
|
|
305
|
-
return self.queryset.get_for_model(self.model)
|
|
306
|
-
|
|
307
301
|
|
|
308
302
|
class RoleModelFilterSetMixin(django_filters.FilterSet):
|
|
309
303
|
"""
|
|
@@ -313,35 +307,16 @@ class RoleModelFilterSetMixin(django_filters.FilterSet):
|
|
|
313
307
|
role = RoleFilter()
|
|
314
308
|
|
|
315
309
|
|
|
316
|
-
class StatusFilter(
|
|
310
|
+
class StatusFilter(NaturalKeyOrPKMultipleChoiceFilter):
|
|
317
311
|
"""
|
|
318
312
|
Filter field used for filtering Status fields.
|
|
319
|
-
|
|
320
|
-
Explicitly sets `to_field_name='value'` and dynamically sets queryset to
|
|
321
|
-
retrieve choices for the corresponding model & field name bound to the
|
|
322
|
-
filterset.
|
|
323
313
|
"""
|
|
324
314
|
|
|
325
315
|
def __init__(self, *args, **kwargs):
|
|
326
|
-
kwargs
|
|
316
|
+
kwargs.setdefault("queryset", Status.objects.all())
|
|
317
|
+
kwargs.setdefault("label", "Status (name or ID)")
|
|
327
318
|
super().__init__(*args, **kwargs)
|
|
328
319
|
|
|
329
|
-
def get_queryset(self, request):
|
|
330
|
-
self.queryset = Status.objects.all()
|
|
331
|
-
return super().get_queryset(request)
|
|
332
|
-
|
|
333
|
-
def get_filter_predicate(self, value):
|
|
334
|
-
"""Always use the field's name and the `to_field_name` attribute as predicate."""
|
|
335
|
-
# e.g. `status__name`
|
|
336
|
-
to_field_name = self.field.to_field_name
|
|
337
|
-
name = f"{self.field_name}__{to_field_name}"
|
|
338
|
-
# Sometimes the incoming value is an instance. This block of logic comes from the base
|
|
339
|
-
# `get_filter_predicate()` and was added here to support this.
|
|
340
|
-
try:
|
|
341
|
-
return {name: getattr(value, to_field_name)}
|
|
342
|
-
except (AttributeError, TypeError):
|
|
343
|
-
return {name: value}
|
|
344
|
-
|
|
345
320
|
|
|
346
321
|
class StatusModelFilterSetMixin(django_filters.FilterSet):
|
|
347
322
|
"""
|
nautobot/extras/forms/forms.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
|
|
1
3
|
from django import forms
|
|
2
4
|
from django.conf import settings
|
|
3
5
|
from django.contrib.auth import get_user_model
|
|
@@ -49,6 +51,7 @@ from nautobot.extras.models import (
|
|
|
49
51
|
DynamicGroup,
|
|
50
52
|
DynamicGroupMembership,
|
|
51
53
|
ExportTemplate,
|
|
54
|
+
ExternalIntegration,
|
|
52
55
|
GitRepository,
|
|
53
56
|
GraphQLQuery,
|
|
54
57
|
ImageAttachment,
|
|
@@ -108,6 +111,8 @@ __all__ = (
|
|
|
108
111
|
"DynamicGroupMembershipFormSet",
|
|
109
112
|
"ExportTemplateForm",
|
|
110
113
|
"ExportTemplateFilterForm",
|
|
114
|
+
"ExternalIntegrationForm",
|
|
115
|
+
"ExternalIntegrationBulkEditForm",
|
|
111
116
|
"GitRepositoryForm",
|
|
112
117
|
"GitRepositoryBulkEditForm",
|
|
113
118
|
"GitRepositoryFilterForm",
|
|
@@ -568,6 +573,44 @@ class ExportTemplateFilterForm(BootstrapMixin, forms.Form):
|
|
|
568
573
|
)
|
|
569
574
|
|
|
570
575
|
|
|
576
|
+
#
|
|
577
|
+
# External integrations
|
|
578
|
+
#
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
class ExternalIntegrationForm(NautobotModelForm):
|
|
582
|
+
class Meta:
|
|
583
|
+
model = ExternalIntegration
|
|
584
|
+
fields = "__all__"
|
|
585
|
+
|
|
586
|
+
EXTRA_CONFIG_HELP_TEXT = """
|
|
587
|
+
Optional user-defined <a href="https://json.org/">JSON</a> data for this integration. Example:
|
|
588
|
+
<pre><code>{
|
|
589
|
+
"headers": {
|
|
590
|
+
"Accept": "application/json",
|
|
591
|
+
"Content-Type": "application/json",
|
|
592
|
+
},
|
|
593
|
+
}</code></pre>
|
|
594
|
+
"""
|
|
595
|
+
help_texts = {"extra_config": inspect.cleandoc(EXTRA_CONFIG_HELP_TEXT)}
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
class ExternalIntegrationBulkEditForm(NautobotBulkEditForm):
|
|
599
|
+
pk = forms.ModelMultipleChoiceField(
|
|
600
|
+
queryset=ExternalIntegration.objects.all(),
|
|
601
|
+
widget=forms.MultipleHiddenInput(),
|
|
602
|
+
)
|
|
603
|
+
remote_url = forms.CharField(required=False, label="Remote URL")
|
|
604
|
+
secrets_group = DynamicModelChoiceField(required=False, queryset=SecretsGroup.objects.all())
|
|
605
|
+
verify_ssl = forms.NullBooleanField(required=False, label="Verify SSL", widget=BulkEditNullBooleanSelect)
|
|
606
|
+
timeout = forms.IntegerField(required=False, min_value=0)
|
|
607
|
+
extra_config = forms.JSONField(required=False)
|
|
608
|
+
|
|
609
|
+
class Meta:
|
|
610
|
+
model = ExternalIntegration
|
|
611
|
+
nullable_fields = ["extra_config", "secrets_group"]
|
|
612
|
+
|
|
613
|
+
|
|
571
614
|
#
|
|
572
615
|
# Git repositories and other data sources
|
|
573
616
|
#
|
nautobot/extras/jobs.py
CHANGED
|
@@ -21,6 +21,7 @@ from db_file_storage.form_widgets import DBClearableFileInput
|
|
|
21
21
|
from django import forms
|
|
22
22
|
from django.conf import settings
|
|
23
23
|
from django.contrib.auth import get_user_model
|
|
24
|
+
from django.core.files.base import ContentFile
|
|
24
25
|
from django.core.files.uploadedfile import InMemoryUploadedFile
|
|
25
26
|
from django.core.validators import RegexValidator
|
|
26
27
|
from django.db.models import Model
|
|
@@ -306,7 +307,7 @@ class BaseJob(Task):
|
|
|
306
307
|
file_fields = list(self._get_file_vars())
|
|
307
308
|
file_ids = [kwargs[f] for f in file_fields]
|
|
308
309
|
if file_ids:
|
|
309
|
-
self.
|
|
310
|
+
self._delete_file_proxies(*file_ids)
|
|
310
311
|
|
|
311
312
|
self.logger.info("Job completed", extra={"grouping": "post_run"})
|
|
312
313
|
|
|
@@ -531,8 +532,10 @@ class BaseJob(Task):
|
|
|
531
532
|
@classmethod
|
|
532
533
|
def _get_vars(cls):
|
|
533
534
|
"""
|
|
534
|
-
Return dictionary of ScriptVariable attributes defined on this class
|
|
535
|
-
|
|
535
|
+
Return dictionary of ScriptVariable attributes defined on this class or any of its base parent classes.
|
|
536
|
+
|
|
537
|
+
The variables are sorted in the order that they were defined,
|
|
538
|
+
with variables defined on base classes appearing before subclass variables.
|
|
536
539
|
"""
|
|
537
540
|
cls_vars = {}
|
|
538
541
|
# get list of base classes, including cls, in reverse method resolution order: [BaseJob, Job, cls]
|
|
@@ -661,7 +664,7 @@ class BaseJob(Task):
|
|
|
661
664
|
return_data[field_name] = value.pk
|
|
662
665
|
# FileVar (Save each FileVar as a FileProxy)
|
|
663
666
|
elif isinstance(value, InMemoryUploadedFile):
|
|
664
|
-
return_data[field_name] = BaseJob.
|
|
667
|
+
return_data[field_name] = BaseJob._save_file_to_proxy(value)
|
|
665
668
|
# IPAddressVar, IPAddressWithMaskVar, IPNetworkVar
|
|
666
669
|
elif isinstance(value, netaddr.ip.BaseIP):
|
|
667
670
|
return_data[field_name] = str(value)
|
|
@@ -721,7 +724,7 @@ class BaseJob(Task):
|
|
|
721
724
|
else:
|
|
722
725
|
return_data[field_name] = var.field_attrs["queryset"].get(pk=value)
|
|
723
726
|
elif isinstance(var, FileVar):
|
|
724
|
-
return_data[field_name] = cls.
|
|
727
|
+
return_data[field_name] = cls._load_file_from_proxy(value)
|
|
725
728
|
# IPAddressVar is a netaddr.IPAddress object
|
|
726
729
|
elif isinstance(var, IPAddressVar):
|
|
727
730
|
return_data[field_name] = netaddr.IPAddress(value)
|
|
@@ -758,20 +761,20 @@ class BaseJob(Task):
|
|
|
758
761
|
return {k: v for k, v in job_kwargs.items() if k in job_vars}
|
|
759
762
|
|
|
760
763
|
@staticmethod
|
|
761
|
-
def
|
|
764
|
+
def _load_file_from_proxy(pk):
|
|
762
765
|
"""Load a file proxy stored in the database by primary key.
|
|
763
766
|
|
|
764
767
|
Args:
|
|
765
768
|
pk (uuid): Primary key of the `FileProxy` to retrieve
|
|
766
769
|
|
|
767
770
|
Returns:
|
|
768
|
-
(
|
|
771
|
+
(File): A File-like object
|
|
769
772
|
"""
|
|
770
773
|
fp = FileProxy.objects.get(pk=pk)
|
|
771
774
|
return fp.file
|
|
772
775
|
|
|
773
776
|
@staticmethod
|
|
774
|
-
def
|
|
777
|
+
def _save_file_to_proxy(uploaded_file):
|
|
775
778
|
"""
|
|
776
779
|
Save an uploaded file to the database as a file proxy and return the
|
|
777
780
|
primary key.
|
|
@@ -785,7 +788,7 @@ class BaseJob(Task):
|
|
|
785
788
|
fp = FileProxy.objects.create(name=uploaded_file.name, file=uploaded_file)
|
|
786
789
|
return fp.pk
|
|
787
790
|
|
|
788
|
-
def
|
|
791
|
+
def _delete_file_proxies(self, *files_to_delete):
|
|
789
792
|
"""Given an unpacked list of primary keys for `FileProxy` objects, delete them.
|
|
790
793
|
|
|
791
794
|
Args:
|
|
@@ -824,6 +827,25 @@ class BaseJob(Task):
|
|
|
824
827
|
|
|
825
828
|
return data
|
|
826
829
|
|
|
830
|
+
def create_file(self, filename, content):
|
|
831
|
+
"""
|
|
832
|
+
Create a file that can later be downloaded by users.
|
|
833
|
+
|
|
834
|
+
Args:
|
|
835
|
+
filename (str): Name of the file to create, including extension
|
|
836
|
+
content (str, bytes): Content to populate the created file with.
|
|
837
|
+
|
|
838
|
+
Returns:
|
|
839
|
+
(FileProxy): record that was created
|
|
840
|
+
"""
|
|
841
|
+
if isinstance(content, str):
|
|
842
|
+
content = content.encode("utf-8")
|
|
843
|
+
fp = FileProxy.objects.create(
|
|
844
|
+
name=filename, job_result=self.job_result, file=ContentFile(content, name=filename)
|
|
845
|
+
)
|
|
846
|
+
self.logger.info("Created file [%s](%s)", filename, fp.file.url)
|
|
847
|
+
return fp
|
|
848
|
+
|
|
827
849
|
|
|
828
850
|
class Job(BaseJob):
|
|
829
851
|
"""
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Generated by Django 3.2.22 on 2023-10-27 16:32
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
import django.db.models.deletion
|
|
5
|
+
import nautobot.extras.models.models
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
dependencies = [
|
|
10
|
+
("extras", "0099_remove_dangling_note_objects"),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AddField(
|
|
15
|
+
model_name="fileproxy",
|
|
16
|
+
name="job_result",
|
|
17
|
+
field=models.ForeignKey(
|
|
18
|
+
blank=True,
|
|
19
|
+
null=True,
|
|
20
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
21
|
+
related_name="files",
|
|
22
|
+
to="extras.jobresult",
|
|
23
|
+
),
|
|
24
|
+
),
|
|
25
|
+
migrations.AlterField(
|
|
26
|
+
model_name="fileproxy",
|
|
27
|
+
name="file",
|
|
28
|
+
field=models.FileField(
|
|
29
|
+
storage=nautobot.extras.models.models._job_storage, upload_to=nautobot.extras.models.models._upload_to
|
|
30
|
+
),
|
|
31
|
+
),
|
|
32
|
+
]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Generated by Django 3.2.22 on 2023-11-01 21:29
|
|
2
|
+
|
|
3
|
+
import django.core.serializers.json
|
|
4
|
+
import django.core.validators
|
|
5
|
+
from django.db import migrations, models
|
|
6
|
+
import django.db.models.deletion
|
|
7
|
+
import nautobot.core.models.fields
|
|
8
|
+
import nautobot.core.models.validators
|
|
9
|
+
import nautobot.extras.models.mixins
|
|
10
|
+
import uuid
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Migration(migrations.Migration):
|
|
14
|
+
dependencies = [
|
|
15
|
+
("extras", "0100_fileproxy_job_result"),
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
operations = [
|
|
19
|
+
migrations.CreateModel(
|
|
20
|
+
name="ExternalIntegration",
|
|
21
|
+
fields=[
|
|
22
|
+
(
|
|
23
|
+
"id",
|
|
24
|
+
models.UUIDField(
|
|
25
|
+
default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True
|
|
26
|
+
),
|
|
27
|
+
),
|
|
28
|
+
("created", models.DateTimeField(auto_now_add=True, null=True)),
|
|
29
|
+
("last_updated", models.DateTimeField(auto_now=True, null=True)),
|
|
30
|
+
(
|
|
31
|
+
"_custom_field_data",
|
|
32
|
+
models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
|
|
33
|
+
),
|
|
34
|
+
("name", models.CharField(max_length=255, unique=True)),
|
|
35
|
+
(
|
|
36
|
+
"remote_url",
|
|
37
|
+
models.CharField(
|
|
38
|
+
max_length=500, validators=[nautobot.core.models.validators.EnhancedURLValidator()]
|
|
39
|
+
),
|
|
40
|
+
),
|
|
41
|
+
("verify_ssl", models.BooleanField(default=True)),
|
|
42
|
+
("timeout", models.IntegerField(default=30, validators=[django.core.validators.MinValueValidator(0)])),
|
|
43
|
+
("extra_config", models.JSONField(blank=True, null=True)),
|
|
44
|
+
(
|
|
45
|
+
"secrets_group",
|
|
46
|
+
models.ForeignKey(
|
|
47
|
+
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to="extras.secretsgroup"
|
|
48
|
+
),
|
|
49
|
+
),
|
|
50
|
+
("tags", nautobot.core.models.fields.TagsField(through="extras.TaggedItem", to="extras.Tag")),
|
|
51
|
+
],
|
|
52
|
+
options={
|
|
53
|
+
"ordering": ["name"],
|
|
54
|
+
},
|
|
55
|
+
bases=(
|
|
56
|
+
models.Model,
|
|
57
|
+
nautobot.extras.models.mixins.DynamicGroupMixin,
|
|
58
|
+
nautobot.extras.models.mixins.NotesMixin,
|
|
59
|
+
),
|
|
60
|
+
),
|
|
61
|
+
]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Generated by Django 3.2.23 on 2023-11-27 20:43
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
import django.db.models.deletion
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
dependencies = [
|
|
9
|
+
("contenttypes", "0002_remove_content_type_name"),
|
|
10
|
+
("extras", "0101_externalintegration"),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AlterField(
|
|
15
|
+
model_name="objectchange",
|
|
16
|
+
name="changed_object_type",
|
|
17
|
+
field=models.ForeignKey(
|
|
18
|
+
null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="+", to="contenttypes.contenttype"
|
|
19
|
+
),
|
|
20
|
+
),
|
|
21
|
+
migrations.AlterField(
|
|
22
|
+
model_name="objectchange",
|
|
23
|
+
name="related_object_type",
|
|
24
|
+
field=models.ForeignKey(
|
|
25
|
+
blank=True,
|
|
26
|
+
null=True,
|
|
27
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
28
|
+
related_name="+",
|
|
29
|
+
to="contenttypes.contenttype",
|
|
30
|
+
),
|
|
31
|
+
),
|
|
32
|
+
]
|
|
@@ -19,6 +19,7 @@ from .models import (
|
|
|
19
19
|
ConfigContextSchema,
|
|
20
20
|
CustomLink,
|
|
21
21
|
ExportTemplate,
|
|
22
|
+
ExternalIntegration,
|
|
22
23
|
FileAttachment,
|
|
23
24
|
FileProxy,
|
|
24
25
|
GraphQLQuery,
|
|
@@ -45,6 +46,7 @@ __all__ = (
|
|
|
45
46
|
"DynamicGroup",
|
|
46
47
|
"DynamicGroupMembership",
|
|
47
48
|
"ExportTemplate",
|
|
49
|
+
"ExternalIntegration",
|
|
48
50
|
"FileAttachment",
|
|
49
51
|
"FileProxy",
|
|
50
52
|
"GitRepository",
|
|
@@ -84,7 +84,7 @@ class ObjectChange(BaseModel):
|
|
|
84
84
|
user_name = models.CharField(max_length=150, editable=False)
|
|
85
85
|
request_id = models.UUIDField(editable=False, db_index=True)
|
|
86
86
|
action = models.CharField(max_length=50, choices=ObjectChangeActionChoices)
|
|
87
|
-
changed_object_type = models.ForeignKey(to=ContentType, on_delete=models.
|
|
87
|
+
changed_object_type = models.ForeignKey(to=ContentType, on_delete=models.SET_NULL, null=True, related_name="+")
|
|
88
88
|
changed_object_id = models.UUIDField(db_index=True)
|
|
89
89
|
changed_object = GenericForeignKey(ct_field="changed_object_type", fk_field="changed_object_id")
|
|
90
90
|
change_context = models.CharField(
|
|
@@ -96,7 +96,7 @@ class ObjectChange(BaseModel):
|
|
|
96
96
|
change_context_detail = models.CharField(max_length=CHANGELOG_MAX_CHANGE_CONTEXT_DETAIL, blank=True, editable=False)
|
|
97
97
|
related_object_type = models.ForeignKey(
|
|
98
98
|
to=ContentType,
|
|
99
|
-
on_delete=models.
|
|
99
|
+
on_delete=models.SET_NULL,
|
|
100
100
|
related_name="+",
|
|
101
101
|
blank=True,
|
|
102
102
|
null=True,
|