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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from datetime import datetime, timedelta, timezone
|
|
2
2
|
import os
|
|
3
|
+
import shutil
|
|
3
4
|
import tempfile
|
|
4
5
|
from unittest import expectedFailure, mock
|
|
5
6
|
import uuid
|
|
@@ -17,6 +18,7 @@ from django.test import override_settings
|
|
|
17
18
|
from django.test.utils import isolate_apps
|
|
18
19
|
from django.utils.timezone import get_default_timezone, now
|
|
19
20
|
from django_celery_beat.tzcrontab import TzAwareCrontab
|
|
21
|
+
from git import GitCommandError
|
|
20
22
|
from jinja2.exceptions import TemplateAssertionError, TemplateSyntaxError
|
|
21
23
|
import time_machine
|
|
22
24
|
|
|
@@ -48,6 +50,7 @@ from nautobot.extras.constants import (
|
|
|
48
50
|
JOB_LOG_MAX_LOG_OBJECT_LENGTH,
|
|
49
51
|
JOB_OVERRIDABLE_FIELDS,
|
|
50
52
|
)
|
|
53
|
+
from nautobot.extras.datasources.registry import get_datasource_contents
|
|
51
54
|
from nautobot.extras.jobs import get_job
|
|
52
55
|
from nautobot.extras.models import (
|
|
53
56
|
ComputedField,
|
|
@@ -83,6 +86,7 @@ from nautobot.extras.models import (
|
|
|
83
86
|
from nautobot.extras.models.statuses import StatusModel
|
|
84
87
|
from nautobot.extras.registry import registry
|
|
85
88
|
from nautobot.extras.secrets.exceptions import SecretParametersError, SecretProviderError, SecretValueNotFoundError
|
|
89
|
+
from nautobot.extras.tests.git_helper import create_and_populate_git_repository
|
|
86
90
|
from nautobot.ipam.models import IPAddress
|
|
87
91
|
from nautobot.tenancy.models import Tenant
|
|
88
92
|
from nautobot.virtualization.models import (
|
|
@@ -1072,6 +1076,285 @@ class GitRepositoryTest(ModelTestCases.BaseModelTestCase):
|
|
|
1072
1076
|
self.repo.remote_url = "http://some-private-host/example.git"
|
|
1073
1077
|
self.repo.validated_save()
|
|
1074
1078
|
|
|
1079
|
+
def test_clone_to_directory_context_manager(self):
|
|
1080
|
+
"""Confirm that the clone_to_directory_context() context manager method works as expected."""
|
|
1081
|
+
try:
|
|
1082
|
+
specified_path = tempfile.mkdtemp()
|
|
1083
|
+
self.tempdir = tempfile.TemporaryDirectory() # pylint: disable=consider-using-with
|
|
1084
|
+
create_and_populate_git_repository(self.tempdir.name, divergent_branch="divergent-branch")
|
|
1085
|
+
self.repo_slug = "new_git_repo"
|
|
1086
|
+
self.repo = GitRepository(
|
|
1087
|
+
name="New Git Repository",
|
|
1088
|
+
slug=self.repo_slug,
|
|
1089
|
+
remote_url="file://"
|
|
1090
|
+
+ self.tempdir.name, # file:// URLs aren't permitted normally, but very useful here!
|
|
1091
|
+
branch="main",
|
|
1092
|
+
# Provide everything we know we can provide
|
|
1093
|
+
provided_contents=[
|
|
1094
|
+
entry.content_identifier for entry in get_datasource_contents("extras.gitrepository")
|
|
1095
|
+
],
|
|
1096
|
+
)
|
|
1097
|
+
self.repo.save()
|
|
1098
|
+
with self.subTest("Clone a repository with no path argument provided"):
|
|
1099
|
+
with self.repo.clone_to_directory_context() as path:
|
|
1100
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1101
|
+
self.assertTrue(path.startswith(tempfile.gettempdir()))
|
|
1102
|
+
self.assertTrue(os.path.exists(path))
|
|
1103
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1104
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema2.json"))
|
|
1105
|
+
self.assertFalse(os.path.exists(path))
|
|
1106
|
+
|
|
1107
|
+
with self.subTest("Clone a repository with a path argument provided"):
|
|
1108
|
+
with self.repo.clone_to_directory_context(path=specified_path) as path:
|
|
1109
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1110
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1111
|
+
self.assertTrue(os.path.exists(path))
|
|
1112
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1113
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema2.json"))
|
|
1114
|
+
# Temp directory is cleaned up after the context manager exits
|
|
1115
|
+
self.assertFalse(os.path.exists(path))
|
|
1116
|
+
|
|
1117
|
+
with self.subTest("Clone a repository with the branch argument provided"):
|
|
1118
|
+
with self.repo.clone_to_directory_context(path=specified_path, branch="main") as path:
|
|
1119
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1120
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1121
|
+
self.assertTrue(os.path.exists(path))
|
|
1122
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1123
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema2.json"))
|
|
1124
|
+
# Temp directory is cleaned up after the context manager exits
|
|
1125
|
+
self.assertFalse(os.path.exists(path))
|
|
1126
|
+
|
|
1127
|
+
with self.subTest("Clone a repository with non-default branch provided"):
|
|
1128
|
+
with self.repo.clone_to_directory_context(path=specified_path, branch="empty-repo") as path:
|
|
1129
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1130
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1131
|
+
self.assertTrue(os.path.exists(path))
|
|
1132
|
+
# empty-repo should contain no files
|
|
1133
|
+
self.assertFalse(os.path.exists(path + "/config_context_schemas"))
|
|
1134
|
+
self.assertFalse(os.path.exists(path + "/config_contexts"))
|
|
1135
|
+
# Temp directory is cleaned up after the context manager exits
|
|
1136
|
+
self.assertFalse(os.path.exists(path))
|
|
1137
|
+
|
|
1138
|
+
with self.subTest("Clone a repository with divergent branch provided"):
|
|
1139
|
+
with self.repo.clone_to_directory_context(path=specified_path, branch="divergent-branch") as path:
|
|
1140
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1141
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1142
|
+
self.assertTrue(os.path.exists(path))
|
|
1143
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1144
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema2.json"))
|
|
1145
|
+
# Temp directory is cleaned up after the context manager exits
|
|
1146
|
+
self.assertFalse(os.path.exists(path))
|
|
1147
|
+
|
|
1148
|
+
with self.subTest("Clone a repository with the head argument provided"):
|
|
1149
|
+
with self.repo.clone_to_directory_context(path=specified_path, head="valid-files") as path:
|
|
1150
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1151
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1152
|
+
self.assertTrue(os.path.exists(path))
|
|
1153
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/schema-1.yaml"))
|
|
1154
|
+
self.assertTrue(os.path.exists(path + "/config_contexts/context.yaml"))
|
|
1155
|
+
# Temp directory is cleaned up after the context manager exits
|
|
1156
|
+
self.assertFalse(os.path.exists(path))
|
|
1157
|
+
|
|
1158
|
+
with self.subTest("Clone a repository with depth argument provided"):
|
|
1159
|
+
with self.repo.clone_to_directory_context(path=specified_path, depth=1) as path:
|
|
1160
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1161
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1162
|
+
self.assertTrue(os.path.exists(path))
|
|
1163
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1164
|
+
self.assertTrue(os.path.exists(path + "/config_contexts/badcontext2.json"))
|
|
1165
|
+
# Temp directory is cleaned up after the context manager exits
|
|
1166
|
+
self.assertFalse(os.path.exists(path))
|
|
1167
|
+
|
|
1168
|
+
with self.subTest("Clone a shallow repository with depth and valid head arguments provided"):
|
|
1169
|
+
with self.repo.clone_to_directory_context(
|
|
1170
|
+
path=specified_path, depth=1, head="divergent-branch-tag"
|
|
1171
|
+
) as path:
|
|
1172
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1173
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1174
|
+
self.assertTrue(os.path.exists(path))
|
|
1175
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1176
|
+
self.assertTrue(os.path.exists(path + "/config_contexts/badcontext2.json"))
|
|
1177
|
+
# Temp directory is cleaned up after the context manager exits
|
|
1178
|
+
self.assertFalse(os.path.exists(path))
|
|
1179
|
+
|
|
1180
|
+
with self.subTest("Clone a shallow repository with depth and invalid head arguments provided"):
|
|
1181
|
+
with self.assertRaisesRegex(GitCommandError, "malformed object name valid-files"):
|
|
1182
|
+
# Shallow copy a repo should only have the latest commit
|
|
1183
|
+
with self.repo.clone_to_directory_context(path=specified_path, depth=1, head="valid-files") as path:
|
|
1184
|
+
pass
|
|
1185
|
+
|
|
1186
|
+
with self.subTest("Clone a shallow repository with depth and valid branch arguments provided"):
|
|
1187
|
+
with self.repo.clone_to_directory_context(path=specified_path, depth=1, branch="main") as path:
|
|
1188
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1189
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1190
|
+
self.assertTrue(os.path.exists(path))
|
|
1191
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1192
|
+
self.assertTrue(os.path.exists(path + "/config_contexts/badcontext2.json"))
|
|
1193
|
+
# Temp directory is cleaned up after the context manager exits
|
|
1194
|
+
self.assertFalse(os.path.exists(path))
|
|
1195
|
+
|
|
1196
|
+
with self.subTest("Clone a shallow repository with depth and divergent branch arguments provided"):
|
|
1197
|
+
with self.repo.clone_to_directory_context(
|
|
1198
|
+
path=specified_path, depth=1, branch="divergent-branch"
|
|
1199
|
+
) as path:
|
|
1200
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1201
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1202
|
+
self.assertTrue(os.path.exists(path))
|
|
1203
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1204
|
+
self.assertTrue(os.path.exists(path + "/config_contexts/badcontext2.json"))
|
|
1205
|
+
# Temp directory is cleaned up after the context manager exits
|
|
1206
|
+
self.assertFalse(os.path.exists(path))
|
|
1207
|
+
|
|
1208
|
+
with self.subTest("Assert a GitCommandError is raised when an invalid commit hash is provided"):
|
|
1209
|
+
with self.assertRaisesRegex(GitCommandError, "malformed object name non-existent"):
|
|
1210
|
+
with self.repo.clone_to_directory_context(path=specified_path, head="non-existent") as path:
|
|
1211
|
+
pass
|
|
1212
|
+
|
|
1213
|
+
with self.subTest("Assert a value error is raised when branch and head are both provided"):
|
|
1214
|
+
with self.assertRaisesRegex(ValueError, "Cannot specify both branch and head"):
|
|
1215
|
+
with self.repo.clone_to_directory_context(branch="main", head="valid-files") as path:
|
|
1216
|
+
pass
|
|
1217
|
+
finally:
|
|
1218
|
+
shutil.rmtree(specified_path, ignore_errors=True)
|
|
1219
|
+
shutil.rmtree(self.tempdir.name, ignore_errors=True)
|
|
1220
|
+
|
|
1221
|
+
def test_clone_to_directory_helper_methods(self):
|
|
1222
|
+
"""Confirm that the clone_to_directory()/cleanup_cloned_directory() methods work as expected."""
|
|
1223
|
+
try:
|
|
1224
|
+
specified_path = tempfile.mkdtemp()
|
|
1225
|
+
self.tempdir = tempfile.TemporaryDirectory() # pylint: disable=consider-using-with
|
|
1226
|
+
create_and_populate_git_repository(self.tempdir.name, divergent_branch="divergent-branch")
|
|
1227
|
+
self.repo_slug = "new_git_repo"
|
|
1228
|
+
self.repo = GitRepository(
|
|
1229
|
+
name="New Git Repository",
|
|
1230
|
+
slug=self.repo_slug,
|
|
1231
|
+
remote_url="file://"
|
|
1232
|
+
+ self.tempdir.name, # file:// URLs aren't permitted normally, but very useful here!
|
|
1233
|
+
branch="main",
|
|
1234
|
+
# Provide everything we know we can provide
|
|
1235
|
+
provided_contents=[
|
|
1236
|
+
entry.content_identifier for entry in get_datasource_contents("extras.gitrepository")
|
|
1237
|
+
],
|
|
1238
|
+
)
|
|
1239
|
+
self.repo.save()
|
|
1240
|
+
with self.subTest("Clone a repository with no path argument provided"):
|
|
1241
|
+
path = self.repo.clone_to_directory()
|
|
1242
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1243
|
+
self.assertTrue(path.startswith(tempfile.gettempdir()))
|
|
1244
|
+
self.assertTrue(os.path.exists(path))
|
|
1245
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1246
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema2.json"))
|
|
1247
|
+
self.repo.cleanup_cloned_directory(path)
|
|
1248
|
+
self.assertFalse(os.path.exists(path))
|
|
1249
|
+
|
|
1250
|
+
with self.subTest("Clone a repository with a path argument provided"):
|
|
1251
|
+
path = self.repo.clone_to_directory(path=specified_path)
|
|
1252
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1253
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1254
|
+
self.assertTrue(os.path.exists(path))
|
|
1255
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1256
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema2.json"))
|
|
1257
|
+
self.repo.cleanup_cloned_directory(path)
|
|
1258
|
+
self.assertFalse(os.path.exists(path))
|
|
1259
|
+
|
|
1260
|
+
with self.subTest("Clone a repository with the branch argument provided"):
|
|
1261
|
+
path = self.repo.clone_to_directory(path=specified_path, branch="main")
|
|
1262
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1263
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1264
|
+
self.assertTrue(os.path.exists(path))
|
|
1265
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1266
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema2.json"))
|
|
1267
|
+
self.repo.cleanup_cloned_directory(path)
|
|
1268
|
+
self.assertFalse(os.path.exists(path))
|
|
1269
|
+
|
|
1270
|
+
with self.subTest("Clone a repository with non-default branch provided"):
|
|
1271
|
+
path = self.repo.clone_to_directory(path=specified_path, branch="empty-repo")
|
|
1272
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1273
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1274
|
+
self.assertTrue(os.path.exists(path))
|
|
1275
|
+
self.assertFalse(os.path.exists(path + "/config_context_schemas"))
|
|
1276
|
+
self.assertFalse(os.path.exists(path + "/config_contexts"))
|
|
1277
|
+
self.repo.cleanup_cloned_directory(path)
|
|
1278
|
+
self.assertFalse(os.path.exists(path))
|
|
1279
|
+
|
|
1280
|
+
with self.subTest("Clone a repository with divergent branch provided"):
|
|
1281
|
+
path = self.repo.clone_to_directory(path=specified_path, branch="divergent-branch")
|
|
1282
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1283
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1284
|
+
self.assertTrue(os.path.exists(path))
|
|
1285
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas"))
|
|
1286
|
+
self.assertTrue(os.path.exists(path + "/config_contexts"))
|
|
1287
|
+
self.repo.cleanup_cloned_directory(path)
|
|
1288
|
+
self.assertFalse(os.path.exists(path))
|
|
1289
|
+
|
|
1290
|
+
with self.subTest("Clone a repository with the head argument provided"):
|
|
1291
|
+
path = self.repo.clone_to_directory(path=specified_path, head="valid-files")
|
|
1292
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1293
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1294
|
+
self.assertTrue(os.path.exists(path))
|
|
1295
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/schema-1.yaml"))
|
|
1296
|
+
self.assertTrue(os.path.exists(path + "/config_contexts/context.yaml"))
|
|
1297
|
+
self.repo.cleanup_cloned_directory(path)
|
|
1298
|
+
self.assertFalse(os.path.exists(path))
|
|
1299
|
+
|
|
1300
|
+
with self.subTest("Clone a repository with depth argument provided"):
|
|
1301
|
+
path = self.repo.clone_to_directory(path=specified_path, depth=1)
|
|
1302
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1303
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1304
|
+
self.assertTrue(os.path.exists(path))
|
|
1305
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1306
|
+
self.assertTrue(os.path.exists(path + "/config_contexts/badcontext2.json"))
|
|
1307
|
+
self.repo.cleanup_cloned_directory(path)
|
|
1308
|
+
self.assertFalse(os.path.exists(path))
|
|
1309
|
+
|
|
1310
|
+
with self.subTest("Clone a shallow repository with depth and valid head arguments provided"):
|
|
1311
|
+
path = self.repo.clone_to_directory(path=specified_path, depth=1, head="divergent-branch-tag")
|
|
1312
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1313
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1314
|
+
self.assertTrue(os.path.exists(path))
|
|
1315
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1316
|
+
self.assertTrue(os.path.exists(path + "/config_contexts/badcontext2.json"))
|
|
1317
|
+
self.repo.cleanup_cloned_directory(path)
|
|
1318
|
+
self.assertFalse(os.path.exists(path))
|
|
1319
|
+
|
|
1320
|
+
with self.subTest("Clone a shallow repository with depth and invalid head arguments provided"):
|
|
1321
|
+
with self.assertRaisesRegex(GitCommandError, "malformed object name valid-files"):
|
|
1322
|
+
# Shallow copy a repo should only have the latest commit
|
|
1323
|
+
path = self.repo.clone_to_directory(path=specified_path, depth=1, head="valid-files")
|
|
1324
|
+
self.repo.cleanup_cloned_directory(path)
|
|
1325
|
+
self.assertFalse(os.path.exists(path))
|
|
1326
|
+
|
|
1327
|
+
with self.subTest("Clone a shallow repository with depth and valid branch arguments provided"):
|
|
1328
|
+
path = self.repo.clone_to_directory(path=specified_path, depth=1, branch="main")
|
|
1329
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1330
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1331
|
+
self.assertTrue(os.path.exists(path))
|
|
1332
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1333
|
+
self.assertTrue(os.path.exists(path + "/config_contexts/badcontext2.json"))
|
|
1334
|
+
self.repo.cleanup_cloned_directory(path)
|
|
1335
|
+
self.assertFalse(os.path.exists(path))
|
|
1336
|
+
|
|
1337
|
+
with self.subTest("Clone a shallow repository with depth and divergent branch arguments provided"):
|
|
1338
|
+
path = self.repo.clone_to_directory(path=specified_path, depth=1, branch="divergent-branch")
|
|
1339
|
+
# assert that the temporary directory was created in the expected location i.e. /tmp/
|
|
1340
|
+
self.assertTrue(path.startswith(specified_path))
|
|
1341
|
+
self.assertTrue(os.path.exists(path))
|
|
1342
|
+
self.assertTrue(os.path.exists(path + "/config_context_schemas/badschema1.json"))
|
|
1343
|
+
self.assertTrue(os.path.exists(path + "/config_contexts/badcontext2.json"))
|
|
1344
|
+
self.repo.cleanup_cloned_directory(path)
|
|
1345
|
+
self.assertFalse(os.path.exists(path))
|
|
1346
|
+
|
|
1347
|
+
with self.subTest("Assert a GitCommandError is raised when an invalid commit hash is provided"):
|
|
1348
|
+
with self.assertRaisesRegex(GitCommandError, "malformed object name non-existent"):
|
|
1349
|
+
path = self.repo.clone_to_directory(path=specified_path, head="non-existent")
|
|
1350
|
+
|
|
1351
|
+
with self.subTest("Assert a ValuError is raised when branch and head are both provided"):
|
|
1352
|
+
with self.assertRaisesRegex(ValueError, "Cannot specify both branch and head"):
|
|
1353
|
+
path = self.repo.clone_to_directory(branch="main", head="valid-files")
|
|
1354
|
+
finally:
|
|
1355
|
+
shutil.rmtree(specified_path, ignore_errors=True)
|
|
1356
|
+
shutil.rmtree(self.tempdir.name, ignore_errors=True)
|
|
1357
|
+
|
|
1075
1358
|
|
|
1076
1359
|
class JobModelTest(ModelTestCases.BaseModelTestCase):
|
|
1077
1360
|
"""
|
|
@@ -1083,7 +1366,7 @@ class JobModelTest(ModelTestCases.BaseModelTestCase):
|
|
|
1083
1366
|
@classmethod
|
|
1084
1367
|
def setUpTestData(cls):
|
|
1085
1368
|
# JobModel instances are automatically instantiated at startup, so we just need to look them up.
|
|
1086
|
-
cls.local_job = JobModel.objects.get(job_class_name="
|
|
1369
|
+
cls.local_job = JobModel.objects.get(job_class_name="TestPassJob")
|
|
1087
1370
|
cls.job_containing_sensitive_variables = JobModel.objects.get(job_class_name="ExampleLoggingJob")
|
|
1088
1371
|
cls.app_job = JobModel.objects.get(job_class_name="ExampleJob")
|
|
1089
1372
|
|
|
@@ -1095,7 +1378,7 @@ class JobModelTest(ModelTestCases.BaseModelTestCase):
|
|
|
1095
1378
|
self.assertEqual(self.app_job.job_class, ExampleJob)
|
|
1096
1379
|
|
|
1097
1380
|
def test_class_path(self):
|
|
1098
|
-
self.assertEqual(self.local_job.class_path, "pass.
|
|
1381
|
+
self.assertEqual(self.local_job.class_path, "pass.TestPassJob")
|
|
1099
1382
|
self.assertIsNotNone(self.local_job.job_class)
|
|
1100
1383
|
self.assertEqual(self.local_job.class_path, self.local_job.job_class.class_path)
|
|
1101
1384
|
|
|
@@ -1832,11 +2115,11 @@ class ScheduledJobTest(ModelTestCases.BaseModelTestCase):
|
|
|
1832
2115
|
|
|
1833
2116
|
def setUp(self):
|
|
1834
2117
|
self.user = User.objects.create_user(username="scheduledjobuser")
|
|
1835
|
-
self.job_model = JobModel.objects.get(name="
|
|
2118
|
+
self.job_model = JobModel.objects.get(name="TestPassJob")
|
|
1836
2119
|
|
|
1837
2120
|
self.daily_utc_job = ScheduledJob.objects.create(
|
|
1838
2121
|
name="Daily UTC Job",
|
|
1839
|
-
task="pass.
|
|
2122
|
+
task="pass.TestPassJob",
|
|
1840
2123
|
job_model=self.job_model,
|
|
1841
2124
|
interval=JobExecutionType.TYPE_DAILY,
|
|
1842
2125
|
start_time=datetime(year=2050, month=1, day=22, hour=17, minute=0, tzinfo=get_default_timezone()),
|
|
@@ -1844,7 +2127,7 @@ class ScheduledJobTest(ModelTestCases.BaseModelTestCase):
|
|
|
1844
2127
|
)
|
|
1845
2128
|
self.daily_est_job = ScheduledJob.objects.create(
|
|
1846
2129
|
name="Daily EST Job",
|
|
1847
|
-
task="pass.
|
|
2130
|
+
task="pass.TestPassJob",
|
|
1848
2131
|
job_model=self.job_model,
|
|
1849
2132
|
interval=JobExecutionType.TYPE_DAILY,
|
|
1850
2133
|
start_time=datetime(year=2050, month=1, day=22, hour=17, minute=0, tzinfo=ZoneInfo("America/New_York")),
|
|
@@ -1859,7 +2142,7 @@ class ScheduledJobTest(ModelTestCases.BaseModelTestCase):
|
|
|
1859
2142
|
)
|
|
1860
2143
|
self.crontab_est_job = ScheduledJob.objects.create(
|
|
1861
2144
|
name="Crontab EST Job",
|
|
1862
|
-
task="pass.
|
|
2145
|
+
task="pass.TestPassJob",
|
|
1863
2146
|
job_model=self.job_model,
|
|
1864
2147
|
interval=JobExecutionType.TYPE_CUSTOM,
|
|
1865
2148
|
start_time=datetime(year=2050, month=1, day=22, hour=17, minute=0, tzinfo=ZoneInfo("America/New_York")),
|
|
@@ -1868,7 +2151,7 @@ class ScheduledJobTest(ModelTestCases.BaseModelTestCase):
|
|
|
1868
2151
|
)
|
|
1869
2152
|
self.one_off_utc_job = ScheduledJob.objects.create(
|
|
1870
2153
|
name="One-off UTC Job",
|
|
1871
|
-
task="pass.
|
|
2154
|
+
task="pass.TestPassJob",
|
|
1872
2155
|
job_model=self.job_model,
|
|
1873
2156
|
interval=JobExecutionType.TYPE_FUTURE,
|
|
1874
2157
|
start_time=datetime(year=2050, month=1, day=22, hour=0, minute=0, tzinfo=ZoneInfo("UTC")),
|
|
@@ -2015,7 +2298,7 @@ class ScheduledJobTest(ModelTestCases.BaseModelTestCase):
|
|
|
2015
2298
|
"""Test that TYPE_CUSTOM behavior around DST is as expected."""
|
|
2016
2299
|
cronjob = ScheduledJob.objects.create(
|
|
2017
2300
|
name="DST Aware Cronjob",
|
|
2018
|
-
task="pass.
|
|
2301
|
+
task="pass.TestPassJob",
|
|
2019
2302
|
job_model=self.job_model,
|
|
2020
2303
|
enabled=False,
|
|
2021
2304
|
interval=JobExecutionType.TYPE_CUSTOM,
|
|
@@ -2070,7 +2353,7 @@ class ScheduledJobTest(ModelTestCases.BaseModelTestCase):
|
|
|
2070
2353
|
"""Test the interaction of TYPE_DAILY around DST."""
|
|
2071
2354
|
daily = ScheduledJob.objects.create(
|
|
2072
2355
|
name="Daily Job",
|
|
2073
|
-
task="pass.
|
|
2356
|
+
task="pass.TestPassJob",
|
|
2074
2357
|
job_model=self.job_model,
|
|
2075
2358
|
enabled=False,
|
|
2076
2359
|
interval=JobExecutionType.TYPE_DAILY,
|
|
@@ -2146,6 +2429,12 @@ class ScheduledJobTest(ModelTestCases.BaseModelTestCase):
|
|
|
2146
2429
|
# entry = NautobotScheduleEntry(model=sj)
|
|
2147
2430
|
# scheduler = NautobotDatabaseScheduler(app=entry.app)
|
|
2148
2431
|
# scheduler.apply_async(entry=entry, producer=None, advance=False)
|
|
2432
|
+
# Check scheduled job runs correctly with no job queue
|
|
2433
|
+
# sj.job_queue = None
|
|
2434
|
+
# sj.save()
|
|
2435
|
+
# entry = NautobotScheduleEntry(model=sj)
|
|
2436
|
+
# scheduler = NautobotDatabaseScheduler(app=entry.app)
|
|
2437
|
+
# scheduler.apply_async(entry=entry, producer=None, advance=False)
|
|
2149
2438
|
|
|
2150
2439
|
|
|
2151
2440
|
class SecretTest(ModelTestCases.BaseModelTestCase):
|
|
@@ -2638,7 +2927,7 @@ class JobLogEntryTest(TestCase): # TODO: change to BaseModelTestCase
|
|
|
2638
2927
|
|
|
2639
2928
|
def setUp(self):
|
|
2640
2929
|
module = "pass"
|
|
2641
|
-
name = "
|
|
2930
|
+
name = "TestPassJob"
|
|
2642
2931
|
job_class = get_job(f"{module}.{name}")
|
|
2643
2932
|
|
|
2644
2933
|
self.job_result = JobResult.objects.create(name=job_class.class_path, user=None)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
from unittest import mock, skip
|
|
1
|
+
from unittest import mock, skip
|
|
2
2
|
|
|
3
|
+
from django.apps import apps
|
|
3
4
|
from django.conf import settings
|
|
4
5
|
from django.contrib.contenttypes.models import ContentType
|
|
5
6
|
from django.core.exceptions import ValidationError
|
|
@@ -21,6 +22,7 @@ from nautobot.extras.models import CustomField, Relationship, RelationshipAssoci
|
|
|
21
22
|
from nautobot.extras.plugins.exceptions import PluginImproperlyConfigured
|
|
22
23
|
from nautobot.extras.plugins.utils import load_plugin
|
|
23
24
|
from nautobot.extras.plugins.validators import wrap_model_clean_methods
|
|
25
|
+
from nautobot.extras.plugins.views import extract_app_data
|
|
24
26
|
from nautobot.extras.registry import DatasourceContent, registry
|
|
25
27
|
from nautobot.ipam.models import IPAddress, Namespace, Prefix
|
|
26
28
|
from nautobot.tenancy.filters import TenantFilterSet
|
|
@@ -315,6 +317,61 @@ class AppListViewTest(TestCase):
|
|
|
315
317
|
response_body = extract_page_body(response.content.decode(response.charset)).lower()
|
|
316
318
|
self.assertIn("example app", response_body, msg=response_body)
|
|
317
319
|
|
|
320
|
+
def test_extract_app_data(self):
|
|
321
|
+
app_config = apps.get_app_config("example_app")
|
|
322
|
+
# Without a corresponding entry in marketplace_data
|
|
323
|
+
self.assertEqual(
|
|
324
|
+
extract_app_data(app_config, {"apps": []}),
|
|
325
|
+
{
|
|
326
|
+
"name": "Example Nautobot App",
|
|
327
|
+
"package": "example_app",
|
|
328
|
+
"app_label": "example_app",
|
|
329
|
+
"author": "Nautobot development team",
|
|
330
|
+
"author_email": "nautobot@example.com",
|
|
331
|
+
"headline": "For testing purposes only",
|
|
332
|
+
"description": "For testing purposes only",
|
|
333
|
+
"version": "1.0.0",
|
|
334
|
+
"home_url": "plugins:example_app:home",
|
|
335
|
+
"config_url": "plugins:example_app:config",
|
|
336
|
+
"docs_url": "plugins:example_app:docs",
|
|
337
|
+
},
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
# With a corresponding entry in marketplace_data
|
|
341
|
+
mock_marketplace_data = {
|
|
342
|
+
"apps": [
|
|
343
|
+
{
|
|
344
|
+
"name": "Nautobot Example App",
|
|
345
|
+
"use_cases": ["Example", "Development"],
|
|
346
|
+
"requires": [],
|
|
347
|
+
"docs": "https://example.com/docs/example_app/",
|
|
348
|
+
"headline": "Demonstrate and test various parts of Nautobot App APIs and functionality.",
|
|
349
|
+
"description": "An example of the kinds of things a Nautobot App can do, including ...",
|
|
350
|
+
"package_name": "example_app",
|
|
351
|
+
"author": "Network to Code (NTC)",
|
|
352
|
+
"availability": "Open Source",
|
|
353
|
+
"icon": "...",
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
}
|
|
357
|
+
self.assertEqual(
|
|
358
|
+
extract_app_data(app_config, mock_marketplace_data),
|
|
359
|
+
{
|
|
360
|
+
"name": "Nautobot Example App",
|
|
361
|
+
"package": "example_app",
|
|
362
|
+
"app_label": "example_app",
|
|
363
|
+
"author": "Network to Code (NTC)",
|
|
364
|
+
"author_email": "nautobot@example.com",
|
|
365
|
+
"availability": "Open Source",
|
|
366
|
+
"headline": "Demonstrate and test various parts of Nautobot App APIs and functionality.",
|
|
367
|
+
"description": "An example of the kinds of things a Nautobot App can do, including ...",
|
|
368
|
+
"version": "1.0.0",
|
|
369
|
+
"home_url": "plugins:example_app:home",
|
|
370
|
+
"config_url": "plugins:example_app:config",
|
|
371
|
+
"docs_url": "plugins:example_app:docs",
|
|
372
|
+
},
|
|
373
|
+
)
|
|
374
|
+
|
|
318
375
|
|
|
319
376
|
class PluginDetailViewTest(TestCase):
|
|
320
377
|
def test_view_detail_anonymous(self):
|
|
@@ -800,10 +857,6 @@ class TestAppCoreViewOverrides(TestCase):
|
|
|
800
857
|
)
|
|
801
858
|
|
|
802
859
|
|
|
803
|
-
@skipIf(
|
|
804
|
-
"example_plugin" not in settings.PLUGINS,
|
|
805
|
-
"example_plugin not in settings.PLUGINS",
|
|
806
|
-
)
|
|
807
860
|
class PluginTemplateExtensionsTest(TestCase):
|
|
808
861
|
"""
|
|
809
862
|
Test that registered TemplateExtensions inject content as expected
|
|
@@ -823,19 +876,19 @@ class PluginTemplateExtensionsTest(TestCase):
|
|
|
823
876
|
def test_detail_view_buttons(self):
|
|
824
877
|
response = self.client.get(reverse("dcim:location", kwargs={"pk": self.location.pk}))
|
|
825
878
|
response_body = extract_page_body(response.content.decode(response.charset))
|
|
826
|
-
self.assertIn("LOCATION CONTENT - BUTTONS", response_body, msg=response_body)
|
|
879
|
+
self.assertIn("APP INJECTED LOCATION CONTENT - BUTTONS", response_body, msg=response_body)
|
|
827
880
|
|
|
828
881
|
def test_detail_view_left_page(self):
|
|
829
882
|
response = self.client.get(reverse("dcim:location", kwargs={"pk": self.location.pk}))
|
|
830
883
|
response_body = extract_page_body(response.content.decode(response.charset))
|
|
831
|
-
self.assertIn("
|
|
884
|
+
self.assertIn("App Injected Content - Left", response_body, msg=response_body)
|
|
832
885
|
|
|
833
886
|
def test_detail_view_right_page(self):
|
|
834
887
|
response = self.client.get(reverse("dcim:location", kwargs={"pk": self.location.pk}))
|
|
835
888
|
response_body = extract_page_body(response.content.decode(response.charset))
|
|
836
|
-
self.assertIn("
|
|
889
|
+
self.assertIn("App Injected Content - Right", response_body, msg=response_body)
|
|
837
890
|
|
|
838
891
|
def test_detail_view_full_width_page(self):
|
|
839
892
|
response = self.client.get(reverse("dcim:location", kwargs={"pk": self.location.pk}))
|
|
840
893
|
response_body = extract_page_body(response.content.decode(response.charset))
|
|
841
|
-
self.assertIn("
|
|
894
|
+
self.assertIn("App Injected Content - Full Width", response_body, msg=response_body)
|