nautobot 2.3.0__py3-none-any.whl → 2.3.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/cloud/factory.py +0 -2
- nautobot/cloud/filters.py +0 -3
- nautobot/cloud/forms.py +1 -7
- nautobot/cloud/migrations/0001_initial.py +1 -1
- nautobot/cloud/models.py +2 -1
- nautobot/cloud/tables.py +17 -1
- nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +7 -1
- nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +0 -11
- nautobot/cloud/templates/cloud/cloudservice_retrieve.html +0 -4
- nautobot/cloud/tests/test_filters.py +0 -12
- nautobot/core/filters.py +1 -15
- nautobot/core/forms/forms.py +2 -10
- nautobot/core/graphql/generators.py +2 -2
- nautobot/core/graphql/schema.py +14 -6
- nautobot/core/jobs/__init__.py +1 -4
- nautobot/core/management/commands/generate_test_data.py +2 -2
- nautobot/core/models/__init__.py +2 -2
- nautobot/core/settings.py +2 -13
- nautobot/core/settings.yaml +2 -16
- nautobot/core/tables.py +0 -3
- nautobot/core/templates/generic/object_retrieve.html +5 -5
- nautobot/core/templates/nautobot_config.py.j2 +0 -15
- nautobot/core/testing/filters.py +1 -12
- nautobot/core/tests/integration/test_general_functionality.py +1 -1
- nautobot/core/tests/test_jobs.py +1 -74
- nautobot/core/views/generic.py +1 -1
- nautobot/core/views/mixins.py +1 -1
- nautobot/core/views/utils.py +6 -8
- nautobot/dcim/factory.py +1 -4
- nautobot/dcim/filters/__init__.py +0 -4
- nautobot/dcim/forms.py +0 -5
- nautobot/dcim/migrations/0061_module_models.py +0 -1
- nautobot/dcim/models/device_components.py +0 -7
- nautobot/dcim/models/devices.py +4 -6
- nautobot/dcim/models/racks.py +1 -0
- nautobot/dcim/tables/devices.py +3 -17
- nautobot/dcim/tables/devicetypes.py +1 -1
- nautobot/dcim/templates/dcim/device/base.html +1 -1
- nautobot/dcim/templates/dcim/device.html +2 -2
- nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +0 -6
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +0 -17
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +2 -2
- nautobot/dcim/tests/test_api.py +0 -2
- nautobot/dcim/tests/test_filters.py +7 -14
- nautobot/dcim/tests/test_models.py +0 -31
- nautobot/dcim/tests/test_views.py +0 -39
- nautobot/dcim/views.py +1 -4
- nautobot/extras/api/views.py +59 -7
- nautobot/extras/factory.py +12 -50
- nautobot/extras/forms/base.py +4 -10
- nautobot/extras/homepage.py +2 -12
- nautobot/extras/jobs.py +2 -2
- nautobot/extras/migrations/0111_metadata.py +4 -4
- nautobot/extras/models/jobs.py +0 -83
- nautobot/extras/models/metadata.py +18 -18
- nautobot/extras/models/models.py +0 -2
- nautobot/extras/signals.py +1 -14
- nautobot/extras/tables.py +14 -43
- nautobot/extras/templates/extras/job_detail.html +0 -11
- nautobot/extras/tests/test_api.py +9 -16
- nautobot/extras/tests/test_jobs.py +2 -2
- nautobot/extras/tests/test_models.py +18 -20
- nautobot/extras/tests/test_views.py +3 -23
- nautobot/extras/utils.py +6 -35
- nautobot/extras/views.py +50 -27
- nautobot/ipam/filters.py +1 -1
- nautobot/ipam/forms.py +1 -1
- nautobot/ipam/models.py +20 -9
- nautobot/ipam/tables.py +0 -4
- nautobot/ipam/tests/test_models.py +2 -3
- nautobot/ipam/views.py +11 -6
- nautobot/project-static/css/base.css +0 -1
- nautobot/project-static/docs/404.html +18 -18
- nautobot/project-static/docs/apps/index.html +18 -18
- nautobot/project-static/docs/apps/nautobot-apps.html +18 -18
- nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +18 -66
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +18 -66
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +18 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +18 -82
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +21 -75
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +18 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +18 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +18 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +19 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +18 -34
- nautobot/project-static/docs/development/apps/api/configuration-view.html +18 -18
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +18 -18
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +18 -18
- nautobot/project-static/docs/development/apps/api/models/global-search.html +18 -18
- nautobot/project-static/docs/development/apps/api/models/graphql.html +18 -18
- nautobot/project-static/docs/development/apps/api/models/index.html +22 -33
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +18 -18
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +18 -18
- nautobot/project-static/docs/development/apps/api/prometheus.html +18 -18
- nautobot/project-static/docs/development/apps/api/setup.html +18 -18
- nautobot/project-static/docs/development/apps/api/testing.html +18 -18
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +18 -18
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +18 -18
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +18 -18
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +18 -18
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/base-template.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/index.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/notes.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +18 -18
- nautobot/project-static/docs/development/apps/api/views/urls.html +18 -18
- nautobot/project-static/docs/development/apps/index.html +18 -18
- nautobot/project-static/docs/development/apps/migration/code-updates.html +18 -18
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +18 -18
- nautobot/project-static/docs/development/apps/migration/from-v1.html +18 -18
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +18 -18
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +18 -18
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +18 -18
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +18 -18
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +18 -18
- nautobot/project-static/docs/development/core/application-registry.html +18 -18
- nautobot/project-static/docs/development/core/best-practices.html +18 -18
- nautobot/project-static/docs/development/core/bootstrap-ui.html +18 -18
- nautobot/project-static/docs/development/core/caching.html +18 -18
- nautobot/project-static/docs/development/core/controllers.html +18 -18
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +18 -18
- nautobot/project-static/docs/development/core/generic-views.html +18 -18
- nautobot/project-static/docs/development/core/getting-started.html +18 -18
- nautobot/project-static/docs/development/core/homepage.html +18 -18
- nautobot/project-static/docs/development/core/index.html +18 -29
- nautobot/project-static/docs/development/core/model-checklist.html +20 -26
- nautobot/project-static/docs/development/core/model-features.html +18 -18
- nautobot/project-static/docs/development/core/natural-keys.html +18 -18
- nautobot/project-static/docs/development/core/navigation-menu.html +18 -18
- nautobot/project-static/docs/development/core/release-checklist.html +18 -18
- nautobot/project-static/docs/development/core/role-internals.html +18 -18
- nautobot/project-static/docs/development/core/settings.html +18 -18
- nautobot/project-static/docs/development/core/style-guide.html +19 -19
- nautobot/project-static/docs/development/core/templates.html +18 -18
- nautobot/project-static/docs/development/core/testing.html +18 -18
- nautobot/project-static/docs/development/core/user-preferences.html +18 -18
- nautobot/project-static/docs/development/index.html +18 -18
- nautobot/project-static/docs/development/jobs/index.html +379 -393
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +18 -18
- nautobot/project-static/docs/index.html +13 -9032
- nautobot/project-static/docs/models/extras/metadatachoice.html +3 -3
- nautobot/project-static/docs/models/extras/metadatatype.html +3 -3
- nautobot/project-static/docs/models/extras/objectmetadata.html +3 -3
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +18 -18
- nautobot/project-static/docs/overview/design_philosophy.html +20 -20
- nautobot/project-static/docs/overview/index.html +9032 -13
- nautobot/project-static/docs/release-notes/index.html +19 -252
- nautobot/project-static/docs/release-notes/version-1.0.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.1.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.2.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.3.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.4.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.5.html +18 -18
- nautobot/project-static/docs/release-notes/version-1.6.html +18 -18
- nautobot/project-static/docs/release-notes/version-2.0.html +18 -18
- nautobot/project-static/docs/release-notes/version-2.1.html +18 -18
- nautobot/project-static/docs/release-notes/version-2.2.html +111 -248
- nautobot/project-static/docs/release-notes/version-2.3.html +90 -520
- nautobot/project-static/docs/requirements.txt +3 -3
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +278 -278
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +18 -18
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +18 -18
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +18 -18
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +18 -18
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +20 -52
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +18 -18
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +18 -22
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +18 -18
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +18 -18
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +18 -18
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +18 -18
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +82 -69
- nautobot/project-static/docs/user-guide/administration/installation/index.html +24 -24
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +52 -60
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +87 -80
- nautobot/project-static/docs/user-guide/administration/installation/services.html +44 -37
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +18 -18
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +18 -18
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +18 -18
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +18 -18
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +18 -18
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +24 -76
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +18 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +19 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +19 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +18 -62
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +18 -18
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +18 -18
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +18 -18
- nautobot/project-static/docs/user-guide/index.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +21 -21
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/{objectmetadata.html → metadata.html} +84 -197
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +36 -36
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +33 -33
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +21 -21
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +18 -18
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +18 -18
- nautobot/tenancy/templates/tenancy/tenant.html +4 -4
- nautobot/virtualization/models.py +2 -0
- nautobot/virtualization/tables.py +5 -2
- {nautobot-2.3.0.dist-info → nautobot-2.3.0b1.dist-info}/METADATA +3 -3
- {nautobot-2.3.0.dist-info → nautobot-2.3.0b1.dist-info}/RECORD +364 -364
- nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css.map +0 -1
- {nautobot-2.3.0.dist-info → nautobot-2.3.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.3.0.dist-info → nautobot-2.3.0b1.dist-info}/NOTICE +0 -0
- {nautobot-2.3.0.dist-info → nautobot-2.3.0b1.dist-info}/WHEEL +0 -0
- {nautobot-2.3.0.dist-info → nautobot-2.3.0b1.dist-info}/entry_points.txt +0 -0
nautobot/cloud/factory.py
CHANGED
|
@@ -24,7 +24,6 @@ class CloudAccountFactory(PrimaryModelFactory):
|
|
|
24
24
|
has_description = NautobotBoolIterator()
|
|
25
25
|
description = factory.Maybe("has_description", factory.Faker("sentence"), "")
|
|
26
26
|
provider = random_instance(Manufacturer, allow_null=False)
|
|
27
|
-
# TODO: once SecretsGroupFactory is implemented:
|
|
28
27
|
# has_secrets_group = NautobotBoolIterator()
|
|
29
28
|
# secrets_group = factory.Maybe(
|
|
30
29
|
# "has_secrets_group",
|
|
@@ -41,7 +40,6 @@ class CloudResourceTypeFactory(PrimaryModelFactory):
|
|
|
41
40
|
name = factory.LazyAttributeSequence(lambda o, n: f"{o.provider.name} CloudResourceType {n + 1}")
|
|
42
41
|
has_description = NautobotBoolIterator()
|
|
43
42
|
description = factory.Maybe("has_description", factory.Faker("sentence"), "")
|
|
44
|
-
# TODO: if we add a `config_schema` here, then CloudNetworkFactory and CloudServiceFactory have to follow it...
|
|
45
43
|
|
|
46
44
|
@factory.post_generation
|
|
47
45
|
def content_types(self, create, extracted, **kwargs):
|
nautobot/cloud/filters.py
CHANGED
|
@@ -74,8 +74,6 @@ class CloudNetworkFilterSet(NautobotFilterSet):
|
|
|
74
74
|
filter_predicates={
|
|
75
75
|
"name": "icontains",
|
|
76
76
|
"description": "icontains",
|
|
77
|
-
"parent__name": "icontains",
|
|
78
|
-
"parent__description": "icontains",
|
|
79
77
|
"cloud_account__name": "icontains",
|
|
80
78
|
"cloud_account__description": "icontains",
|
|
81
79
|
"cloud_resource_type__name": "icontains",
|
|
@@ -98,7 +96,6 @@ class CloudNetworkFilterSet(NautobotFilterSet):
|
|
|
98
96
|
queryset=models.CloudNetwork.objects.all(),
|
|
99
97
|
label="Parent cloud network (name or ID)",
|
|
100
98
|
)
|
|
101
|
-
prefixes = django_filters.ModelMultipleChoiceFilter(queryset=Prefix.objects.all())
|
|
102
99
|
|
|
103
100
|
class Meta:
|
|
104
101
|
model = models.CloudNetwork
|
nautobot/cloud/forms.py
CHANGED
|
@@ -94,7 +94,6 @@ class CloudNetworkForm(NautobotModelForm):
|
|
|
94
94
|
)
|
|
95
95
|
parent = DynamicModelChoiceField(
|
|
96
96
|
queryset=CloudNetwork.objects.all(),
|
|
97
|
-
query_params={"parent__isnull": True},
|
|
98
97
|
required=False,
|
|
99
98
|
)
|
|
100
99
|
namespace = DynamicModelChoiceField(queryset=Namespace.objects.all(), required=False)
|
|
@@ -188,12 +187,7 @@ class CloudNetworkFilterForm(NautobotFilterForm):
|
|
|
188
187
|
cloud_account = DynamicModelMultipleChoiceField(
|
|
189
188
|
queryset=CloudAccount.objects.all(), to_field_name="name", required=False
|
|
190
189
|
)
|
|
191
|
-
parent = DynamicModelMultipleChoiceField(
|
|
192
|
-
queryset=CloudNetwork.objects.all(),
|
|
193
|
-
query_params={"parent__isnull": True},
|
|
194
|
-
to_field_name="name",
|
|
195
|
-
required=False,
|
|
196
|
-
)
|
|
190
|
+
parent = DynamicModelMultipleChoiceField(queryset=CloudNetwork.objects.all(), to_field_name="name", required=False)
|
|
197
191
|
tags = TagFilterField(model)
|
|
198
192
|
|
|
199
193
|
|
|
@@ -271,7 +271,7 @@ class Migration(migrations.Migration):
|
|
|
271
271
|
field=models.ForeignKey(
|
|
272
272
|
blank=True,
|
|
273
273
|
null=True,
|
|
274
|
-
on_delete=django.db.models.deletion.
|
|
274
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
275
275
|
related_name="children",
|
|
276
276
|
to="cloud.cloudnetwork",
|
|
277
277
|
),
|
nautobot/cloud/models.py
CHANGED
|
@@ -14,6 +14,7 @@ from nautobot.extras.utils import FeatureQuery, extras_features
|
|
|
14
14
|
@extras_features(
|
|
15
15
|
"custom_links",
|
|
16
16
|
"custom_validators",
|
|
17
|
+
"dynamic_groups",
|
|
17
18
|
"export_templates",
|
|
18
19
|
"graphql",
|
|
19
20
|
"webhooks",
|
|
@@ -136,7 +137,7 @@ class CloudNetwork(CloudResourceTypeMixin, PrimaryModel):
|
|
|
136
137
|
description = models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True)
|
|
137
138
|
cloud_account = models.ForeignKey(to=CloudAccount, on_delete=models.PROTECT, related_name="cloud_networks")
|
|
138
139
|
parent = models.ForeignKey(
|
|
139
|
-
to="cloud.CloudNetwork", on_delete=models.
|
|
140
|
+
to="cloud.CloudNetwork", on_delete=models.SET_NULL, blank=True, null=True, related_name="children"
|
|
140
141
|
)
|
|
141
142
|
prefixes = models.ManyToManyField(
|
|
142
143
|
blank=True,
|
nautobot/cloud/tables.py
CHANGED
|
@@ -7,8 +7,9 @@ from nautobot.core.tables import (
|
|
|
7
7
|
TagColumn,
|
|
8
8
|
ToggleColumn,
|
|
9
9
|
)
|
|
10
|
+
from nautobot.tenancy.tables import TenantColumn
|
|
10
11
|
|
|
11
|
-
from .models import CloudAccount, CloudNetwork, CloudResourceType, CloudService
|
|
12
|
+
from .models import CloudAccount, CloudNetwork, CloudNetworkPrefixAssignment, CloudResourceType, CloudService
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class CloudAccountTable(BaseTable):
|
|
@@ -94,6 +95,21 @@ class CloudNetworkTable(BaseTable):
|
|
|
94
95
|
)
|
|
95
96
|
|
|
96
97
|
|
|
98
|
+
class CloudNetworkPrefixAssignmentTable(BaseTable):
|
|
99
|
+
cloud_network = tables.Column(
|
|
100
|
+
verbose_name="Cloud Network",
|
|
101
|
+
linkify=lambda record: record.cloud_network.get_absolute_url(),
|
|
102
|
+
accessor="cloud_network.name",
|
|
103
|
+
)
|
|
104
|
+
prefix = tables.Column(linkify=True)
|
|
105
|
+
rd = tables.Column(accessor="vrf.rd", verbose_name="RD")
|
|
106
|
+
tenant = TenantColumn(accessor="vrf.tenant")
|
|
107
|
+
|
|
108
|
+
class Meta(BaseTable.Meta):
|
|
109
|
+
model = CloudNetworkPrefixAssignment
|
|
110
|
+
fields = ("cloud_network", "prefix", "rd", "tenant")
|
|
111
|
+
|
|
112
|
+
|
|
97
113
|
class CloudResourceTypeTable(BaseTable):
|
|
98
114
|
pk = ToggleColumn()
|
|
99
115
|
name = tables.Column(linkify=True)
|
|
@@ -100,7 +100,13 @@
|
|
|
100
100
|
</tr>
|
|
101
101
|
<tr>
|
|
102
102
|
<td>Parent</td>
|
|
103
|
-
<td>
|
|
103
|
+
<td>
|
|
104
|
+
{% if object.parent %}
|
|
105
|
+
{{ object.parent|hyperlinked_object }}
|
|
106
|
+
{% else %}
|
|
107
|
+
<span class="text-muted">—</span>
|
|
108
|
+
{% endif %}
|
|
109
|
+
</td>
|
|
104
110
|
</tr>
|
|
105
111
|
<tr>
|
|
106
112
|
<td>Description</td>
|
|
@@ -60,17 +60,6 @@
|
|
|
60
60
|
</div>
|
|
61
61
|
{% endblock content_left_page %}
|
|
62
62
|
|
|
63
|
-
{% block content_right_page %}
|
|
64
|
-
<div class="panel panel-default">
|
|
65
|
-
<div class="panel-heading">
|
|
66
|
-
<strong>Config Schema</strong>
|
|
67
|
-
</div>
|
|
68
|
-
<div class="panel-body">
|
|
69
|
-
<pre>{{ object.config_schema|render_json }}</pre>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
72
|
-
{% endblock content_right_page %}
|
|
73
|
-
|
|
74
63
|
{% block extra_tab_content %}
|
|
75
64
|
{% if networks_count %}
|
|
76
65
|
<div id="networks" role="tabpanel" class="tab-pane {% if not active_tab and not request.GET.tab or request.GET.tab == "networks" %}active{% else %}fade{% endif %}">
|
|
@@ -65,18 +65,6 @@ class CloudNetworkTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
65
65
|
("parent", "parent__id"),
|
|
66
66
|
("parent", "parent__name"),
|
|
67
67
|
]
|
|
68
|
-
exclude_q_filter_predicates = [
|
|
69
|
-
"parent__name",
|
|
70
|
-
"parent__description",
|
|
71
|
-
]
|
|
72
|
-
|
|
73
|
-
def _get_relevant_filterset_queryset(self, queryset, *filter_params):
|
|
74
|
-
queryset = super()._get_relevant_filterset_queryset(queryset, *filter_params)
|
|
75
|
-
if "name" in filter_params or "description" in filter_params:
|
|
76
|
-
# Only select an instance with no children as otherwise the search will also match the children,
|
|
77
|
-
# due to `parent__name` and `parent__description` also being search parameters
|
|
78
|
-
queryset = queryset.filter(children__isnull=True)
|
|
79
|
-
return queryset
|
|
80
68
|
|
|
81
69
|
|
|
82
70
|
class CloudNetworkPrefixAssignmentTestCase(FilterTestCases.FilterTestCase):
|
nautobot/core/filters.py
CHANGED
|
@@ -6,11 +6,9 @@ from django import forms as django_forms
|
|
|
6
6
|
from django.conf import settings
|
|
7
7
|
from django.db import models
|
|
8
8
|
from django.forms.utils import ErrorDict, ErrorList
|
|
9
|
-
from django.utils.encoding import force_str
|
|
10
|
-
from django.utils.text import capfirst
|
|
11
9
|
import django_filters
|
|
12
10
|
from django_filters.constants import EMPTY_VALUES
|
|
13
|
-
from django_filters.utils import get_model_field,
|
|
11
|
+
from django_filters.utils import get_model_field, resolve_field
|
|
14
12
|
from drf_spectacular.types import OpenApiTypes
|
|
15
13
|
from drf_spectacular.utils import extend_schema_field
|
|
16
14
|
|
|
@@ -722,18 +720,6 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
722
720
|
# Of course setting the negation of the existing filter's exclude attribute handles both cases
|
|
723
721
|
new_filter.exclude = not filter_field.exclude
|
|
724
722
|
|
|
725
|
-
# If the base filter_field has a custom label, django_filters won't adjust it for the new_filter lookup,
|
|
726
|
-
# so we have to do it.
|
|
727
|
-
if filter_field.label and filter_field.label != label_for_filter(
|
|
728
|
-
cls.Meta.model, filter_field.field_name, filter_field.lookup_expr, filter_field.exclude
|
|
729
|
-
):
|
|
730
|
-
# Lightly adjusted from label_for_filter() implementation:
|
|
731
|
-
verbose_expression = ["exclude", filter_field.label] if new_filter.exclude else [filter_field.label]
|
|
732
|
-
if isinstance(lookup_expr, str):
|
|
733
|
-
verbose_expression.append(verbose_lookup_expr(lookup_expr))
|
|
734
|
-
verbose_expression = [force_str(part) for part in verbose_expression if part]
|
|
735
|
-
new_filter.label = capfirst(" ".join(verbose_expression))
|
|
736
|
-
|
|
737
723
|
magic_filters[new_filter_name] = new_filter
|
|
738
724
|
|
|
739
725
|
return magic_filters
|
nautobot/core/forms/forms.py
CHANGED
|
@@ -59,13 +59,6 @@ class AddressFieldMixin(forms.ModelForm):
|
|
|
59
59
|
class BootstrapMixin(forms.BaseForm):
|
|
60
60
|
"""
|
|
61
61
|
Add the base Bootstrap CSS classes to form elements.
|
|
62
|
-
|
|
63
|
-
Note that this only applies to form fields that are:
|
|
64
|
-
|
|
65
|
-
1. statically defined on the form class at declaration time, or
|
|
66
|
-
2. dynamically added to the form at init time by a class **later in the MRO than this mixin**.
|
|
67
|
-
|
|
68
|
-
If a class earlier in the MRO adds its own fields, it will have to ensure that the widgets are correctly configured.
|
|
69
62
|
"""
|
|
70
63
|
|
|
71
64
|
def __init__(self, *args, **kwargs):
|
|
@@ -80,9 +73,8 @@ class BootstrapMixin(forms.BaseForm):
|
|
|
80
73
|
|
|
81
74
|
for field in self.fields.values():
|
|
82
75
|
if field.widget.__class__ not in exempt_widgets:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
field.widget.attrs["class"] = " ".join([css_classes, "form-control"]).strip()
|
|
76
|
+
css = field.widget.attrs.get("class", "")
|
|
77
|
+
field.widget.attrs["class"] = " ".join([css, "form-control"]).strip()
|
|
86
78
|
if field.required and not isinstance(field.widget, forms.FileInput):
|
|
87
79
|
field.widget.attrs["required"] = "required"
|
|
88
80
|
if "placeholder" not in field.widget.attrs:
|
|
@@ -64,8 +64,8 @@ def generate_filter_resolver(schema_type, resolver_name, field_name):
|
|
|
64
64
|
"""
|
|
65
65
|
filterset_class = schema_type._meta.filterset_class
|
|
66
66
|
|
|
67
|
-
def resolve_filter(self,
|
|
68
|
-
if not filterset_class
|
|
67
|
+
def resolve_filter(self, *args, **kwargs):
|
|
68
|
+
if not filterset_class:
|
|
69
69
|
return getattr(self, field_name).all()
|
|
70
70
|
|
|
71
71
|
# Inverse of substitution logic from get_filtering_args_from_filterset() - transform "_type" back to "type"
|
nautobot/core/graphql/schema.py
CHANGED
|
@@ -4,7 +4,6 @@ from collections import OrderedDict
|
|
|
4
4
|
import logging
|
|
5
5
|
|
|
6
6
|
from django.conf import settings
|
|
7
|
-
from django.contrib.contenttypes.fields import GenericRelation
|
|
8
7
|
from django.contrib.contenttypes.models import ContentType
|
|
9
8
|
from django.core.validators import ValidationError
|
|
10
9
|
from django.db.models import ManyToManyField
|
|
@@ -206,7 +205,8 @@ def extend_schema_type_filter(schema_type, model):
|
|
|
206
205
|
(DjangoObjectType): The extended schema_type object
|
|
207
206
|
"""
|
|
208
207
|
for field in model._meta.get_fields():
|
|
209
|
-
|
|
208
|
+
# Check whether attribute is a ManyToOne or ManyToMany field
|
|
209
|
+
if not isinstance(field, (ManyToManyField, ManyToManyRel, ManyToOneRel)):
|
|
210
210
|
continue
|
|
211
211
|
# OneToOneRel is a subclass of ManyToOneRel, but we don't want to treat it as a list
|
|
212
212
|
if isinstance(field, OneToOneRel):
|
|
@@ -374,9 +374,16 @@ def extend_schema_type_config_context(schema_type, model):
|
|
|
374
374
|
|
|
375
375
|
def extend_schema_type_global_features(schema_type, model):
|
|
376
376
|
"""
|
|
377
|
-
Extend schema_type object to have attributes and resolvers for global features (dynamic groups, etc.).
|
|
377
|
+
Extend schema_type object to have attributes and resolvers for global features (contacts, dynamic groups, etc.).
|
|
378
378
|
"""
|
|
379
|
-
|
|
379
|
+
if getattr(model, "is_contact_associable_model", False):
|
|
380
|
+
|
|
381
|
+
def resolve_associated_contacts(self, args):
|
|
382
|
+
return self.associated_contacts.all()
|
|
383
|
+
|
|
384
|
+
setattr(schema_type, "resolve_associated_contacts", resolve_associated_contacts)
|
|
385
|
+
schema_type._meta.fields["associated_contacts"] = graphene.Field.mounted(graphene.List(ContactAssociationType))
|
|
386
|
+
|
|
380
387
|
if getattr(model, "is_dynamic_group_associable_model", False):
|
|
381
388
|
|
|
382
389
|
def resolve_dynamic_groups(self, args):
|
|
@@ -392,9 +399,10 @@ def extend_schema_type_relationships(schema_type, model):
|
|
|
392
399
|
"""Extend the schema type with attributes and resolvers corresponding
|
|
393
400
|
to the relationships associated with this model."""
|
|
394
401
|
|
|
402
|
+
ct = ContentType.objects.get_for_model(model)
|
|
395
403
|
relationships_by_side = {
|
|
396
|
-
"source": Relationship.objects.
|
|
397
|
-
"destination": Relationship.objects.
|
|
404
|
+
"source": Relationship.objects.filter(source_type=ct),
|
|
405
|
+
"destination": Relationship.objects.filter(destination_type=ct),
|
|
398
406
|
}
|
|
399
407
|
|
|
400
408
|
prefix = ""
|
nautobot/core/jobs/__init__.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import codecs
|
|
2
1
|
import contextlib
|
|
3
2
|
from io import BytesIO
|
|
4
3
|
|
|
@@ -297,9 +296,7 @@ class ImportObjects(Job):
|
|
|
297
296
|
if not csv_data and not csv_file:
|
|
298
297
|
raise RunJobTaskFailed("Either csv_data or csv_file must be provided")
|
|
299
298
|
if csv_file:
|
|
300
|
-
|
|
301
|
-
# Bytes read from the original file are decoded according to file_encoding, and the result is encoded using data_encoding.
|
|
302
|
-
csv_bytes = codecs.EncodedFile(csv_file, "utf-8", "utf-8-sig")
|
|
299
|
+
csv_bytes = csv_file
|
|
303
300
|
else:
|
|
304
301
|
csv_bytes = BytesIO(csv_data.encode("utf-8"))
|
|
305
302
|
|
|
@@ -329,8 +329,6 @@ class Command(BaseCommand):
|
|
|
329
329
|
)
|
|
330
330
|
_create_batch(MetadataChoiceFactory, 100)
|
|
331
331
|
_create_batch(ObjectChangeFactory, 100)
|
|
332
|
-
_create_batch(JobResultFactory, 20)
|
|
333
|
-
_create_batch(JobLogEntryFactory, 100)
|
|
334
332
|
_create_batch(ObjectMetadataFactory, 100)
|
|
335
333
|
_create_batch(
|
|
336
334
|
ObjectMetadataFactory,
|
|
@@ -346,6 +344,8 @@ class Command(BaseCommand):
|
|
|
346
344
|
has_contact=False,
|
|
347
345
|
description="with teams",
|
|
348
346
|
)
|
|
347
|
+
_create_batch(JobResultFactory, 20)
|
|
348
|
+
_create_batch(JobLogEntryFactory, 100)
|
|
349
349
|
|
|
350
350
|
def handle(self, *args, **options):
|
|
351
351
|
if options["flush"]:
|
nautobot/core/models/__init__.py
CHANGED
|
@@ -54,11 +54,11 @@ class BaseModel(models.Model):
|
|
|
54
54
|
is_saved_view_model = False # SavedViewMixin overrides this to default True
|
|
55
55
|
is_cloud_resource_type_model = False # CloudResourceTypeMixin overrides this to default True
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
associated_object_metadatas = GenericRelation(
|
|
58
58
|
"extras.ObjectMetadata",
|
|
59
59
|
content_type_field="assigned_object_type",
|
|
60
60
|
object_id_field="assigned_object_id",
|
|
61
|
-
related_query_name="
|
|
61
|
+
related_query_name="associated_object_metadatas_%(app_label)s_%(class)s", # e.g. 'associated_object_metadatas_dcim_device'
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
class Meta:
|
nautobot/core/settings.py
CHANGED
|
@@ -892,24 +892,13 @@ CELERY_TASK_TRACK_STARTED = True
|
|
|
892
892
|
# If enabled, a `task-sent` event will be sent for every task so tasks can be tracked before they're consumed by a worker.
|
|
893
893
|
CELERY_TASK_SEND_SENT_EVENT = True
|
|
894
894
|
|
|
895
|
-
# How many tasks a worker is allowed to reserve for its own consumption and execution.
|
|
896
|
-
# If set to zero (not recommended) a single worker can reserve all tasks even if other workers are free.
|
|
897
|
-
# For short running tasks (such as webhooks) you may want to set this to a larger number to increase throughput.
|
|
898
|
-
# Conversely, for long running tasks (such as SSoT or Golden-Config Jobs at scale) you may want to set this to 1
|
|
899
|
-
# so that a worker executing a long-running task will not prefetch other tasks, which would block their execution
|
|
900
|
-
# until the long-running task completes.
|
|
901
|
-
# https://docs.celeryq.dev/en/stable/userguide/optimizing.html#prefetch-limits
|
|
902
|
-
CELERY_WORKER_PREFETCH_MULTIPLIER = int(os.getenv("NAUTOBOT_CELERY_WORKER_PREFETCH_MULTIPLIER", "4"))
|
|
903
|
-
|
|
904
895
|
# If enabled stdout and stderr of running jobs will be redirected to the task logger.
|
|
905
896
|
CELERY_WORKER_REDIRECT_STDOUTS = is_truthy(os.getenv("NAUTOBOT_CELERY_WORKER_REDIRECT_STDOUTS", "True"))
|
|
906
897
|
|
|
907
|
-
# The log level of log messages generated by redirected job stdout and stderr.
|
|
908
|
-
# Can be one of `DEBUG`, `INFO`, `WARNING`, `ERROR`, or `CRITICAL`.
|
|
898
|
+
# The log level of log messages generated by redirected job stdout and stderr. Can be one of `DEBUG`, `INFO`, `WARNING`, `ERROR`, or `CRITICAL`.
|
|
909
899
|
CELERY_WORKER_REDIRECT_STDOUTS_LEVEL = os.getenv("NAUTOBOT_CELERY_WORKER_REDIRECT_STDOUTS_LEVEL", "WARNING")
|
|
910
900
|
|
|
911
|
-
# Send task-related events so that tasks can be monitored using tools like flower.
|
|
912
|
-
# Sets the default value for the workers -E argument.
|
|
901
|
+
# Send task-related events so that tasks can be monitored using tools like flower. Sets the default value for the workers -E argument.
|
|
913
902
|
CELERY_WORKER_SEND_TASK_EVENTS = True
|
|
914
903
|
|
|
915
904
|
# Default celery queue name that will be used by workers and tasks if no queue is specified
|
nautobot/core/settings.yaml
CHANGED
|
@@ -426,20 +426,6 @@ properties:
|
|
|
426
426
|
see_also:
|
|
427
427
|
"`CELERY_TASK_SOFT_TIME_LIMIT`": "#celery_task_soft_time_limit"
|
|
428
428
|
type: "integer"
|
|
429
|
-
CELERY_WORKER_PREFETCH_MULTIPLIER:
|
|
430
|
-
default: 4
|
|
431
|
-
description: "How many tasks a worker is allowed to reserve for its own consumption and execution."
|
|
432
|
-
details: >-
|
|
433
|
-
If set to `0` (not recommended) a single worker can reserve all tasks even if other workers are free.
|
|
434
|
-
For short running tasks (such as webhooks) you may want to set this to a larger number to increase throughput.
|
|
435
|
-
Conversely, for long-running tasks (such as SSoT or Golden-Config Jobs at scale) you may want to set this to `1`
|
|
436
|
-
so that a worker executing a long-running task will not prefetch other tasks, which would block their execution
|
|
437
|
-
until the long-running task completes.
|
|
438
|
-
environment_variable: "NAUTOBOT_CELERY_WORKER_PREFETCH_MULTIPLIER"
|
|
439
|
-
see_also:
|
|
440
|
-
"Celery documentation": "https://docs.celeryq.dev/en/stable/userguide/optimizing.html#prefetch-limits"
|
|
441
|
-
type: "integer"
|
|
442
|
-
version_added: "2.2.9"
|
|
443
429
|
CELERY_WORKER_PROMETHEUS_PORTS:
|
|
444
430
|
default: []
|
|
445
431
|
description: "Ports for Prometheus metric HTTP server running on the celery worker(s)."
|
|
@@ -482,8 +468,8 @@ properties:
|
|
|
482
468
|
If enabling indefinite changelog retention, it is recommended to periodically delete old entries.
|
|
483
469
|
Otherwise, the database may eventually exceed capacity.
|
|
484
470
|
|
|
485
|
-
+/- 2.
|
|
486
|
-
As of Nautobot 2.
|
|
471
|
+
+/- 2.2.0
|
|
472
|
+
As of Nautobot 2.2.0, changelog cleanup does not run automatically. Use the `Cleanup of ObjectChange records`
|
|
487
473
|
system Job to handle changelog cleanup; you may schedule this to run automatically like any other Job if
|
|
488
474
|
desired. The `CHANGELOG_RETENTION` setting provides a default age cutoff for the Job but may be overridden
|
|
489
475
|
at runtime if desired.
|
nautobot/core/tables.py
CHANGED
|
@@ -155,9 +155,6 @@ class BaseTable(django_tables2.Table):
|
|
|
155
155
|
continue
|
|
156
156
|
if isinstance(column.column, LinkedCountColumn):
|
|
157
157
|
column_model = lookup.get_model_for_view_name(column.column.viewname)
|
|
158
|
-
if column_model is None:
|
|
159
|
-
logger.error("Couldn't find model for %s", column.column.viewname)
|
|
160
|
-
continue
|
|
161
158
|
reverse_lookup = column.column.reverse_lookup or next(iter(column.column.url_params.keys()))
|
|
162
159
|
count_fields.append((column.name, column_model, reverse_lookup))
|
|
163
160
|
continue
|
|
@@ -106,10 +106,10 @@
|
|
|
106
106
|
{% endwith %}
|
|
107
107
|
{% endif %}
|
|
108
108
|
{% if object.is_metadata_associable_model and perms.extras.view_objectmetadata %}
|
|
109
|
-
{% with object.
|
|
109
|
+
{% with object.associated_object_metadatas.count as om_count %}
|
|
110
110
|
{% if om_count %}
|
|
111
|
-
<li role="presentation"{% if request.GET.tab == '
|
|
112
|
-
<a href="{{ object.get_absolute_url }}#
|
|
111
|
+
<li role="presentation"{% if request.GET.tab == 'object_metadatas' %} class="active"{% endif %}>
|
|
112
|
+
<a href="{{ object.get_absolute_url }}#object_metadatas" onclick="switch_tab(this.href)" aria-controls="object_metadatas" role="tab" data-toggle="tab">
|
|
113
113
|
Object Metadata {% badge om_count %}
|
|
114
114
|
</a>
|
|
115
115
|
</li>
|
|
@@ -246,7 +246,7 @@
|
|
|
246
246
|
</div>
|
|
247
247
|
{% endif %}
|
|
248
248
|
{% if object.is_metadata_associable_model and perms.extras.view_objectmetadata %}
|
|
249
|
-
<div id="
|
|
249
|
+
<div id="object_metadatas" role="tabpanel" class="tab-pane {% if request.GET.tab == 'object_metadatas' %}active{% else %}fade{% endif %}">
|
|
250
250
|
<div class="row">
|
|
251
251
|
<div class="col-md-12">
|
|
252
252
|
<form method="post">
|
|
@@ -259,7 +259,7 @@
|
|
|
259
259
|
</div>
|
|
260
260
|
</div>
|
|
261
261
|
<div class="table-responsive">
|
|
262
|
-
{% render_table
|
|
262
|
+
{% render_table associated_object_metadatas_table 'inc/table.html' %}
|
|
263
263
|
</div>
|
|
264
264
|
</div>
|
|
265
265
|
</form>
|
|
@@ -295,15 +295,6 @@ SECRET_KEY = os.getenv("NAUTOBOT_SECRET_KEY", "{{ secret_key }}")
|
|
|
295
295
|
# CELERY_TASK_SOFT_TIME_LIMIT = int(os.getenv("NAUTOBOT_CELERY_TASK_SOFT_TIME_LIMIT", str(5 * 60)))
|
|
296
296
|
# CELERY_TASK_TIME_LIMIT = int(os.getenv("NAUTOBOT_CELERY_TASK_TIME_LIMIT", str(10 * 60)))
|
|
297
297
|
|
|
298
|
-
# How many tasks a worker is allowed to reserve for its own consumption and execution.
|
|
299
|
-
# If set to zero (not recommended) a single worker can reserve all tasks even if other workers are free.
|
|
300
|
-
# For short running tasks (such as webhooks) you may want to set this to a larger number to increase throughput.
|
|
301
|
-
# Conversely, for long running tasks (such as SSoT or Golden-Config Jobs at scale) you may want to set this to 1
|
|
302
|
-
# so that a worker executing a long-running task will not prefetch other tasks, which would block their execution
|
|
303
|
-
# until the long-running task completes.
|
|
304
|
-
# https://docs.celeryq.dev/en/stable/userguide/optimizing.html#prefetch-limits
|
|
305
|
-
# CELERY_WORKER_PREFETCH_MULTIPLIER = int(os.getenv("NAUTOBOT_CELERY_WORKER_PREFETCH_MULTIPLIER", "4"))
|
|
306
|
-
|
|
307
298
|
# Ports for prometheus metric HTTP server running on the celery worker.
|
|
308
299
|
# Normally this should be set to a single port, unless you have multiple workers running on a single machine, i.e.
|
|
309
300
|
# sharing the same available ports. In that case you need to specify a range of ports greater than or equal to the
|
|
@@ -316,12 +307,6 @@ SECRET_KEY = os.getenv("NAUTOBOT_SECRET_KEY", "{{ secret_key }}")
|
|
|
316
307
|
# int(value) for value in os.getenv("NAUTOBOT_CELERY_WORKER_PROMETHEUS_PORTS").split(",")
|
|
317
308
|
# ]
|
|
318
309
|
|
|
319
|
-
# If enabled stdout and stderr of running jobs will be redirected to the task logger.
|
|
320
|
-
# CELERY_WORKER_REDIRECT_STDOUTS = is_truthy(os.getenv("NAUTOBOT_CELERY_WORKER_REDIRECT_STDOUTS", "True"))
|
|
321
|
-
|
|
322
|
-
# The log level of log messages generated by redirected job stdout and stderr.
|
|
323
|
-
# Can be one of `DEBUG`, `INFO`, `WARNING`, `ERROR`, or `CRITICAL`.
|
|
324
|
-
# CELERY_WORKER_REDIRECT_STDOUTS_LEVEL = os.getenv("NAUTOBOT_CELERY_WORKER_REDIRECT_STDOUTS_LEVEL", "WARNING")
|
|
325
310
|
|
|
326
311
|
# Number of days to retain changelog entries. Set to 0 to retain changes indefinitely. Defaults to 90 if not set here.
|
|
327
312
|
#
|
nautobot/core/testing/filters.py
CHANGED
|
@@ -132,17 +132,6 @@ class FilterTestCases:
|
|
|
132
132
|
if generic_filter_test not in self.generic_filter_tests:
|
|
133
133
|
self.generic_filter_tests = (*self.generic_filter_tests, generic_filter_test)
|
|
134
134
|
|
|
135
|
-
# Make sure we have at least 3 contacts and 3 teams in the database
|
|
136
|
-
if Contact.objects.count() < 3:
|
|
137
|
-
Contact.objects.create(name="Generic Filter Test Contact 1")
|
|
138
|
-
Contact.objects.create(name="Generic Filter Test Contact 2")
|
|
139
|
-
Contact.objects.create(name="Generic Filter Test Contact 3")
|
|
140
|
-
|
|
141
|
-
if Team.objects.count() < 3:
|
|
142
|
-
Team.objects.create(name="Generic Filter Test Team 1")
|
|
143
|
-
Team.objects.create(name="Generic Filter Test Team 2")
|
|
144
|
-
Team.objects.create(name="Generic Filter Test Team 3")
|
|
145
|
-
|
|
146
135
|
# Make sure we have some valid contact-associations:
|
|
147
136
|
for contact, team, instance in zip(Contact.objects.all()[:3], Team.objects.all()[:3], self.queryset):
|
|
148
137
|
ContactAssociation.objects.create(
|
|
@@ -283,7 +272,7 @@ class FilterTestCases:
|
|
|
283
272
|
# if lookup_method is iexact use the full updated attr
|
|
284
273
|
if lookup_method == "iexact":
|
|
285
274
|
lookup = randomized_attr_value.upper()
|
|
286
|
-
model_queryset = self.queryset.filter(**{f"{filter_field_name}
|
|
275
|
+
model_queryset = self.queryset.filter(**{f"{filter_field_name}": lookup})
|
|
287
276
|
else:
|
|
288
277
|
lookup = randomized_attr_value[1:].upper()
|
|
289
278
|
model_queryset = self.queryset.filter(**{f"{filter_field_name}__icontains": lookup})
|
nautobot/core/tests/test_jobs.py
CHANGED
|
@@ -3,27 +3,24 @@ from pathlib import Path
|
|
|
3
3
|
|
|
4
4
|
from django.contrib.contenttypes.models import ContentType
|
|
5
5
|
from django.core.cache import cache
|
|
6
|
-
from django.core.files.base import ContentFile
|
|
7
6
|
from django.utils import timezone
|
|
8
7
|
import yaml
|
|
9
8
|
|
|
10
9
|
from nautobot.core.jobs.cleanup import CleanupTypes
|
|
11
10
|
from nautobot.core.testing import create_job_result_and_run_job, TransactionTestCase
|
|
12
|
-
from nautobot.dcim.models import
|
|
11
|
+
from nautobot.dcim.models import DeviceType, Location, LocationType, Manufacturer
|
|
13
12
|
from nautobot.extras.choices import JobResultStatusChoices, LogLevelChoices
|
|
14
13
|
from nautobot.extras.factory import JobResultFactory, ObjectChangeFactory
|
|
15
14
|
from nautobot.extras.models import (
|
|
16
15
|
Contact,
|
|
17
16
|
ContactAssociation,
|
|
18
17
|
ExportTemplate,
|
|
19
|
-
FileProxy,
|
|
20
18
|
JobLogEntry,
|
|
21
19
|
JobResult,
|
|
22
20
|
ObjectChange,
|
|
23
21
|
Role,
|
|
24
22
|
Status,
|
|
25
23
|
)
|
|
26
|
-
from nautobot.ipam.models import Prefix
|
|
27
24
|
from nautobot.users.models import ObjectPermission
|
|
28
25
|
|
|
29
26
|
|
|
@@ -221,76 +218,6 @@ class ImportObjectsTestCase(TransactionTestCase):
|
|
|
221
218
|
)
|
|
222
219
|
self.assertEqual(4, Status.objects.filter(name__startswith="test_status").count())
|
|
223
220
|
|
|
224
|
-
def test_csv_import_with_utf_8_with_bom_encoding(self):
|
|
225
|
-
"""
|
|
226
|
-
A superuser running the job with a .csv file with utf_8 with bom encoding should successfully create all specified objects.
|
|
227
|
-
Test for bug fix https://github.com/nautobot/nautobot/issues/5812 and https://github.com/nautobot/nautobot/issues/5985
|
|
228
|
-
"""
|
|
229
|
-
|
|
230
|
-
status = Status.objects.get(name="Active").pk
|
|
231
|
-
content = f"prefix,status\n192.168.1.1/32,{status}"
|
|
232
|
-
content = content.encode("utf-8-sig")
|
|
233
|
-
filename = "test.csv"
|
|
234
|
-
csv_file = FileProxy.objects.create(name=filename, file=ContentFile(content, name=filename))
|
|
235
|
-
job_result = create_job_result_and_run_job(
|
|
236
|
-
"nautobot.core.jobs",
|
|
237
|
-
"ImportObjects",
|
|
238
|
-
content_type=ContentType.objects.get_for_model(Prefix).pk,
|
|
239
|
-
csv_file=csv_file.id,
|
|
240
|
-
)
|
|
241
|
-
self.assertEqual(job_result.status, JobResultStatusChoices.STATUS_SUCCESS)
|
|
242
|
-
self.assertFalse(
|
|
243
|
-
JobLogEntry.objects.filter(job_result=job_result, log_level=LogLevelChoices.LOG_WARNING).exists()
|
|
244
|
-
)
|
|
245
|
-
self.assertFalse(
|
|
246
|
-
JobLogEntry.objects.filter(job_result=job_result, log_level=LogLevelChoices.LOG_ERROR).exists()
|
|
247
|
-
)
|
|
248
|
-
self.assertEqual(
|
|
249
|
-
1, Prefix.objects.filter(status=Status.objects.get(name="Active"), prefix="192.168.1.1/32").count()
|
|
250
|
-
)
|
|
251
|
-
mfr = Manufacturer.objects.create(name="Test Cisco Manufacturer")
|
|
252
|
-
device_type = DeviceType.objects.create(
|
|
253
|
-
manufacturer=mfr,
|
|
254
|
-
model="Cisco CSR1000v",
|
|
255
|
-
u_height=0,
|
|
256
|
-
)
|
|
257
|
-
location_type = LocationType.objects.create(name="Test Location Type")
|
|
258
|
-
location_type.content_types.set([ContentType.objects.get_for_model(Device)])
|
|
259
|
-
location = Location.objects.create(
|
|
260
|
-
name="Device Location",
|
|
261
|
-
location_type=location_type,
|
|
262
|
-
status=Status.objects.get_for_model(Location).first(),
|
|
263
|
-
)
|
|
264
|
-
role = Role.objects.create(name="Device Status")
|
|
265
|
-
role.content_types.set([ContentType.objects.get_for_model(Device)])
|
|
266
|
-
content = "\n".join(
|
|
267
|
-
[
|
|
268
|
-
"serial,asset_tag,device_type,location,status,name,role",
|
|
269
|
-
f"1021C4,CA211,{device_type.pk},{location.pk},{status},Test-AC-01,{role}",
|
|
270
|
-
f"1021C5,CA212,{device_type.pk},{location.pk},{status},Test-AC-02,{role}",
|
|
271
|
-
]
|
|
272
|
-
)
|
|
273
|
-
content = content.encode("utf-8-sig")
|
|
274
|
-
filename = "test.csv"
|
|
275
|
-
csv_file = FileProxy.objects.create(name=filename, file=ContentFile(content, name=filename))
|
|
276
|
-
job_result = create_job_result_and_run_job(
|
|
277
|
-
"nautobot.core.jobs",
|
|
278
|
-
"ImportObjects",
|
|
279
|
-
content_type=ContentType.objects.get_for_model(Device).pk,
|
|
280
|
-
csv_file=csv_file.id,
|
|
281
|
-
)
|
|
282
|
-
self.assertEqual(job_result.status, JobResultStatusChoices.STATUS_SUCCESS)
|
|
283
|
-
self.assertFalse(
|
|
284
|
-
JobLogEntry.objects.filter(job_result=job_result, log_level=LogLevelChoices.LOG_WARNING).exists()
|
|
285
|
-
)
|
|
286
|
-
self.assertFalse(
|
|
287
|
-
JobLogEntry.objects.filter(job_result=job_result, log_level=LogLevelChoices.LOG_ERROR).exists()
|
|
288
|
-
)
|
|
289
|
-
device_1 = Device.objects.get(name="Test-AC-01")
|
|
290
|
-
device_2 = Device.objects.get(name="Test-AC-02")
|
|
291
|
-
self.assertEqual(device_1.serial, "1021C4")
|
|
292
|
-
self.assertEqual(device_2.serial, "1021C5")
|
|
293
|
-
|
|
294
221
|
def test_csv_import_bad_row(self):
|
|
295
222
|
"""A row of incorrect data should fail validation for that object but import all others successfully if `roll_back_if_error` is False."""
|
|
296
223
|
csv_data = self.csv_data.split("\n")
|