nautobot 2.4.0b1__py3-none-any.whl → 2.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/apps/__init__.py +1 -1
- nautobot/apps/api.py +8 -8
- nautobot/apps/change_logging.py +2 -2
- nautobot/apps/choices.py +4 -4
- nautobot/apps/events.py +3 -3
- nautobot/apps/factory.py +2 -2
- nautobot/apps/filters.py +1 -1
- nautobot/apps/forms.py +20 -20
- nautobot/apps/graphql.py +2 -2
- nautobot/apps/jobs.py +8 -8
- nautobot/apps/models.py +19 -19
- nautobot/apps/tables.py +1 -1
- nautobot/apps/testing.py +10 -10
- nautobot/apps/ui.py +2 -2
- nautobot/apps/utils.py +7 -7
- nautobot/apps/views.py +7 -7
- nautobot/circuits/api/serializers.py +1 -0
- nautobot/circuits/api/views.py +4 -8
- nautobot/circuits/tables.py +2 -1
- nautobot/circuits/templates/circuits/circuit_create.html +1 -7
- nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +43 -0
- nautobot/circuits/tests/integration/test_relationships.py +1 -1
- nautobot/circuits/views.py +3 -3
- nautobot/cloud/api/views.py +6 -10
- nautobot/cloud/models.py +1 -1
- nautobot/cloud/views.py +0 -16
- nautobot/core/api/constants.py +11 -0
- nautobot/core/api/fields.py +5 -5
- nautobot/core/api/filter_backends.py +3 -9
- nautobot/core/api/schema.py +13 -2
- nautobot/core/api/serializers.py +40 -34
- nautobot/core/api/views.py +56 -4
- nautobot/core/apps/__init__.py +0 -5
- nautobot/core/celery/log.py +4 -4
- nautobot/core/celery/schedulers.py +2 -2
- nautobot/core/choices.py +2 -2
- nautobot/core/events/__init__.py +3 -3
- nautobot/core/filters.py +67 -35
- nautobot/core/forms/__init__.py +19 -19
- nautobot/core/forms/fields.py +14 -11
- nautobot/core/forms/forms.py +33 -2
- nautobot/core/graphql/types.py +1 -1
- nautobot/core/jobs/__init__.py +28 -7
- nautobot/core/jobs/bulk_actions.py +285 -0
- nautobot/core/jobs/cleanup.py +48 -12
- nautobot/core/jobs/groups.py +1 -1
- nautobot/core/management/commands/validate_models.py +1 -1
- nautobot/core/models/__init__.py +3 -1
- nautobot/core/models/query_functions.py +2 -2
- nautobot/core/models/tree_queries.py +6 -3
- nautobot/core/settings.py +29 -2
- nautobot/core/settings.yaml +21 -0
- nautobot/core/tables.py +79 -61
- nautobot/core/templates/about.html +67 -0
- nautobot/core/templates/generic/object_bulk_destroy.html +1 -1
- nautobot/core/templates/inc/media.html +3 -0
- nautobot/core/templates/inc/nav_menu.html +1 -0
- nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
- nautobot/core/templates/inc/tenant_table_row.html +11 -0
- nautobot/core/templates/nautobot_config.py.j2 +13 -0
- nautobot/core/templates/search.html +7 -0
- nautobot/core/templates/utilities/render_jinja2.html +1 -1
- nautobot/core/templates/utilities/templatetags/tag.html +1 -1
- nautobot/core/templates/utilities/theme_preview.html +7 -0
- nautobot/core/templatetags/helpers.py +11 -2
- nautobot/core/testing/__init__.py +8 -8
- nautobot/core/testing/api.py +170 -15
- nautobot/core/testing/filters.py +45 -10
- nautobot/core/testing/forms.py +2 -0
- nautobot/core/testing/integration.py +514 -5
- nautobot/core/testing/mixins.py +7 -2
- nautobot/core/testing/views.py +44 -29
- nautobot/core/tests/integration/test_app_home.py +0 -1
- nautobot/core/tests/integration/test_app_navbar.py +0 -1
- nautobot/core/tests/integration/test_filters.py +0 -2
- nautobot/core/tests/integration/test_home.py +0 -1
- nautobot/core/tests/integration/test_navbar.py +0 -1
- nautobot/core/tests/integration/test_view_authentication.py +1 -0
- nautobot/core/tests/runner.py +1 -1
- nautobot/core/tests/test_api.py +98 -1
- nautobot/core/tests/test_csv.py +25 -3
- nautobot/core/tests/test_filters.py +209 -246
- nautobot/core/tests/test_forms.py +1 -0
- nautobot/core/tests/test_jobs.py +492 -1
- nautobot/core/tests/test_models.py +9 -0
- nautobot/core/tests/test_settings_schema.py +7 -0
- nautobot/core/tests/test_tables.py +100 -0
- nautobot/core/tests/test_utils.py +63 -1
- nautobot/core/tests/test_views.py +30 -3
- nautobot/core/ui/nav.py +1 -0
- nautobot/core/ui/object_detail.py +15 -1
- nautobot/core/urls.py +11 -0
- nautobot/core/utils/git.py +7 -2
- nautobot/core/utils/lookup.py +11 -8
- nautobot/core/utils/querysets.py +64 -0
- nautobot/core/utils/requests.py +24 -9
- nautobot/core/views/__init__.py +42 -0
- nautobot/core/views/generic.py +131 -197
- nautobot/core/views/mixins.py +136 -41
- nautobot/core/views/renderers.py +6 -6
- nautobot/core/views/utils.py +2 -2
- nautobot/dcim/api/serializers.py +56 -64
- nautobot/dcim/api/views.py +47 -113
- nautobot/dcim/constants.py +6 -13
- nautobot/dcim/factory.py +6 -1
- nautobot/dcim/filters/__init__.py +31 -2
- nautobot/dcim/forms.py +48 -17
- nautobot/dcim/graphql/types.py +2 -2
- nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
- nautobot/dcim/models/__init__.py +1 -1
- nautobot/dcim/models/device_component_templates.py +2 -2
- nautobot/dcim/models/device_components.py +22 -20
- nautobot/dcim/models/devices.py +10 -1
- nautobot/dcim/models/locations.py +3 -3
- nautobot/dcim/models/power.py +6 -5
- nautobot/dcim/models/racks.py +4 -4
- nautobot/dcim/tables/__init__.py +3 -3
- nautobot/dcim/tables/devices.py +9 -6
- nautobot/dcim/tables/devicetypes.py +2 -2
- nautobot/dcim/tables/racks.py +1 -1
- nautobot/dcim/templates/dcim/cable.html +1 -1
- nautobot/dcim/templates/dcim/controller_create.html +1 -7
- nautobot/dcim/templates/dcim/controller_retrieve.html +1 -9
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +2 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +5 -0
- nautobot/dcim/templates/dcim/device/base.html +1 -1
- nautobot/dcim/templates/dcim/device.html +3 -11
- nautobot/dcim/templates/dcim/device_component.html +1 -1
- nautobot/dcim/templates/dcim/device_edit.html +36 -37
- nautobot/dcim/templates/dcim/devicetype.html +1 -1
- nautobot/dcim/templates/dcim/location.html +2 -10
- nautobot/dcim/templates/dcim/location_edit.html +1 -7
- nautobot/dcim/templates/dcim/locationtype.html +1 -1
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/manufacturer.html +1 -1
- nautobot/dcim/templates/dcim/platform.html +1 -1
- nautobot/dcim/templates/dcim/powerfeed.html +1 -1
- nautobot/dcim/templates/dcim/powerpanel.html +1 -1
- nautobot/dcim/templates/dcim/rack.html +2 -10
- nautobot/dcim/templates/dcim/rack_edit.html +1 -7
- nautobot/dcim/templates/dcim/rackgroup.html +1 -1
- nautobot/dcim/templates/dcim/rackreservation.html +3 -11
- nautobot/dcim/templates/dcim/virtualchassis.html +1 -1
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -9
- nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +1 -7
- nautobot/dcim/tests/integration/test_controller.py +62 -0
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
- nautobot/dcim/tests/integration/test_device_bulk_operations.py +30 -0
- nautobot/dcim/tests/integration/test_location_bulk_operations.py +43 -0
- nautobot/dcim/tests/test_api.py +16 -5
- nautobot/dcim/tests/test_filters.py +33 -0
- nautobot/dcim/tests/test_forms.py +51 -2
- nautobot/dcim/tests/test_graphql.py +52 -0
- nautobot/dcim/tests/test_jobs.py +118 -0
- nautobot/dcim/tests/test_models.py +52 -9
- nautobot/dcim/tests/test_views.py +30 -84
- nautobot/dcim/views.py +13 -28
- nautobot/extras/api/customfields.py +2 -2
- nautobot/extras/api/serializers.py +123 -85
- nautobot/extras/api/views.py +33 -30
- nautobot/extras/constants.py +3 -0
- nautobot/extras/datasources/git.py +125 -0
- nautobot/extras/filters/__init__.py +8 -6
- nautobot/extras/forms/base.py +2 -2
- nautobot/extras/forms/forms.py +139 -31
- nautobot/extras/forms/mixins.py +14 -6
- nautobot/extras/group_sync.py +3 -3
- nautobot/extras/health_checks.py +1 -2
- nautobot/extras/jobs.py +85 -18
- nautobot/extras/managers.py +3 -1
- nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
- nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
- nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
- nautobot/extras/migrations/0122_add_graphqlquery_owner_content_type.py +34 -0
- nautobot/extras/models/__init__.py +1 -1
- nautobot/extras/models/contacts.py +1 -1
- nautobot/extras/models/customfields.py +41 -23
- nautobot/extras/models/datasources.py +85 -0
- nautobot/extras/models/groups.py +11 -9
- nautobot/extras/models/jobs.py +23 -4
- nautobot/extras/models/models.py +17 -2
- nautobot/extras/models/relationships.py +17 -5
- nautobot/extras/plugins/__init__.py +13 -2
- nautobot/extras/plugins/marketplace_manifest.yml +84 -79
- nautobot/extras/plugins/tables.py +16 -14
- nautobot/extras/plugins/views.py +65 -69
- nautobot/extras/registry.py +1 -1
- nautobot/extras/secrets/__init__.py +2 -2
- nautobot/extras/signals.py +15 -1
- nautobot/extras/tables.py +7 -5
- nautobot/extras/templates/extras/computedfield.html +1 -1
- nautobot/extras/templates/extras/configcontext.html +1 -1
- nautobot/extras/templates/extras/configcontextschema.html +1 -1
- nautobot/extras/templates/extras/customfield.html +1 -1
- nautobot/extras/templates/extras/customlink.html +1 -1
- nautobot/extras/templates/extras/dynamicgroup.html +2 -10
- nautobot/extras/templates/extras/exporttemplate.html +1 -1
- nautobot/extras/templates/extras/gitrepository.html +1 -1
- nautobot/extras/templates/extras/graphqlquery.html +1 -1
- nautobot/extras/templates/extras/job_detail.html +17 -1
- nautobot/extras/templates/extras/job_edit.html +1 -0
- nautobot/extras/templates/extras/jobbutton_retrieve.html +1 -1
- nautobot/extras/templates/extras/jobhook.html +1 -1
- nautobot/extras/templates/extras/jobqueue_retrieve.html +1 -9
- nautobot/extras/templates/extras/jobresult.html +1 -1
- nautobot/extras/templates/extras/marketplace.html +29 -11
- nautobot/extras/templates/extras/objectchange.html +1 -1
- nautobot/extras/templates/extras/plugin_detail.html +33 -16
- nautobot/extras/templates/extras/plugins_tiles.html +21 -10
- nautobot/extras/templates/extras/relationship.html +1 -63
- nautobot/extras/templates/extras/role_retrieve.html +1 -1
- nautobot/extras/templates/extras/scheduledjob.html +1 -1
- nautobot/extras/templates/extras/secret.html +1 -1
- nautobot/extras/templates/extras/secretsgroup.html +1 -1
- nautobot/extras/templates/extras/status.html +1 -1
- nautobot/extras/templates/extras/tag.html +1 -1
- nautobot/extras/templates/extras/webhook.html +1 -1
- nautobot/extras/templatetags/job_buttons.py +4 -4
- nautobot/extras/test_jobs/api_test_job.py +1 -1
- nautobot/extras/test_jobs/atomic_transaction.py +2 -2
- nautobot/extras/test_jobs/dry_run.py +1 -1
- nautobot/extras/test_jobs/fail.py +5 -5
- nautobot/extras/test_jobs/file_output.py +1 -1
- nautobot/extras/test_jobs/file_upload_fail.py +1 -1
- nautobot/extras/test_jobs/file_upload_pass.py +1 -1
- nautobot/extras/test_jobs/ipaddress_vars.py +3 -1
- nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
- nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
- nautobot/extras/test_jobs/log_redaction.py +1 -1
- nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
- nautobot/extras/test_jobs/modify_db.py +1 -1
- nautobot/extras/test_jobs/object_var_optional.py +1 -1
- nautobot/extras/test_jobs/object_var_required.py +1 -1
- nautobot/extras/test_jobs/object_vars.py +1 -1
- nautobot/extras/test_jobs/pass.py +3 -3
- nautobot/extras/test_jobs/profiling.py +1 -1
- nautobot/extras/test_jobs/relative_import.py +3 -3
- nautobot/extras/test_jobs/singleton.py +16 -0
- nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
- nautobot/extras/test_jobs/task_queues.py +1 -1
- nautobot/extras/tests/git_data/01-valid-files/graphql_queries/device_interfaces.gql +8 -0
- nautobot/extras/tests/git_data/01-valid-files/graphql_queries/device_names.gql +5 -0
- nautobot/extras/tests/git_data/02-invalid-files/graphql_queries/bad_device_names.gql +5 -0
- nautobot/extras/tests/git_helper.py +9 -1
- nautobot/extras/tests/integration/__init__.py +29 -16
- nautobot/extras/tests/integration/test_plugin_banner.py +0 -2
- nautobot/extras/tests/test_api.py +19 -13
- nautobot/extras/tests/test_customfields.py +50 -52
- nautobot/extras/tests/test_datasources.py +29 -1
- nautobot/extras/tests/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/test_filters.py +6 -6
- nautobot/extras/tests/test_forms.py +33 -1
- nautobot/extras/tests/test_jobs.py +178 -32
- nautobot/extras/tests/test_models.py +299 -10
- nautobot/extras/tests/test_plugins.py +62 -9
- nautobot/extras/tests/test_relationships.py +120 -9
- nautobot/extras/tests/test_utils.py +22 -1
- nautobot/extras/tests/test_views.py +56 -194
- nautobot/extras/utils.py +20 -10
- nautobot/extras/views.py +85 -110
- nautobot/ipam/api/fields.py +3 -3
- nautobot/ipam/api/serializers.py +41 -33
- nautobot/ipam/api/views.py +68 -117
- nautobot/ipam/factory.py +1 -1
- nautobot/ipam/filters.py +3 -2
- nautobot/ipam/lookups.py +101 -62
- nautobot/ipam/models.py +74 -18
- nautobot/ipam/querysets.py +2 -2
- nautobot/ipam/tables.py +25 -9
- nautobot/ipam/templates/ipam/ipaddress.html +2 -10
- nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
- nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
- nautobot/ipam/templates/ipam/prefix.html +2 -10
- nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
- nautobot/ipam/templates/ipam/rir.html +1 -1
- nautobot/ipam/templates/ipam/routetarget.html +1 -1
- nautobot/ipam/templates/ipam/service.html +1 -1
- nautobot/ipam/templates/ipam/vlan.html +2 -10
- nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
- nautobot/ipam/templates/ipam/vlangroup.html +1 -1
- nautobot/ipam/templates/ipam/vrf.html +1 -1
- nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
- nautobot/ipam/tests/test_api.py +436 -3
- nautobot/ipam/tests/test_forms.py +49 -47
- nautobot/ipam/tests/test_migrations.py +30 -30
- nautobot/ipam/tests/test_models.py +119 -34
- nautobot/ipam/tests/test_querysets.py +63 -1
- nautobot/ipam/tests/test_utils.py +41 -2
- nautobot/ipam/tests/test_views.py +3 -0
- nautobot/ipam/utils/__init__.py +54 -17
- nautobot/ipam/views.py +61 -87
- 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.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
- 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/docs/404.html +131 -14
- nautobot/project-static/docs/apps/index.html +131 -14
- nautobot/project-static/docs/apps/nautobot-apps.html +132 -16
- nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
- nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js → bundle.60a45f97.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js.map → bundle.60a45f97.min.js.map} +2 -2
- nautobot/project-static/docs/assets/javascripts/workers/{search.6ce7567c.min.js → search.f8cc74c7.min.js} +1 -1
- nautobot/project-static/docs/assets/javascripts/workers/{search.6ce7567c.min.js.map → search.f8cc74c7.min.js.map} +1 -1
- nautobot/project-static/docs/assets/stylesheets/{main.6f8fc17f.min.css → main.a40c8224.min.css} +1 -1
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +147 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +144 -17
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +459 -132
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +175 -28
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +180 -31
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +138 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +137 -15
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +164 -27
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +187 -38
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +193 -31
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +216 -48
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +324 -75
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +666 -175
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +194 -46
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +538 -177
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +578 -221
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +145 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +156 -25
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +492 -65
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +705 -215
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +943 -422
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +144 -17
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +619 -200
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +474 -159
- nautobot/project-static/docs/development/apps/api/configuration-view.html +131 -14
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +131 -14
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +131 -14
- nautobot/project-static/docs/development/apps/api/models/global-search.html +131 -14
- nautobot/project-static/docs/development/apps/api/models/graphql.html +131 -14
- nautobot/project-static/docs/development/apps/api/models/index.html +131 -14
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +153 -17
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +131 -14
- nautobot/project-static/docs/development/apps/api/prometheus.html +131 -14
- nautobot/project-static/docs/development/apps/api/setup.html +131 -14
- nautobot/project-static/docs/development/apps/api/testing.html +131 -14
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +131 -14
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +131 -14
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +131 -14
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +131 -14
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/base-template.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/index.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/notes.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +137 -16
- nautobot/project-static/docs/development/apps/api/views/urls.html +131 -14
- nautobot/project-static/docs/development/apps/index.html +131 -14
- nautobot/project-static/docs/development/apps/migration/code-updates.html +131 -14
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +131 -14
- nautobot/project-static/docs/development/apps/migration/from-v1.html +131 -14
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +131 -14
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +131 -14
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +131 -14
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +131 -14
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +135 -18
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +131 -14
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +297 -25
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +131 -14
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +131 -14
- nautobot/project-static/docs/development/core/application-registry.html +131 -14
- nautobot/project-static/docs/development/core/best-practices.html +131 -14
- nautobot/project-static/docs/development/core/bootstrap-ui.html +131 -14
- nautobot/project-static/docs/development/core/caching.html +131 -14
- nautobot/project-static/docs/development/core/controllers.html +131 -14
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +158 -84
- nautobot/project-static/docs/development/core/generic-views.html +131 -14
- nautobot/project-static/docs/development/core/getting-started.html +334 -234
- nautobot/project-static/docs/development/core/homepage.html +134 -17
- nautobot/project-static/docs/development/core/index.html +131 -14
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +9829 -0
- nautobot/project-static/docs/development/core/model-checklist.html +141 -22
- nautobot/project-static/docs/development/core/model-features.html +131 -14
- nautobot/project-static/docs/development/core/natural-keys.html +131 -14
- nautobot/project-static/docs/development/core/navigation-menu.html +131 -14
- nautobot/project-static/docs/development/core/release-checklist.html +134 -17
- nautobot/project-static/docs/development/core/role-internals.html +131 -14
- nautobot/project-static/docs/development/core/settings.html +131 -14
- nautobot/project-static/docs/development/core/style-guide.html +134 -17
- nautobot/project-static/docs/development/core/templates.html +132 -15
- nautobot/project-static/docs/development/core/testing.html +131 -14
- nautobot/project-static/docs/development/core/ui-component-framework.html +454 -283
- nautobot/project-static/docs/development/core/user-preferences.html +131 -14
- nautobot/project-static/docs/development/index.html +131 -14
- nautobot/project-static/docs/development/jobs/index.html +301 -132
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +131 -14
- nautobot/project-static/docs/index.html +139 -33
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +132 -17
- nautobot/project-static/docs/overview/design_philosophy.html +131 -14
- nautobot/project-static/docs/release-notes/index.html +137 -22
- nautobot/project-static/docs/release-notes/version-1.0.html +319 -203
- nautobot/project-static/docs/release-notes/version-1.1.html +316 -200
- nautobot/project-static/docs/release-notes/version-1.2.html +391 -275
- nautobot/project-static/docs/release-notes/version-1.3.html +417 -301
- nautobot/project-static/docs/release-notes/version-1.4.html +502 -387
- nautobot/project-static/docs/release-notes/version-1.5.html +690 -576
- nautobot/project-static/docs/release-notes/version-1.6.html +989 -457
- nautobot/project-static/docs/release-notes/version-2.0.html +613 -499
- nautobot/project-static/docs/release-notes/version-2.1.html +448 -334
- nautobot/project-static/docs/release-notes/version-2.2.html +441 -327
- nautobot/project-static/docs/release-notes/version-2.3.html +1171 -451
- nautobot/project-static/docs/release-notes/version-2.4.html +800 -111
- nautobot/project-static/docs/requirements.txt +2 -2
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +303 -287
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +131 -14
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +131 -14
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +133 -16
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +131 -14
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +131 -14
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +195 -18
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +134 -17
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +133 -16
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +131 -14
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +131 -14
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +131 -14
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +151 -18
- nautobot/project-static/docs/user-guide/administration/installation/index.html +131 -14
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +132 -15
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +131 -14
- nautobot/project-static/docs/user-guide/administration/installation/services.html +131 -14
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +131 -14
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +131 -14
- nautobot/project-static/docs/user-guide/administration/security/index.html +9420 -0
- nautobot/project-static/docs/user-guide/administration/security/notices.html +9843 -0
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +131 -14
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +134 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +135 -22
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +134 -17
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +134 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +236 -34
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +134 -17
- nautobot/project-static/docs/{development/core/local-k8s.html → user-guide/feature-guides/wireless-networks-and-controllers.html} +632 -566
- nautobot/project-static/docs/user-guide/index.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +135 -18
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +451 -16
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +135 -17
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +134 -17
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9797 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +132 -15
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +179 -35
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +159 -15
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +131 -14
- nautobot/project-static/js/forms.js +1 -1
- nautobot/tenancy/api/views.py +9 -13
- nautobot/tenancy/templates/tenancy/tenant.html +1 -2
- nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
- nautobot/tenancy/views.py +4 -2
- nautobot/users/admin.py +1 -1
- nautobot/users/api/serializers.py +5 -4
- nautobot/users/api/views.py +3 -3
- nautobot/virtualization/api/serializers.py +4 -4
- nautobot/virtualization/api/views.py +5 -24
- nautobot/virtualization/filters.py +20 -3
- nautobot/virtualization/models.py +1 -1
- nautobot/virtualization/tables.py +2 -2
- nautobot/virtualization/templates/virtualization/cluster.html +1 -1
- nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
- nautobot/virtualization/templates/virtualization/clustergroup.html +1 -1
- nautobot/virtualization/templates/virtualization/clustertype.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -10
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
- nautobot/virtualization/templates/virtualization/vminterface.html +1 -1
- nautobot/virtualization/tests/test_filters.py +17 -0
- nautobot/wireless/filters.py +2 -2
- nautobot/wireless/forms.py +1 -1
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +1 -9
- nautobot/wireless/tests/integration/__init__.py +0 -0
- nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
- nautobot/wireless/tests/test_filters.py +29 -1
- nautobot/wireless/tests/test_views.py +22 -1
- nautobot/wireless/views.py +0 -10
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/METADATA +9 -9
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/RECORD +667 -610
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/WHEEL +1 -1
- nautobot/core/fixtures/user-data.json +0 -59
- /nautobot/project-static/docs/assets/stylesheets/{main.6f8fc17f.min.css.map → main.a40c8224.min.css.map} +0 -0
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/NOTICE +0 -0
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
from django.contrib.contenttypes.models import ContentType
|
|
2
|
+
from django.core.exceptions import (
|
|
3
|
+
FieldDoesNotExist,
|
|
4
|
+
ObjectDoesNotExist,
|
|
5
|
+
PermissionDenied,
|
|
6
|
+
ValidationError,
|
|
7
|
+
)
|
|
8
|
+
from django.db.models import ManyToManyField, ProtectedError
|
|
9
|
+
|
|
10
|
+
from nautobot.core import exceptions
|
|
11
|
+
from nautobot.core.forms.utils import restrict_form_fields
|
|
12
|
+
from nautobot.core.utils.filtering import get_filterset_field
|
|
13
|
+
from nautobot.core.utils.lookup import get_filterset_for_model, get_form_for_model
|
|
14
|
+
from nautobot.extras.context_managers import deferred_change_logging_for_bulk_operation
|
|
15
|
+
from nautobot.extras.jobs import (
|
|
16
|
+
BooleanVar,
|
|
17
|
+
Job,
|
|
18
|
+
JSONVar,
|
|
19
|
+
ObjectVar,
|
|
20
|
+
RunJobTaskFailed,
|
|
21
|
+
)
|
|
22
|
+
from nautobot.extras.utils import bulk_delete_with_bulk_change_logging, remove_prefix_from_cf_key
|
|
23
|
+
|
|
24
|
+
name = "System Jobs"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class BulkEditObjects(Job):
|
|
28
|
+
"""System Job to bulk Edit objects."""
|
|
29
|
+
|
|
30
|
+
content_type = ObjectVar(
|
|
31
|
+
model=ContentType,
|
|
32
|
+
description="Type of objects to update",
|
|
33
|
+
)
|
|
34
|
+
form_data = JSONVar(description="BulkEditForm data")
|
|
35
|
+
edit_all = BooleanVar(description="Bulk Edit all object / all filtered objects", required=False)
|
|
36
|
+
filter_query_params = JSONVar(label="Filter Query Params", required=False)
|
|
37
|
+
|
|
38
|
+
class Meta:
|
|
39
|
+
name = "Bulk Edit Objects"
|
|
40
|
+
description = "Bulk edit objects."
|
|
41
|
+
has_sensitive_variables = False
|
|
42
|
+
soft_time_limit = 1800
|
|
43
|
+
time_limit = 2000
|
|
44
|
+
|
|
45
|
+
def _update_objects(self, model, form, filter_query_params, edit_all, nullified_fields):
|
|
46
|
+
with deferred_change_logging_for_bulk_operation():
|
|
47
|
+
base_queryset = model.objects.restrict(self.user, "change")
|
|
48
|
+
updated_objects_pk = []
|
|
49
|
+
filterset_cls = get_filterset_for_model(model)
|
|
50
|
+
|
|
51
|
+
if filter_query_params:
|
|
52
|
+
if not filterset_cls:
|
|
53
|
+
self.logger.error(f"Filterset not found for {model._meta.verbose_name}")
|
|
54
|
+
raise RunJobTaskFailed(
|
|
55
|
+
f"Filter query provided but {model._meta.verbose_name} does not have a filterset."
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Discarding non-filter query params
|
|
59
|
+
new_filter_query_params = {}
|
|
60
|
+
|
|
61
|
+
for key, value in filter_query_params.items():
|
|
62
|
+
try:
|
|
63
|
+
get_filterset_field(filterset_cls(), key)
|
|
64
|
+
new_filter_query_params[key] = value
|
|
65
|
+
except exceptions.FilterSetFieldNotFound:
|
|
66
|
+
self.logger.debug(
|
|
67
|
+
f"Query parameter `{key}` not found in filterset for `{filterset_cls}`, discarding it"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
filter_query_params = new_filter_query_params
|
|
71
|
+
|
|
72
|
+
if edit_all:
|
|
73
|
+
if filter_query_params:
|
|
74
|
+
queryset = filterset_cls(filter_query_params).qs.restrict(self.user, "change")
|
|
75
|
+
else:
|
|
76
|
+
queryset = model.objects.restrict(self.user, "change")
|
|
77
|
+
else:
|
|
78
|
+
queryset = model.objects.restrict(self.user, "change").filter(pk__in=form.cleaned_data["pk"])
|
|
79
|
+
|
|
80
|
+
form_custom_fields = getattr(form, "custom_fields", [])
|
|
81
|
+
form_relationships = getattr(form, "relationships", [])
|
|
82
|
+
standard_fields = [
|
|
83
|
+
field
|
|
84
|
+
for field in form.fields
|
|
85
|
+
if field not in form_custom_fields + form_relationships + ["pk"] + ["object_note"]
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
self.logger.debug(f"Performing update on {queryset.count()} {model._meta.verbose_name_plural}")
|
|
89
|
+
for obj in queryset.iterator():
|
|
90
|
+
# Update standard fields. If a field is listed in _nullify, delete its value.
|
|
91
|
+
for field_name in standard_fields:
|
|
92
|
+
try:
|
|
93
|
+
model_field = model._meta.get_field(field_name)
|
|
94
|
+
except FieldDoesNotExist:
|
|
95
|
+
# This form field is used to modify a field rather than set its value directly
|
|
96
|
+
model_field = None
|
|
97
|
+
|
|
98
|
+
# Handle nullification
|
|
99
|
+
if nullified_fields:
|
|
100
|
+
if field_name in form.nullable_fields and field_name in nullified_fields:
|
|
101
|
+
if isinstance(model_field, ManyToManyField):
|
|
102
|
+
getattr(obj, field_name).set([])
|
|
103
|
+
else:
|
|
104
|
+
setattr(obj, field_name, None if model_field is not None and model_field.null else "")
|
|
105
|
+
|
|
106
|
+
# ManyToManyFields
|
|
107
|
+
elif isinstance(model_field, ManyToManyField):
|
|
108
|
+
if form.cleaned_data[field_name]:
|
|
109
|
+
getattr(obj, field_name).set(form.cleaned_data[field_name])
|
|
110
|
+
# Normal fields
|
|
111
|
+
elif form.cleaned_data[field_name] not in (None, ""):
|
|
112
|
+
setattr(obj, field_name, form.cleaned_data[field_name])
|
|
113
|
+
|
|
114
|
+
# Update custom fields
|
|
115
|
+
for field_name in form_custom_fields:
|
|
116
|
+
if field_name in form.nullable_fields and nullified_fields and field_name in nullified_fields:
|
|
117
|
+
obj.cf[remove_prefix_from_cf_key(field_name)] = None
|
|
118
|
+
elif form.cleaned_data.get(field_name) not in (None, "", []):
|
|
119
|
+
obj.cf[remove_prefix_from_cf_key(field_name)] = form.cleaned_data[field_name]
|
|
120
|
+
|
|
121
|
+
obj.full_clean()
|
|
122
|
+
obj.save()
|
|
123
|
+
updated_objects_pk.append(obj.pk)
|
|
124
|
+
form.post_save(obj)
|
|
125
|
+
|
|
126
|
+
if hasattr(form, "save_relationships") and callable(form.save_relationships):
|
|
127
|
+
# Add/remove relationship associations
|
|
128
|
+
form.save_relationships(instance=obj, nullified_fields=nullified_fields)
|
|
129
|
+
|
|
130
|
+
if hasattr(form, "save_note") and callable(form.save_note):
|
|
131
|
+
form.save_note(instance=obj, user=self.user)
|
|
132
|
+
total_updated_objs = len(updated_objects_pk)
|
|
133
|
+
# Enforce object-level permissions
|
|
134
|
+
if base_queryset.filter(pk__in=updated_objects_pk).count() != total_updated_objs:
|
|
135
|
+
raise ObjectDoesNotExist
|
|
136
|
+
return total_updated_objs
|
|
137
|
+
|
|
138
|
+
def _process_valid_form(self, model, form, filter_query_params, edit_all, nullified_fields):
|
|
139
|
+
try:
|
|
140
|
+
total_updated_objs = self._update_objects(model, form, filter_query_params, edit_all, nullified_fields)
|
|
141
|
+
msg = f"Updated {total_updated_objs} {model._meta.verbose_name_plural}"
|
|
142
|
+
self.logger.info(msg)
|
|
143
|
+
return msg
|
|
144
|
+
except ValidationError as e:
|
|
145
|
+
self.logger.error(str(e))
|
|
146
|
+
except ObjectDoesNotExist:
|
|
147
|
+
msg = "Object update failed due to object-level permissions violation"
|
|
148
|
+
self.logger.error(msg)
|
|
149
|
+
raise RunJobTaskFailed("Bulk Edit not fully successful, see logs")
|
|
150
|
+
|
|
151
|
+
def run( # pylint: disable=arguments-differ
|
|
152
|
+
self, *, content_type, form_data, edit_all=False, filter_query_params=None
|
|
153
|
+
):
|
|
154
|
+
if not self.user.has_perm(f"{content_type.app_label}.change_{content_type.model}"):
|
|
155
|
+
self.logger.error('User "%s" does not have permission to update %s objects', self.user, content_type.model)
|
|
156
|
+
raise PermissionDenied("User does not have change permissions on the requested content-type")
|
|
157
|
+
|
|
158
|
+
model = content_type.model_class()
|
|
159
|
+
if model is None:
|
|
160
|
+
self.logger.error(
|
|
161
|
+
'Could not find the "%s.%s" data model. Perhaps an app is uninstalled?',
|
|
162
|
+
content_type.app_label,
|
|
163
|
+
content_type.model,
|
|
164
|
+
)
|
|
165
|
+
raise RunJobTaskFailed("Model not found")
|
|
166
|
+
try:
|
|
167
|
+
form_cls = get_form_for_model(model, form_prefix="BulkEdit")
|
|
168
|
+
except Exception:
|
|
169
|
+
self.logger.debug(
|
|
170
|
+
'Could not find the "%s.%s" data bulk edit form. Unable to process Bulk Edit for this model.',
|
|
171
|
+
content_type.app_label,
|
|
172
|
+
content_type.model,
|
|
173
|
+
)
|
|
174
|
+
raise
|
|
175
|
+
form = form_cls(model, form_data, edit_all=edit_all)
|
|
176
|
+
restrict_form_fields(form, self.user)
|
|
177
|
+
|
|
178
|
+
if form.is_valid():
|
|
179
|
+
self.logger.debug("Form validation was successful")
|
|
180
|
+
nullified_fields = form_data.get("_nullify")
|
|
181
|
+
return self._process_valid_form(model, form, filter_query_params, edit_all, nullified_fields)
|
|
182
|
+
else:
|
|
183
|
+
self.logger.error(f"Form validation unsuccessful: {form.errors.as_json()}")
|
|
184
|
+
|
|
185
|
+
raise RunJobTaskFailed("Updating Jobs Failed")
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class BulkDeleteObjects(Job):
|
|
189
|
+
"""
|
|
190
|
+
System job to bulk delete objects.
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
content_type = ObjectVar(
|
|
194
|
+
model=ContentType,
|
|
195
|
+
description="Type of objects to delete",
|
|
196
|
+
)
|
|
197
|
+
pk_list = JSONVar(description="List of objects pks to delete", required=False)
|
|
198
|
+
delete_all = BooleanVar(description="Delete all (filtered) objects instead of a list of PKs", required=False)
|
|
199
|
+
filter_query_params = JSONVar(label="Filter Query Params", required=False)
|
|
200
|
+
|
|
201
|
+
class Meta:
|
|
202
|
+
name = "Bulk Delete Objects"
|
|
203
|
+
description = "Bulk delete objects."
|
|
204
|
+
has_sensitive_variables = False
|
|
205
|
+
soft_time_limit = 1800
|
|
206
|
+
time_limit = 2000
|
|
207
|
+
|
|
208
|
+
def run( # pylint: disable=arguments-differ
|
|
209
|
+
self, *, content_type, pk_list=None, delete_all=False, filter_query_params=None
|
|
210
|
+
):
|
|
211
|
+
if not self.user.has_perm(f"{content_type.app_label}.delete_{content_type.model}"):
|
|
212
|
+
self.logger.error('User "%s" does not have permission to delete %s objects', self.user, content_type.model)
|
|
213
|
+
raise PermissionDenied("User does not have delete permissions on the requested content-type")
|
|
214
|
+
|
|
215
|
+
model = content_type.model_class()
|
|
216
|
+
if model is None:
|
|
217
|
+
self.logger.error(
|
|
218
|
+
'Could not find the "%s.%s" data model. Perhaps an app is uninstalled?',
|
|
219
|
+
content_type.app_label,
|
|
220
|
+
content_type.model,
|
|
221
|
+
)
|
|
222
|
+
raise RunJobTaskFailed("Model not found")
|
|
223
|
+
|
|
224
|
+
filterset_cls = get_filterset_for_model(model)
|
|
225
|
+
|
|
226
|
+
if filter_query_params:
|
|
227
|
+
if not filterset_cls:
|
|
228
|
+
self.logger.error(f"Filterset not found for {model._meta.verbose_name}")
|
|
229
|
+
raise RunJobTaskFailed(
|
|
230
|
+
f"Filter query provided but {model._meta.verbose_name} does not have a filterset."
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
# Discarding non-filter query params
|
|
234
|
+
new_filter_query_params = {}
|
|
235
|
+
|
|
236
|
+
for key, value in filter_query_params.items():
|
|
237
|
+
try:
|
|
238
|
+
get_filterset_field(filterset_cls(), key)
|
|
239
|
+
new_filter_query_params[key] = value
|
|
240
|
+
except exceptions.FilterSetFieldNotFound:
|
|
241
|
+
self.logger.debug(f"Query parameter `{key}` not found in `{filterset_cls}`, discarding it")
|
|
242
|
+
|
|
243
|
+
filter_query_params = new_filter_query_params
|
|
244
|
+
|
|
245
|
+
if delete_all:
|
|
246
|
+
# Case for selecting all objects (or all filtered objects) to delete
|
|
247
|
+
if filter_query_params:
|
|
248
|
+
# If there is filter query params, we need to apply it to the queryset
|
|
249
|
+
queryset = filterset_cls(filter_query_params).qs.restrict(self.user, "delete")
|
|
250
|
+
# We take this approach because filterset.qs has already applied .distinct(),
|
|
251
|
+
# and performing a .delete directly on a queryset with .distinct applied is not allowed.
|
|
252
|
+
queryset = model.objects.filter(pk__in=queryset)
|
|
253
|
+
else:
|
|
254
|
+
# If there is not, we can just restrict the queryset to the user's permissions
|
|
255
|
+
queryset = model.objects.restrict(self.user, "delete")
|
|
256
|
+
elif pk_list:
|
|
257
|
+
# Case for selecting specific objects to delete, delete_all overrides this option
|
|
258
|
+
queryset = model.objects.restrict(self.user, "delete").filter(pk__in=pk_list)
|
|
259
|
+
if queryset.count() < len(pk_list):
|
|
260
|
+
# We do not check ObjectPermission error for `delete_all` case because user is trying to
|
|
261
|
+
# delete all objs they have permission to which would not raise any issue.
|
|
262
|
+
self.logger.error("You do not have permissions to delete some of the objects provided in `pk_list`.")
|
|
263
|
+
raise RunJobTaskFailed("Caught ObjectPermission error while attempting to delete objects")
|
|
264
|
+
elif not pk_list and not delete_all:
|
|
265
|
+
self.logger.error("You must select at least one object instance to delete.")
|
|
266
|
+
raise RunJobTaskFailed("Either `pk_list` or `delete_all` is required.")
|
|
267
|
+
|
|
268
|
+
verbose_name_plural = model._meta.verbose_name_plural
|
|
269
|
+
|
|
270
|
+
# Currently the only purpose of a bulk delete form is to perform a `pre_delete` operation
|
|
271
|
+
if form_cls := get_form_for_model(model, form_prefix="BulkDelete"):
|
|
272
|
+
form = form_cls(model, {"pk": pk_list}, delete_all=delete_all)
|
|
273
|
+
if hasattr(form, "perform_pre_delete"):
|
|
274
|
+
form.perform_pre_delete(queryset)
|
|
275
|
+
|
|
276
|
+
try:
|
|
277
|
+
self.logger.info(f"Deleting {queryset.count()} {verbose_name_plural}...")
|
|
278
|
+
_, deleted_info = bulk_delete_with_bulk_change_logging(queryset)
|
|
279
|
+
deleted_count = deleted_info.get(model._meta.label, 0)
|
|
280
|
+
except ProtectedError as err:
|
|
281
|
+
# TODO this error message needs to be cleaner, ideally using a variant of handle_protectederror
|
|
282
|
+
self.logger.error(f"Caught ProtectedError while attempting to delete objects: `{err}`")
|
|
283
|
+
raise RunJobTaskFailed("Caught ProtectedError while attempting to delete objects")
|
|
284
|
+
msg = f"Deleted {deleted_count} {model._meta.verbose_name_plural}"
|
|
285
|
+
self.logger.info(msg)
|
nautobot/core/jobs/cleanup.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from datetime import timedelta
|
|
2
2
|
|
|
3
3
|
from django.core.exceptions import PermissionDenied
|
|
4
|
+
from django.db.models import CASCADE
|
|
4
5
|
from django.db.models.signals import pre_delete
|
|
5
6
|
from django.utils import timezone
|
|
6
7
|
|
|
@@ -48,7 +49,28 @@ class LogsCleanup(Job):
|
|
|
48
49
|
description = "Delete ObjectChange and/or JobResult/JobLogEntry records older than a specified cutoff."
|
|
49
50
|
has_sensitive_variables = False
|
|
50
51
|
|
|
51
|
-
def
|
|
52
|
+
def recursive_delete_with_cascade(self, queryset, deletion_summary):
|
|
53
|
+
"""
|
|
54
|
+
Recursively deletes all related objects with CASCADE for a given queryset.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
queryset (QuerySet): The queryset of objects to delete.
|
|
58
|
+
deletion_summary (dict): A dictionary to store the count of deleted objects for each model.
|
|
59
|
+
"""
|
|
60
|
+
related_objects = queryset.model._meta.related_objects
|
|
61
|
+
queryset = queryset.only("id")
|
|
62
|
+
|
|
63
|
+
for related_object in related_objects:
|
|
64
|
+
if related_object.on_delete is CASCADE:
|
|
65
|
+
related_model = related_object.related_model
|
|
66
|
+
related_field_name = related_object.field.name
|
|
67
|
+
cascade_queryset = related_model.objects.filter(**{f"{related_field_name}__id__in": queryset})
|
|
68
|
+
self.recursive_delete_with_cascade(cascade_queryset, deletion_summary)
|
|
69
|
+
_, deleted_dict = queryset.delete()
|
|
70
|
+
deletion_summary.update(deleted_dict)
|
|
71
|
+
return deletion_summary
|
|
72
|
+
|
|
73
|
+
def run(self, *, cleanup_types, max_age=None): # pylint: disable=arguments-differ
|
|
52
74
|
if max_age in (None, ""):
|
|
53
75
|
max_age = get_settings_or_config("CHANGELOG_RETENTION", fallback=90)
|
|
54
76
|
if max_age == 0:
|
|
@@ -77,22 +99,36 @@ class LogsCleanup(Job):
|
|
|
77
99
|
|
|
78
100
|
if CleanupTypes.JOB_RESULT in cleanup_types:
|
|
79
101
|
self.logger.info("Deleting JobResult records prior to %s", cutoff)
|
|
80
|
-
|
|
102
|
+
queryset = JobResult.objects.restrict(self.user, "delete").filter(date_done__lt=cutoff)
|
|
103
|
+
deletion_summary = {}
|
|
104
|
+
self.recursive_delete_with_cascade(queryset, deletion_summary)
|
|
81
105
|
result.setdefault("extras.JobResult", 0)
|
|
82
106
|
result.setdefault("extras.JobLogEntry", 0)
|
|
83
|
-
result.update(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
107
|
+
result.update(deletion_summary)
|
|
108
|
+
|
|
109
|
+
for modelname, count in deletion_summary.items():
|
|
110
|
+
self.logger.info(
|
|
111
|
+
"As part of deleting %d JobResult records, also deleted %d related %s records",
|
|
112
|
+
result["extras.JobResult"],
|
|
113
|
+
count,
|
|
114
|
+
modelname,
|
|
115
|
+
)
|
|
89
116
|
|
|
90
117
|
if CleanupTypes.OBJECT_CHANGE in cleanup_types:
|
|
91
118
|
self.logger.info("Deleting ObjectChange records prior to %s", cutoff)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
119
|
+
queryset = ObjectChange.objects.restrict(self.user, "delete").filter(time__lt=cutoff)
|
|
120
|
+
deletion_summary = {}
|
|
121
|
+
self.recursive_delete_with_cascade(queryset, deletion_summary)
|
|
122
|
+
result.setdefault("extras.ObjectChange", 0)
|
|
123
|
+
result.update(deletion_summary)
|
|
124
|
+
|
|
125
|
+
for modelname, count in deletion_summary.items():
|
|
126
|
+
self.logger.info(
|
|
127
|
+
"As part of deleting %d ObjectChange records, also deleted %d related %s records",
|
|
128
|
+
result["extras.ObjectChange"],
|
|
129
|
+
count,
|
|
130
|
+
modelname,
|
|
131
|
+
)
|
|
96
132
|
return result
|
|
97
133
|
finally:
|
|
98
134
|
# Be sure to clean up after ourselves!
|
nautobot/core/jobs/groups.py
CHANGED
|
@@ -24,7 +24,7 @@ class RefreshDynamicGroupCaches(Job):
|
|
|
24
24
|
description = "Re-calculate and re-cache the membership lists of Dynamic Groups."
|
|
25
25
|
has_sensitive_variables = False
|
|
26
26
|
|
|
27
|
-
def run(self, single_group=None):
|
|
27
|
+
def run(self, single_group=None): # pylint: disable=arguments-differ
|
|
28
28
|
groups = DynamicGroup.objects.restrict(self.user, "view").exclude(
|
|
29
29
|
group_type=DynamicGroupTypeChoices.TYPE_STATIC
|
|
30
30
|
)
|
|
@@ -63,7 +63,7 @@ class Command(BaseCommand):
|
|
|
63
63
|
for model in models:
|
|
64
64
|
model_name = f"{model._meta.app_label}.{model.__name__}"
|
|
65
65
|
# Most swap out for user_model
|
|
66
|
-
if model_name == "auth.User":
|
|
66
|
+
if model_name == "auth.User": # pylint: disable=hard-coded-auth-user
|
|
67
67
|
model = get_user_model()
|
|
68
68
|
# Skip models that aren't actually in the database
|
|
69
69
|
if not model._meta.managed:
|
nautobot/core/models/__init__.py
CHANGED
|
@@ -248,6 +248,8 @@ class BaseModel(models.Model):
|
|
|
248
248
|
Unlike `get_natural_key_def()`, this doesn't auto-exclude all AutoField and BigAutoField fields,
|
|
249
249
|
but instead explicitly discounts the `id` field (only) as a candidate.
|
|
250
250
|
"""
|
|
251
|
+
if cls != cls._meta.concrete_model:
|
|
252
|
+
return cls._meta.concrete_model.natural_key_field_lookups
|
|
251
253
|
# First, figure out which local fields comprise the natural key:
|
|
252
254
|
natural_key_field_names = []
|
|
253
255
|
if hasattr(cls, "natural_key_field_names"):
|
|
@@ -270,7 +272,7 @@ class BaseModel(models.Model):
|
|
|
270
272
|
|
|
271
273
|
if not natural_key_field_names:
|
|
272
274
|
raise AttributeError(
|
|
273
|
-
f"Unable to identify an intrinsic natural-key definition for {cls.__name__}. "
|
|
275
|
+
f"Unable to identify an intrinsic natural-key definition for {cls.__name__}. " # pylint: disable=no-member
|
|
274
276
|
"If there isn't at least one UniqueConstraint, unique_together, or field with unique=True, "
|
|
275
277
|
"you probably need to explicitly declare the 'natural_key_field_names' for this model, "
|
|
276
278
|
"or potentially override the default 'natural_key_field_lookups' implementation for this model."
|
|
@@ -69,7 +69,7 @@ class JSONSet(Func):
|
|
|
69
69
|
}
|
|
70
70
|
return c
|
|
71
71
|
|
|
72
|
-
def as_sql(self, compiler, connection, function=None, **extra_context):
|
|
72
|
+
def as_sql(self, compiler, connection, function=None, **extra_context): # pylint:disable=arguments-differ
|
|
73
73
|
"""
|
|
74
74
|
MySQL implementation based on https://github.com/django/django/pull/18489/files.
|
|
75
75
|
|
|
@@ -138,7 +138,7 @@ class JSONRemove(Func):
|
|
|
138
138
|
self.path = path
|
|
139
139
|
super().__init__(expression)
|
|
140
140
|
|
|
141
|
-
def as_sql(self, compiler, connection, function=None, **extra_context):
|
|
141
|
+
def as_sql(self, compiler, connection, function=None, **extra_context): # pylint:disable=arguments-differ
|
|
142
142
|
"""
|
|
143
143
|
MySQL implementation based on https://github.com/django/django/pull/18489/files.
|
|
144
144
|
|
|
@@ -111,12 +111,15 @@ class TreeModel(TreeNode):
|
|
|
111
111
|
if display_str:
|
|
112
112
|
return display_str
|
|
113
113
|
try:
|
|
114
|
-
if self.
|
|
115
|
-
|
|
114
|
+
if self.parent_id is not None:
|
|
115
|
+
parent_display_str = cache.get(cache_key.replace(str(self.id), str(self.parent_id)), "")
|
|
116
|
+
if not parent_display_str:
|
|
117
|
+
parent_display_str = self.parent.display # pylint: disable=no-member
|
|
118
|
+
display_str = parent_display_str + " → "
|
|
116
119
|
except self.DoesNotExist:
|
|
117
120
|
# Expected to occur at times during bulk-delete operations
|
|
118
121
|
pass
|
|
119
|
-
display_str += self.name
|
|
122
|
+
display_str += self.name # pylint: disable=no-member # we checked with hasattr() above
|
|
120
123
|
cache.set(cache_key, display_str, 5)
|
|
121
124
|
return display_str
|
|
122
125
|
|
nautobot/core/settings.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import datetime
|
|
1
2
|
import os
|
|
2
3
|
import os.path
|
|
3
4
|
import platform
|
|
@@ -163,6 +164,16 @@ NAPALM_PASSWORD = os.getenv("NAUTOBOT_NAPALM_PASSWORD", "")
|
|
|
163
164
|
NAPALM_TIMEOUT = int(os.getenv("NAUTOBOT_NAPALM_TIMEOUT", "30"))
|
|
164
165
|
NAPALM_USERNAME = os.getenv("NAUTOBOT_NAPALM_USERNAME", "")
|
|
165
166
|
|
|
167
|
+
# Expiration date (YYYY-MM-DD) for an active Nautobot support contract with Network to Code.
|
|
168
|
+
# Displayed in the About page.
|
|
169
|
+
if (
|
|
170
|
+
"NAUTOBOT_NTC_SUPPORT_CONTRACT_EXPIRATION_DATE" in os.environ
|
|
171
|
+
and os.environ["NAUTOBOT_NTC_SUPPORT_CONTRACT_EXPIRATION_DATE"] != ""
|
|
172
|
+
):
|
|
173
|
+
NTC_SUPPORT_CONTRACT_EXPIRATION_DATE = datetime.date.fromisoformat(
|
|
174
|
+
os.environ["NAUTOBOT_NTC_SUPPORT_CONTRACT_EXPIRATION_DATE"]
|
|
175
|
+
)
|
|
176
|
+
|
|
166
177
|
# Default number of objects to display per page of the UI and REST API. Default is 50
|
|
167
178
|
if "NAUTOBOT_PAGINATE_COUNT" in os.environ and os.environ["NAUTOBOT_PAGINATE_COUNT"] != "":
|
|
168
179
|
PAGINATE_COUNT = int(os.environ["NAUTOBOT_PAGINATE_COUNT"])
|
|
@@ -180,6 +191,9 @@ PLUGINS_CONFIG = {}
|
|
|
180
191
|
if "NAUTOBOT_PREFER_IPV4" in os.environ and os.environ["NAUTOBOT_PREFER_IPV4"] != "":
|
|
181
192
|
PREFER_IPV4 = is_truthy(os.environ["NAUTOBOT_PREFER_IPV4"])
|
|
182
193
|
|
|
194
|
+
# Publish a simple "no-index" robots.txt for Nautobot?
|
|
195
|
+
PUBLISH_ROBOTS_TXT = is_truthy(os.getenv("NAUTOBOT_PUBLISH_ROBOTS_TXT", "True"))
|
|
196
|
+
|
|
183
197
|
# Default height and width in pixels of a single rack unit in rendered rack elevations. Defaults are 22 and 220
|
|
184
198
|
if (
|
|
185
199
|
"NAUTOBOT_RACK_ELEVATION_DEFAULT_UNIT_HEIGHT" in os.environ
|
|
@@ -232,7 +246,7 @@ if SSO_ENABLE_GROUP_SYNC:
|
|
|
232
246
|
"social_core.pipeline.social_auth.associate_user",
|
|
233
247
|
"social_core.pipeline.social_auth.load_extra_data",
|
|
234
248
|
"social_core.pipeline.user.user_details",
|
|
235
|
-
"nautobot.extras.group_sync",
|
|
249
|
+
"nautobot.extras.group_sync.group_sync",
|
|
236
250
|
)
|
|
237
251
|
# OAuth2/OIDC claim where the list of groups the authenticating user is a part of
|
|
238
252
|
SSO_CLAIMS_GROUP = os.getenv("NAUTOBOT_SSO_CLAIMS_GROUP", "groups")
|
|
@@ -718,6 +732,13 @@ CONSTANCE_ADDITIONAL_FIELDS = {
|
|
|
718
732
|
"required": False,
|
|
719
733
|
},
|
|
720
734
|
],
|
|
735
|
+
"optional_date_field": [
|
|
736
|
+
"django.forms.DateField",
|
|
737
|
+
{
|
|
738
|
+
"widget": "nautobot.core.forms.widgets.DatePicker",
|
|
739
|
+
"required": False,
|
|
740
|
+
},
|
|
741
|
+
],
|
|
721
742
|
}
|
|
722
743
|
|
|
723
744
|
CONSTANCE_CONFIG = {
|
|
@@ -803,6 +824,12 @@ CONSTANCE_CONFIG = {
|
|
|
803
824
|
# Use custom field type defined above
|
|
804
825
|
field_type="optional_json_field",
|
|
805
826
|
),
|
|
827
|
+
"NTC_SUPPORT_CONTRACT_EXPIRATION_DATE": ConstanceConfigItem(
|
|
828
|
+
default="",
|
|
829
|
+
help_text="Expiration date for an active Nautobot support contract with Network to Code. "
|
|
830
|
+
"This value is displayed in the About page to provide additional support information.",
|
|
831
|
+
field_type="optional_date_field",
|
|
832
|
+
),
|
|
806
833
|
"PREFER_IPV4": ConstanceConfigItem(
|
|
807
834
|
default=False,
|
|
808
835
|
help_text="Whether to prefer IPv4 primary addresses over IPv6 primary addresses for devices.",
|
|
@@ -856,7 +883,7 @@ CONSTANCE_CONFIG_FIELDSETS = {
|
|
|
856
883
|
"RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT",
|
|
857
884
|
],
|
|
858
885
|
"Release Checking": ["RELEASE_CHECK_URL", "RELEASE_CHECK_TIMEOUT"],
|
|
859
|
-
"User Interface": ["SUPPORT_MESSAGE"],
|
|
886
|
+
"User Interface": ["SUPPORT_MESSAGE", "NTC_SUPPORT_CONTRACT_EXPIRATION_DATE"],
|
|
860
887
|
"Debugging": ["ALLOW_REQUEST_PROFILING"],
|
|
861
888
|
}
|
|
862
889
|
|
nautobot/core/settings.yaml
CHANGED
|
@@ -6,6 +6,8 @@ definitions:
|
|
|
6
6
|
type: "string"
|
|
7
7
|
callable:
|
|
8
8
|
type: "string"
|
|
9
|
+
date:
|
|
10
|
+
type: "string"
|
|
9
11
|
regex:
|
|
10
12
|
type: "string"
|
|
11
13
|
relative_path:
|
|
@@ -1491,6 +1493,17 @@ properties:
|
|
|
1491
1493
|
is_constance_config: true
|
|
1492
1494
|
type: "object"
|
|
1493
1495
|
version_added: "1.6.0"
|
|
1496
|
+
NTC_SUPPORT_CONTRACT_EXPIRATION_DATE:
|
|
1497
|
+
"$ref": "#/definitions/date"
|
|
1498
|
+
default: ""
|
|
1499
|
+
description: >-
|
|
1500
|
+
Expiration date for an active Nautobot support contract with Network to Code.
|
|
1501
|
+
This value is displayed in the "About" page to provide additional support information.
|
|
1502
|
+
details: >-
|
|
1503
|
+
If specified as an environment variable, use ISO 8601 (`YYYY-MM-DD`) format.
|
|
1504
|
+
environment_variable: "NAUTOBOT_NTC_SUPPORT_CONTRACT_EXPIRATION_DATE"
|
|
1505
|
+
is_constance_config: true
|
|
1506
|
+
version_added: "2.4.0"
|
|
1494
1507
|
PAGINATE_COUNT:
|
|
1495
1508
|
default: 50
|
|
1496
1509
|
description: >-
|
|
@@ -1559,6 +1572,14 @@ properties:
|
|
|
1559
1572
|
environment_variable: "NAUTOBOT_PREFER_IPV4"
|
|
1560
1573
|
is_constance_config: true
|
|
1561
1574
|
type: "boolean"
|
|
1575
|
+
PUBLISH_ROBOTS_TXT:
|
|
1576
|
+
default: true
|
|
1577
|
+
description: >-
|
|
1578
|
+
Setting this to true causes Nautobot to publish a `robots.txt` that discourages indexing by web crawlers.
|
|
1579
|
+
Irrelevant if deployed behind a firewall.
|
|
1580
|
+
environment_variable: "NAUTOBOT_PUBLISH_ROBOTS_TXT"
|
|
1581
|
+
type: "boolean"
|
|
1582
|
+
version_added: "2.3.15"
|
|
1562
1583
|
RACK_ELEVATION_DEFAULT_UNIT_HEIGHT:
|
|
1563
1584
|
default: 22
|
|
1564
1585
|
description: >-
|