nautobot 2.3.15b1__py3-none-any.whl → 2.4.0__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/__init__.py +15 -0
- nautobot/apps/__init__.py +1 -1
- nautobot/apps/api.py +8 -10
- nautobot/apps/change_logging.py +2 -2
- nautobot/apps/choices.py +4 -4
- nautobot/apps/config.py +32 -3
- nautobot/apps/events.py +19 -0
- nautobot/apps/exceptions.py +0 -2
- 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 +44 -9
- nautobot/apps/utils.py +7 -15
- nautobot/apps/views.py +8 -6
- nautobot/circuits/api/serializers.py +1 -0
- nautobot/circuits/api/views.py +4 -8
- nautobot/circuits/navigation.py +0 -57
- nautobot/circuits/templates/circuits/circuit_create.html +1 -7
- nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -71
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -64
- nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +40 -0
- nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +26 -0
- nautobot/circuits/templates/circuits/provider_retrieve.html +0 -76
- nautobot/circuits/tests/integration/test_relationships.py +33 -24
- nautobot/circuits/tests/test_filters.py +4 -8
- nautobot/circuits/views.py +143 -26
- nautobot/cloud/api/views.py +6 -10
- nautobot/cloud/factory.py +4 -1
- nautobot/cloud/models.py +1 -1
- nautobot/cloud/tests/test_filters.py +5 -4
- 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/metadata.py +28 -256
- nautobot/core/api/pagination.py +3 -2
- nautobot/core/api/renderers.py +3 -0
- nautobot/core/api/schema.py +13 -2
- nautobot/core/api/serializers.py +54 -268
- nautobot/core/api/urls.py +3 -4
- nautobot/core/api/utils.py +0 -62
- nautobot/core/api/views.py +102 -159
- nautobot/core/apps/__init__.py +22 -575
- nautobot/core/celery/__init__.py +13 -0
- nautobot/core/celery/schedulers.py +48 -3
- nautobot/core/choices.py +2 -2
- nautobot/core/cli/__init__.py +8 -0
- nautobot/core/constants.py +7 -0
- nautobot/core/events/__init__.py +116 -0
- nautobot/core/events/base.py +27 -0
- nautobot/core/events/exceptions.py +10 -0
- nautobot/core/events/redis_broker.py +48 -0
- nautobot/core/events/syslog_broker.py +19 -0
- nautobot/core/exceptions.py +0 -6
- nautobot/core/filters.py +19 -16
- nautobot/core/forms/__init__.py +19 -19
- nautobot/core/forms/fields.py +62 -14
- nautobot/core/forms/forms.py +33 -2
- nautobot/core/forms/utils.py +2 -1
- nautobot/core/graphql/schema.py +3 -1
- nautobot/core/graphql/types.py +1 -1
- nautobot/core/jobs/__init__.py +28 -7
- nautobot/core/jobs/bulk_actions.py +248 -0
- nautobot/core/jobs/cleanup.py +2 -2
- nautobot/core/jobs/groups.py +1 -1
- nautobot/core/management/commands/generate_test_data.py +21 -0
- nautobot/core/management/commands/validate_models.py +1 -1
- nautobot/core/middleware.py +16 -0
- nautobot/core/models/__init__.py +1 -1
- nautobot/core/models/fields.py +11 -7
- nautobot/core/models/query_functions.py +2 -2
- nautobot/core/models/tree_queries.py +2 -2
- nautobot/core/settings.py +71 -4
- nautobot/core/settings.yaml +107 -0
- nautobot/core/tables.py +15 -51
- nautobot/core/tasks.py +1 -1
- nautobot/core/templates/about.html +67 -0
- nautobot/core/templates/components/button/default.html +7 -0
- nautobot/core/templates/components/button/dropdown.html +20 -0
- nautobot/core/templates/components/layout/one_over_two.html +19 -0
- nautobot/core/templates/components/layout/two_over_one.html +19 -0
- nautobot/core/templates/components/panel/body_content_data_table.html +27 -0
- nautobot/core/templates/components/panel/body_content_objects_table.html +4 -0
- nautobot/core/templates/components/panel/body_content_tags.html +6 -0
- nautobot/core/templates/components/panel/body_content_text.html +12 -0
- nautobot/core/templates/components/panel/body_wrapper_generic.html +3 -0
- nautobot/core/templates/components/panel/body_wrapper_key_value_table.html +3 -0
- nautobot/core/templates/components/panel/body_wrapper_table.html +3 -0
- nautobot/core/templates/components/panel/footer_contacts_table.html +20 -0
- nautobot/core/templates/components/panel/footer_content_table.html +14 -0
- nautobot/core/templates/components/panel/grouping_toggle.html +14 -0
- nautobot/core/templates/components/panel/header_extra_content_table.html +3 -0
- nautobot/core/templates/components/panel/panel.html +16 -0
- nautobot/core/templates/components/panel/stats_panel_body.html +8 -0
- nautobot/core/templates/components/tab/content_wrapper.html +3 -0
- nautobot/core/templates/components/tab/label_wrapper.html +5 -0
- nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +3 -0
- nautobot/core/templates/generic/object_retrieve.html +28 -17
- nautobot/core/templates/inc/computed_fields/panel_data.html +4 -7
- nautobot/core/templates/inc/custom_fields/panel.html +2 -2
- nautobot/core/templates/inc/custom_fields/panel_data.html +4 -7
- nautobot/core/templates/inc/footer.html +1 -0
- nautobot/core/templates/inc/media.html +3 -0
- nautobot/core/templates/inc/nav_menu.html +2 -1
- nautobot/core/templates/inc/relationships_panel.html +1 -1
- 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 +16 -0
- nautobot/core/templates/panel_table.html +12 -0
- nautobot/core/templates/utilities/render_jinja2.html +117 -0
- nautobot/core/templates/utilities/templatetags/tag.html +1 -1
- nautobot/core/templates/utilities/theme_preview.html +7 -0
- nautobot/core/templatetags/helpers.py +104 -6
- nautobot/core/templatetags/ui_framework.py +40 -0
- nautobot/core/testing/__init__.py +8 -8
- nautobot/core/testing/api.py +187 -137
- nautobot/core/testing/context.py +18 -0
- nautobot/core/testing/filters.py +44 -34
- nautobot/core/testing/forms.py +2 -0
- nautobot/core/testing/views.py +68 -146
- 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 +2 -1
- nautobot/core/tests/nautobot_config.py +198 -0
- nautobot/core/tests/runner.py +3 -3
- nautobot/core/tests/test_api.py +154 -176
- nautobot/core/tests/test_events.py +214 -0
- nautobot/core/tests/test_forms.py +1 -0
- nautobot/core/tests/test_jinja_filters.py +1 -0
- nautobot/core/tests/test_jobs.py +387 -14
- nautobot/core/tests/test_navigations.py +7 -241
- nautobot/core/tests/test_settings_schema.py +7 -0
- nautobot/core/tests/test_tables.py +100 -0
- nautobot/core/tests/test_templatetags_helpers.py +16 -0
- nautobot/core/tests/test_ui.py +150 -0
- nautobot/core/tests/test_utils.py +55 -18
- nautobot/core/tests/test_views.py +153 -5
- nautobot/core/ui/__init__.py +0 -0
- nautobot/core/ui/base.py +11 -0
- nautobot/core/ui/choices.py +44 -0
- nautobot/core/ui/homepage.py +167 -0
- nautobot/core/ui/nav.py +280 -0
- nautobot/core/ui/object_detail.py +1855 -0
- nautobot/core/ui/utils.py +36 -0
- nautobot/core/urls.py +15 -0
- nautobot/core/utils/config.py +30 -3
- nautobot/core/utils/lookup.py +12 -2
- nautobot/core/utils/querysets.py +64 -0
- nautobot/core/utils/requests.py +24 -9
- nautobot/core/views/__init__.py +48 -1
- nautobot/core/views/generic.py +82 -177
- nautobot/core/views/mixins.py +98 -38
- nautobot/core/views/paginator.py +8 -5
- nautobot/core/views/renderers.py +9 -9
- nautobot/core/views/utils.py +11 -0
- nautobot/core/wsgi.py +3 -3
- nautobot/dcim/api/serializers.py +82 -189
- nautobot/dcim/api/urls.py +5 -0
- nautobot/dcim/api/views.py +57 -110
- nautobot/dcim/apps.py +1 -0
- nautobot/dcim/choices.py +28 -0
- nautobot/dcim/factory.py +58 -0
- nautobot/dcim/filters/__init__.py +204 -2
- nautobot/dcim/forms.py +221 -9
- nautobot/dcim/graphql/types.py +2 -2
- nautobot/dcim/migrations/0063_interfacevdcassignment_virtualdevicecontext_and_more.py +165 -0
- nautobot/dcim/migrations/0064_virtualdevicecontext_status_data_migration.py +28 -0
- nautobot/dcim/migrations/0065_controller_capabilities_and_more.py +29 -0
- nautobot/dcim/migrations/0066_controllermanageddevicegroup_radio_profiles_and_more.py +33 -0
- nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
- nautobot/dcim/models/__init__.py +5 -1
- nautobot/dcim/models/device_component_templates.py +2 -2
- nautobot/dcim/models/device_components.py +22 -20
- nautobot/dcim/models/devices.py +181 -3
- nautobot/dcim/models/locations.py +3 -3
- nautobot/dcim/models/power.py +6 -5
- nautobot/dcim/models/racks.py +6 -6
- nautobot/dcim/navigation.py +25 -224
- nautobot/dcim/signals.py +44 -0
- nautobot/dcim/tables/__init__.py +5 -3
- nautobot/dcim/tables/devices.py +103 -7
- nautobot/dcim/tables/devicetypes.py +2 -2
- nautobot/dcim/tables/racks.py +1 -1
- nautobot/dcim/templates/dcim/controller/base.html +10 -0
- nautobot/dcim/templates/dcim/controller_create.html +2 -7
- nautobot/dcim/templates/dcim/controller_retrieve.html +6 -10
- nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +25 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +68 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +51 -0
- nautobot/dcim/templates/dcim/device/base.html +6 -42
- nautobot/dcim/templates/dcim/device/wireless.html +73 -0
- nautobot/dcim/templates/dcim/device.html +4 -10
- nautobot/dcim/templates/dcim/device_edit.html +36 -37
- nautobot/dcim/templates/dcim/interface.html +1 -0
- nautobot/dcim/templates/dcim/interface_edit.html +1 -0
- nautobot/dcim/templates/dcim/location.html +1 -9
- nautobot/dcim/templates/dcim/location_edit.html +1 -7
- nautobot/dcim/templates/dcim/locationtype.html +0 -107
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +8 -0
- nautobot/dcim/templates/dcim/rack.html +1 -9
- nautobot/dcim/templates/dcim/rack_edit.html +1 -7
- nautobot/dcim/templates/dcim/rackreservation.html +1 -9
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +68 -0
- nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +28 -0
- nautobot/dcim/tests/integration/test_controller.py +62 -0
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
- nautobot/dcim/tests/test_api.py +188 -64
- nautobot/dcim/tests/test_filters.py +172 -76
- nautobot/dcim/tests/test_graphql.py +52 -0
- nautobot/dcim/tests/test_jobs.py +118 -0
- nautobot/dcim/tests/test_models.py +159 -5
- nautobot/dcim/tests/test_signals.py +1 -0
- nautobot/dcim/tests/test_views.py +118 -88
- nautobot/dcim/urls.py +72 -27
- nautobot/dcim/utils.py +2 -2
- nautobot/dcim/views.py +357 -62
- nautobot/extras/api/customfields.py +2 -2
- nautobot/extras/api/serializers.py +111 -87
- nautobot/extras/api/urls.py +4 -0
- nautobot/extras/api/views.py +93 -35
- nautobot/extras/choices.py +13 -0
- nautobot/extras/constants.py +2 -1
- nautobot/extras/context_managers.py +23 -6
- nautobot/extras/datasources/git.py +4 -1
- nautobot/extras/factory.py +27 -0
- nautobot/extras/filters/__init__.py +66 -5
- nautobot/extras/forms/base.py +2 -2
- nautobot/extras/forms/forms.py +262 -59
- nautobot/extras/forms/mixins.py +3 -3
- nautobot/extras/graphql/types.py +25 -1
- nautobot/extras/health_checks.py +1 -2
- nautobot/extras/jobs.py +114 -20
- nautobot/extras/management/__init__.py +1 -0
- nautobot/extras/management/commands/runjob.py +7 -79
- nautobot/extras/management/commands/runjob_with_job_result.py +46 -0
- nautobot/extras/management/utils.py +87 -0
- nautobot/extras/managers.py +3 -1
- nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
- nautobot/extras/migrations/0117_create_job_queue_model.py +129 -0
- nautobot/extras/migrations/0118_task_queue_to_job_queue_migration.py +78 -0
- nautobot/extras/migrations/0119_remove_task_queues_from_job_and_queue_from_scheduled_job.py +28 -0
- 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/models/__init__.py +5 -1
- nautobot/extras/models/change_logging.py +7 -3
- nautobot/extras/models/contacts.py +1 -1
- nautobot/extras/models/customfields.py +12 -11
- nautobot/extras/models/groups.py +11 -9
- nautobot/extras/models/jobs.py +237 -37
- nautobot/extras/models/models.py +2 -2
- nautobot/extras/models/relationships.py +69 -1
- nautobot/extras/models/secrets.py +5 -0
- nautobot/extras/navigation.py +20 -262
- nautobot/extras/plugins/__init__.py +54 -19
- nautobot/extras/plugins/marketplace_manifest.yml +455 -0
- nautobot/extras/plugins/tables.py +16 -14
- nautobot/extras/plugins/urls.py +1 -0
- nautobot/extras/plugins/views.py +104 -61
- nautobot/extras/registry.py +1 -1
- nautobot/extras/secrets/__init__.py +2 -2
- nautobot/extras/signals.py +39 -1
- nautobot/extras/tables.py +42 -6
- nautobot/extras/templates/extras/dynamicgroup.html +1 -9
- nautobot/extras/templates/extras/externalintegration_retrieve.html +0 -47
- nautobot/extras/templates/extras/inc/tags_panel.html +1 -5
- nautobot/extras/templates/extras/job_bulk_edit.html +2 -1
- nautobot/extras/templates/extras/job_detail.html +52 -6
- nautobot/extras/templates/extras/job_edit.html +6 -2
- nautobot/extras/templates/extras/job_list.html +2 -7
- nautobot/extras/templates/extras/jobqueue_retrieve.html +36 -0
- nautobot/extras/templates/extras/marketplace.html +296 -0
- nautobot/extras/templates/extras/plugin_detail.html +32 -15
- nautobot/extras/templates/extras/plugins_list.html +35 -1
- nautobot/extras/templates/extras/plugins_tiles.html +90 -0
- nautobot/extras/templates/extras/role_retrieve.html +16 -0
- nautobot/extras/templates/extras/secret.html +0 -65
- nautobot/extras/templates/extras/secret_check.js +16 -0
- nautobot/extras/templates/extras/secret_create.html +114 -0
- nautobot/extras/templates/extras/secret_edit.html +1 -114
- nautobot/extras/templates/extras/secretsgroup_edit.html +1 -1
- nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +2 -0
- nautobot/extras/templatetags/job_buttons.py +5 -4
- nautobot/extras/templatetags/plugins.py +69 -6
- 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/integration/test_plugin_banner.py +0 -2
- nautobot/extras/tests/test_api.py +157 -55
- nautobot/extras/tests/test_context_managers.py +4 -1
- nautobot/extras/tests/test_customfields.py +1 -1
- nautobot/extras/tests/test_datasources.py +2 -1
- nautobot/extras/tests/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/test_filters.py +219 -535
- nautobot/extras/tests/test_forms.py +20 -1
- nautobot/extras/tests/test_job_variables.py +73 -152
- nautobot/extras/tests/test_jobs.py +192 -62
- nautobot/extras/tests/test_models.py +71 -16
- nautobot/extras/tests/test_plugins.py +62 -9
- nautobot/extras/tests/test_relationships.py +124 -10
- nautobot/extras/tests/test_utils.py +23 -2
- nautobot/extras/tests/test_views.py +162 -161
- nautobot/extras/tests/test_webhooks.py +2 -1
- nautobot/extras/urls.py +2 -20
- nautobot/extras/utils.py +119 -4
- nautobot/extras/views.py +188 -141
- nautobot/extras/webhooks.py +5 -2
- nautobot/ipam/api/fields.py +3 -3
- nautobot/ipam/api/serializers.py +44 -137
- nautobot/ipam/api/views.py +68 -110
- nautobot/ipam/factory.py +1 -1
- nautobot/ipam/filters.py +3 -2
- nautobot/ipam/models.py +10 -12
- nautobot/ipam/navigation.py +0 -90
- nautobot/ipam/querysets.py +2 -2
- nautobot/ipam/tables.py +3 -1
- nautobot/ipam/templates/ipam/ipaddress.html +1 -9
- 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 +1 -9
- nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
- nautobot/ipam/templates/ipam/routetarget.html +0 -28
- nautobot/ipam/templates/ipam/vlan.html +1 -9
- nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
- nautobot/ipam/templates/ipam/vrf.html +0 -47
- nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
- nautobot/ipam/tests/test_api.py +19 -6
- nautobot/ipam/tests/test_filters.py +39 -119
- nautobot/ipam/tests/test_forms.py +49 -47
- nautobot/ipam/tests/test_migrations.py +30 -30
- nautobot/ipam/tests/test_models.py +56 -36
- nautobot/ipam/tests/test_querysets.py +14 -0
- nautobot/ipam/tests/test_views.py +3 -0
- nautobot/ipam/urls.py +3 -69
- nautobot/ipam/utils/__init__.py +16 -10
- nautobot/ipam/views.py +91 -162
- 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/css/base.css +38 -3
- nautobot/project-static/docs/404.html +463 -19
- nautobot/project-static/docs/apps/index.html +463 -19
- nautobot/project-static/docs/apps/nautobot-apps.html +464 -21
- nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
- nautobot/project-static/docs/assets/extra.css +5 -1
- nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js → bundle.88dd0f4e.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js.map → bundle.88dd0f4e.min.js.map} +2 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +479 -25
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +476 -22
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +792 -291
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +507 -33
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +512 -36
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +473 -22
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +469 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +499 -35
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +9883 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +525 -77
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +548 -53
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +672 -96
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1033 -180
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +526 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +876 -190
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +957 -237
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +477 -23
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +488 -30
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +663 -101
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +949 -481
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +6427 -1236
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +476 -22
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +879 -346
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +830 -173
- nautobot/project-static/docs/development/apps/api/configuration-view.html +463 -19
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +463 -19
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +463 -19
- nautobot/project-static/docs/development/apps/api/models/global-search.html +463 -19
- nautobot/project-static/docs/development/apps/api/models/graphql.html +463 -19
- nautobot/project-static/docs/development/apps/api/models/index.html +463 -19
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +463 -19
- nautobot/project-static/docs/development/apps/api/prometheus.html +463 -19
- nautobot/project-static/docs/development/apps/api/setup.html +467 -155
- nautobot/project-static/docs/development/apps/api/testing.html +463 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +463 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +463 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +463 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +463 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +743 -130
- nautobot/project-static/docs/development/apps/api/views/base-template.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/index.html +465 -20
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +467 -19
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +493 -19
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/notes.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +469 -21
- nautobot/project-static/docs/development/apps/api/views/urls.html +463 -19
- nautobot/project-static/docs/development/apps/index.html +463 -19
- nautobot/project-static/docs/development/apps/migration/code-updates.html +464 -52
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +464 -20
- nautobot/project-static/docs/development/apps/migration/from-v1.html +463 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +463 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +463 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +463 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +466 -22
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +9261 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +9375 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +9671 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +9559 -0
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +466 -22
- nautobot/project-static/docs/development/core/application-registry.html +463 -19
- nautobot/project-static/docs/development/core/best-practices.html +463 -19
- nautobot/project-static/docs/development/core/bootstrap-ui.html +463 -19
- nautobot/project-static/docs/development/core/caching.html +463 -19
- nautobot/project-static/docs/development/core/controllers.html +465 -19
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +491 -90
- nautobot/project-static/docs/development/core/generic-views.html +463 -19
- nautobot/project-static/docs/development/core/getting-started.html +541 -129
- nautobot/project-static/docs/development/core/homepage.html +474 -30
- nautobot/project-static/docs/development/core/index.html +463 -19
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +9754 -0
- nautobot/project-static/docs/development/core/model-checklist.html +473 -27
- nautobot/project-static/docs/development/core/model-features.html +463 -19
- nautobot/project-static/docs/development/core/natural-keys.html +463 -19
- nautobot/project-static/docs/development/core/navigation-menu.html +480 -26
- nautobot/project-static/docs/development/core/release-checklist.html +480 -48
- nautobot/project-static/docs/development/core/role-internals.html +463 -19
- nautobot/project-static/docs/development/core/settings.html +463 -19
- nautobot/project-static/docs/development/core/style-guide.html +466 -22
- nautobot/project-static/docs/development/core/templates.html +473 -22
- nautobot/project-static/docs/development/core/testing.html +463 -19
- nautobot/project-static/docs/development/core/ui-component-framework.html +11116 -0
- nautobot/project-static/docs/development/core/user-preferences.html +466 -22
- nautobot/project-static/docs/development/index.html +463 -19
- nautobot/project-static/docs/development/jobs/index.html +501 -21
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +463 -19
- nautobot/project-static/docs/index.html +471 -38
- 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/basic-panel-layout.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/button-example.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/dropdown-button-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-1.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-2.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-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/media/development/core/ui-component-framework/stats-panel-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/table-panels-family.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/text-panels-family.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/ui-framework-example.png +0 -0
- nautobot/project-static/docs/media/models/virtual_device_context_overview.drawio +73 -0
- nautobot/project-static/docs/media/models/virtual_device_context_overview.png +0 -0
- nautobot/project-static/docs/models/dcim/virtualdevicecontext.html +14 -0
- nautobot/project-static/docs/models/extras/jobqueue.html +14 -0
- nautobot/project-static/docs/models/wireless/radioprofile.html +14 -0
- nautobot/project-static/docs/models/wireless/supporteddatarate.html +14 -0
- nautobot/project-static/docs/models/wireless/wirelessnetwork.html +14 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +469 -23
- nautobot/project-static/docs/overview/design_philosophy.html +463 -19
- nautobot/project-static/docs/release-notes/index.html +485 -22
- nautobot/project-static/docs/release-notes/version-1.0.html +651 -208
- nautobot/project-static/docs/release-notes/version-1.1.html +648 -205
- nautobot/project-static/docs/release-notes/version-1.2.html +723 -280
- nautobot/project-static/docs/release-notes/version-1.3.html +749 -306
- nautobot/project-static/docs/release-notes/version-1.4.html +834 -392
- nautobot/project-static/docs/release-notes/version-1.5.html +1022 -581
- nautobot/project-static/docs/release-notes/version-1.6.html +942 -518
- nautobot/project-static/docs/release-notes/version-2.0.html +945 -504
- nautobot/project-static/docs/release-notes/version-2.1.html +780 -339
- nautobot/project-static/docs/release-notes/version-2.2.html +773 -332
- nautobot/project-static/docs/release-notes/version-2.3.html +1142 -448
- nautobot/project-static/docs/release-notes/version-2.4.html +10323 -0
- nautobot/project-static/docs/requirements.txt +2 -2
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +342 -270
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +463 -19
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +463 -19
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +463 -19
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +475 -32
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +463 -19
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +894 -180
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +476 -29
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +465 -21
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +463 -19
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +463 -19
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +463 -19
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +483 -23
- nautobot/project-static/docs/user-guide/administration/installation/index.html +468 -20
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +464 -20
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +463 -19
- nautobot/project-static/docs/user-guide/administration/installation/services.html +463 -19
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +463 -19
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +484 -41
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +477 -66
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +477 -66
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +466 -23
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-nautobot-app-location.yaml +0 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +469 -21
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +499 -20
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +489 -22
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +9375 -0
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +470 -30
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +466 -22
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +466 -22
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +9313 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +9217 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +9211 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +9277 -0
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +468 -22
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +463 -19
- 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 +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +466 -22
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
- nautobot/project-static/docs/user-guide/index.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +467 -23
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +9617 -0
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +472 -23
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +9224 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9722 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +467 -23
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +9292 -0
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +511 -40
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +494 -23
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +531 -56
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +463 -19
- nautobot/project-static/img/jinja_logo.svg +97 -0
- nautobot/project-static/js/forms.js +6 -1
- nautobot/project-static/js/nav_menu.js +2 -1
- nautobot/tenancy/api/serializers.py +0 -2
- nautobot/tenancy/api/views.py +9 -13
- nautobot/tenancy/factory.py +1 -1
- nautobot/tenancy/navigation.py +0 -29
- nautobot/tenancy/templates/tenancy/tenant.html +4 -91
- nautobot/tenancy/tests/test_filters.py +29 -134
- nautobot/tenancy/views.py +35 -24
- nautobot/users/admin.py +3 -1
- nautobot/users/api/serializers.py +4 -4
- nautobot/users/api/views.py +3 -3
- nautobot/users/forms.py +19 -0
- nautobot/users/templates/users/preferences.html +22 -0
- nautobot/users/tests/test_filters.py +1 -19
- nautobot/users/tests/test_views.py +57 -0
- nautobot/users/utils.py +8 -0
- nautobot/users/views.py +48 -11
- nautobot/virtualization/api/serializers.py +4 -4
- nautobot/virtualization/api/views.py +5 -24
- nautobot/virtualization/filters.py +1 -2
- nautobot/virtualization/models.py +1 -1
- nautobot/virtualization/navigation.py +0 -48
- nautobot/virtualization/tables.py +2 -2
- nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
- nautobot/virtualization/templates/virtualization/clustertype.html +0 -39
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
- nautobot/virtualization/tests/test_filters.py +57 -166
- nautobot/virtualization/views.py +18 -15
- nautobot/wireless/__init__.py +0 -0
- nautobot/wireless/api/__init__.py +0 -0
- nautobot/wireless/api/serializers.py +44 -0
- nautobot/wireless/api/urls.py +20 -0
- nautobot/wireless/api/views.py +34 -0
- nautobot/wireless/apps.py +8 -0
- nautobot/wireless/choices.py +345 -0
- nautobot/wireless/factory.py +138 -0
- nautobot/wireless/filters.py +167 -0
- nautobot/wireless/forms.py +283 -0
- nautobot/wireless/homepage.py +19 -0
- nautobot/wireless/migrations/0001_initial.py +223 -0
- nautobot/wireless/migrations/__init__.py +0 -0
- nautobot/wireless/models.py +207 -0
- nautobot/wireless/navigation.py +105 -0
- nautobot/wireless/tables.py +244 -0
- nautobot/wireless/templates/wireless/radioprofile_retrieve.html +81 -0
- nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +26 -0
- nautobot/wireless/templates/wireless/wirelessnetwork_create.html +88 -0
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +56 -0
- nautobot/wireless/tests/__init__.py +0 -0
- nautobot/wireless/tests/integration/__init__.py +0 -0
- nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
- nautobot/wireless/tests/test_api.py +247 -0
- nautobot/wireless/tests/test_filters.py +82 -0
- nautobot/wireless/tests/test_models.py +22 -0
- nautobot/wireless/tests/test_views.py +378 -0
- nautobot/wireless/urls.py +13 -0
- nautobot/wireless/views.py +119 -0
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/METADATA +11 -13
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/RECORD +783 -613
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/WHEEL +1 -1
- nautobot/core/fixtures/user-data.json +0 -59
- nautobot/core/utils/navigation.py +0 -54
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/NOTICE +0 -0
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/entry_points.txt +0 -0
nautobot/extras/models/jobs.py
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import contextlib
|
|
4
4
|
from datetime import timedelta
|
|
5
|
+
import json
|
|
5
6
|
import logging
|
|
7
|
+
import signal
|
|
6
8
|
|
|
9
|
+
from billiard.exceptions import SoftTimeLimitExceeded
|
|
7
10
|
from celery.exceptions import NotRegistered
|
|
8
11
|
from celery.utils.log import get_logger, LoggingProxy
|
|
9
12
|
from django.conf import settings
|
|
@@ -26,12 +29,12 @@ from nautobot.core.celery import (
|
|
|
26
29
|
)
|
|
27
30
|
from nautobot.core.constants import CHARFIELD_MAX_LENGTH
|
|
28
31
|
from nautobot.core.models import BaseManager, BaseModel
|
|
29
|
-
from nautobot.core.models.fields import JSONArrayField
|
|
30
32
|
from nautobot.core.models.generics import OrganizationalModel, PrimaryModel
|
|
31
33
|
from nautobot.core.utils.logging import sanitize
|
|
32
34
|
from nautobot.extras.choices import (
|
|
33
35
|
ButtonClassChoices,
|
|
34
36
|
JobExecutionType,
|
|
37
|
+
JobQueueTypeChoices,
|
|
35
38
|
JobResultStatusChoices,
|
|
36
39
|
LogLevelChoices,
|
|
37
40
|
)
|
|
@@ -49,6 +52,8 @@ from nautobot.extras.querysets import JobQuerySet, ScheduledJobExtendedQuerySet
|
|
|
49
52
|
from nautobot.extras.utils import (
|
|
50
53
|
ChangeLoggedModelsQuery,
|
|
51
54
|
extras_features,
|
|
55
|
+
get_job_queue_worker_count,
|
|
56
|
+
run_kubernetes_job_and_return_job_result,
|
|
52
57
|
)
|
|
53
58
|
|
|
54
59
|
from .customfields import CustomFieldModel
|
|
@@ -135,6 +140,11 @@ class Job(PrimaryModel):
|
|
|
135
140
|
default=True, help_text="Whether this job contains sensitive variables"
|
|
136
141
|
)
|
|
137
142
|
|
|
143
|
+
is_singleton = models.BooleanField(
|
|
144
|
+
default=False,
|
|
145
|
+
help_text="Whether this job should fail to run if another instance of this job is already running",
|
|
146
|
+
)
|
|
147
|
+
|
|
138
148
|
# Additional properties, potentially inherited from the source code
|
|
139
149
|
# See also the docstring of nautobot.extras.jobs.BaseJob.Meta.
|
|
140
150
|
approval_required = models.BooleanField(
|
|
@@ -164,17 +174,26 @@ class Job(PrimaryModel):
|
|
|
164
174
|
help_text="Maximum runtime in seconds before the job will be forcibly terminated."
|
|
165
175
|
"<br>Set to 0 to use Nautobot system default",
|
|
166
176
|
)
|
|
167
|
-
task_queues = JSONArrayField(
|
|
168
|
-
base_field=models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True),
|
|
169
|
-
default=list,
|
|
170
|
-
blank=True,
|
|
171
|
-
help_text="Comma separated list of task queues that this job can run on. A blank list will use the default queue",
|
|
172
|
-
)
|
|
173
177
|
supports_dryrun = models.BooleanField(
|
|
174
178
|
default=False,
|
|
175
179
|
editable=False,
|
|
176
180
|
help_text="If supported, allows the job to bypass approval when running with dryrun argument set to true",
|
|
177
181
|
)
|
|
182
|
+
job_queues = models.ManyToManyField(
|
|
183
|
+
to="extras.JobQueue",
|
|
184
|
+
related_name="jobs",
|
|
185
|
+
verbose_name="Job Queues",
|
|
186
|
+
help_text="The job queues that this job can be run on",
|
|
187
|
+
through="extras.JobQueueAssignment",
|
|
188
|
+
)
|
|
189
|
+
default_job_queue = models.ForeignKey(
|
|
190
|
+
to="extras.JobQueue",
|
|
191
|
+
related_name="default_for_jobs",
|
|
192
|
+
on_delete=models.PROTECT,
|
|
193
|
+
verbose_name="Default Job Queue",
|
|
194
|
+
null=False,
|
|
195
|
+
blank=False,
|
|
196
|
+
)
|
|
178
197
|
|
|
179
198
|
# Flags to indicate whether the above properties are inherited from the source code or overridden by the database
|
|
180
199
|
grouping_override = models.BooleanField(
|
|
@@ -213,11 +232,18 @@ class Job(PrimaryModel):
|
|
|
213
232
|
default=False,
|
|
214
233
|
help_text="If set, the configured value will remain even if the underlying Job source code changes",
|
|
215
234
|
)
|
|
216
|
-
|
|
235
|
+
job_queues_override = models.BooleanField(
|
|
236
|
+
default=False,
|
|
237
|
+
help_text="If set, the configured value will remain even if the underlying Job source code changes",
|
|
238
|
+
)
|
|
239
|
+
default_job_queue_override = models.BooleanField(
|
|
240
|
+
default=False,
|
|
241
|
+
help_text="If set, the configured value will remain even if the underlying Job source code changes",
|
|
242
|
+
)
|
|
243
|
+
is_singleton_override = models.BooleanField(
|
|
217
244
|
default=False,
|
|
218
245
|
help_text="If set, the configured value will remain even if the underlying Job source code changes",
|
|
219
246
|
)
|
|
220
|
-
|
|
221
247
|
objects = BaseManager.from_queryset(JobQuerySet)()
|
|
222
248
|
|
|
223
249
|
documentation_static_path = "docs/user-guide/platform-functionality/jobs/models.html"
|
|
@@ -234,13 +260,13 @@ class Job(PrimaryModel):
|
|
|
234
260
|
def __str__(self):
|
|
235
261
|
return self.name
|
|
236
262
|
|
|
237
|
-
def delete(self):
|
|
263
|
+
def delete(self, *args, **kwargs):
|
|
238
264
|
if self.module_name.startswith("nautobot."):
|
|
239
265
|
raise ProtectedError(
|
|
240
266
|
f"Unable to delete Job {self}. System Job cannot be deleted",
|
|
241
267
|
[],
|
|
242
268
|
)
|
|
243
|
-
super().delete()
|
|
269
|
+
super().delete(*args, **kwargs)
|
|
244
270
|
|
|
245
271
|
@property
|
|
246
272
|
def job_class(self):
|
|
@@ -302,6 +328,38 @@ class Job(PrimaryModel):
|
|
|
302
328
|
except TypeError as err: # keep 2.0-2.2.2 exception behavior
|
|
303
329
|
raise NotRegistered from err
|
|
304
330
|
|
|
331
|
+
@property
|
|
332
|
+
def task_queues(self):
|
|
333
|
+
"""Deprecated backward-compatibility property for the list of queue names for this Job."""
|
|
334
|
+
return self.job_queues.values_list("name", flat=True)
|
|
335
|
+
|
|
336
|
+
@task_queues.setter
|
|
337
|
+
def task_queues(self, value):
|
|
338
|
+
job_queues = []
|
|
339
|
+
# value is going to be a comma separated list of queue names
|
|
340
|
+
if isinstance(value, str):
|
|
341
|
+
value = value.split(",")
|
|
342
|
+
for queue in value:
|
|
343
|
+
try:
|
|
344
|
+
job_queues.append(JobQueue.objects.get(name=queue))
|
|
345
|
+
except JobQueue.DoesNotExist:
|
|
346
|
+
raise ValidationError(f"Job Queue {queue} does not exist in the database.")
|
|
347
|
+
self.job_queues.set(job_queues)
|
|
348
|
+
|
|
349
|
+
@property
|
|
350
|
+
def task_queues_override(self):
|
|
351
|
+
return self.job_queues_override
|
|
352
|
+
|
|
353
|
+
@task_queues_override.setter
|
|
354
|
+
def task_queues_override(self, value):
|
|
355
|
+
if isinstance(value, bool):
|
|
356
|
+
raise ValidationError(
|
|
357
|
+
{
|
|
358
|
+
"task_queues_override": f"{value} is invalid for field task_queues_override, use a boolean value instead"
|
|
359
|
+
}
|
|
360
|
+
)
|
|
361
|
+
self.job_queues_override = value
|
|
362
|
+
|
|
305
363
|
def clean(self):
|
|
306
364
|
"""For any non-overridden fields, make sure they get reset to the actual underlying class value if known."""
|
|
307
365
|
from nautobot.extras.jobs import get_job
|
|
@@ -312,6 +370,9 @@ class Job(PrimaryModel):
|
|
|
312
370
|
if not getattr(self, f"{field_name}_override", False):
|
|
313
371
|
setattr(self, field_name, getattr(job_class, field_name))
|
|
314
372
|
|
|
373
|
+
if not self.job_queues_override:
|
|
374
|
+
self.task_queues = job_class.task_queues or [settings.CELERY_TASK_DEFAULT_QUEUE]
|
|
375
|
+
|
|
315
376
|
# Protect against invalid input when auto-creating Job records
|
|
316
377
|
if len(self.module_name) > JOB_MAX_NAME_LENGTH:
|
|
317
378
|
raise ValidationError(f"Module name may not exceed {JOB_MAX_NAME_LENGTH} characters in length")
|
|
@@ -478,6 +539,77 @@ class JobLogEntry(BaseModel):
|
|
|
478
539
|
verbose_name_plural = "job log entries"
|
|
479
540
|
|
|
480
541
|
|
|
542
|
+
#
|
|
543
|
+
# Job Queues
|
|
544
|
+
#
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
@extras_features(
|
|
548
|
+
"custom_links",
|
|
549
|
+
"custom_validators",
|
|
550
|
+
"export_templates",
|
|
551
|
+
"graphql",
|
|
552
|
+
"webhooks",
|
|
553
|
+
)
|
|
554
|
+
class JobQueue(PrimaryModel):
|
|
555
|
+
"""
|
|
556
|
+
A Job Queue represents a structure that is used to manage, organize and schedule jobs for Nautobot workers.
|
|
557
|
+
"""
|
|
558
|
+
|
|
559
|
+
name = models.CharField(max_length=CHARFIELD_MAX_LENGTH, unique=True)
|
|
560
|
+
description = models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True)
|
|
561
|
+
queue_type = models.CharField(
|
|
562
|
+
max_length=50,
|
|
563
|
+
choices=JobQueueTypeChoices,
|
|
564
|
+
)
|
|
565
|
+
tenant = models.ForeignKey(
|
|
566
|
+
to="tenancy.Tenant",
|
|
567
|
+
on_delete=models.PROTECT,
|
|
568
|
+
related_name="job_queues",
|
|
569
|
+
blank=True,
|
|
570
|
+
null=True,
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
documentation_static_path = "docs/user-guide/platform-functionality/jobs/jobqueue.html"
|
|
574
|
+
|
|
575
|
+
class Meta:
|
|
576
|
+
ordering = ["name"]
|
|
577
|
+
|
|
578
|
+
def __str__(self):
|
|
579
|
+
return f"{self.queue_type}: {self.name}"
|
|
580
|
+
|
|
581
|
+
@property
|
|
582
|
+
def display(self):
|
|
583
|
+
if self.queue_type != JobQueueTypeChoices.TYPE_CELERY:
|
|
584
|
+
return f"{self.queue_type}: {self.name}"
|
|
585
|
+
worker_count = get_job_queue_worker_count(job_queue=self)
|
|
586
|
+
workers = "worker" if worker_count == 1 else "workers"
|
|
587
|
+
return f"{self.queue_type}: {self.name} ({worker_count} {workers})"
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
@extras_features(
|
|
591
|
+
"custom_links",
|
|
592
|
+
"custom_validators",
|
|
593
|
+
"export_templates",
|
|
594
|
+
"graphql",
|
|
595
|
+
)
|
|
596
|
+
class JobQueueAssignment(BaseModel):
|
|
597
|
+
"""
|
|
598
|
+
Through table model that represents the m2m relationship between jobs and job queues.
|
|
599
|
+
"""
|
|
600
|
+
|
|
601
|
+
job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name="job_queue_assignments")
|
|
602
|
+
job_queue = models.ForeignKey(JobQueue, on_delete=models.CASCADE, related_name="job_assignments")
|
|
603
|
+
is_metadata_associable_model = False
|
|
604
|
+
|
|
605
|
+
class Meta:
|
|
606
|
+
unique_together = ["job", "job_queue"]
|
|
607
|
+
ordering = ["job", "job_queue"]
|
|
608
|
+
|
|
609
|
+
def __str__(self):
|
|
610
|
+
return f"{self.job}: {self.job_queue}"
|
|
611
|
+
|
|
612
|
+
|
|
481
613
|
#
|
|
482
614
|
# Job results
|
|
483
615
|
#
|
|
@@ -610,13 +742,13 @@ class JobResult(BaseModel, CustomFieldModel):
|
|
|
610
742
|
# Only add metrics if we have a related job model. If we are moving to a terminal state we should always
|
|
611
743
|
# have a related job model, so this shouldn't be too tight of a restriction.
|
|
612
744
|
if self.job_model:
|
|
613
|
-
duration = self.date_done - self.
|
|
745
|
+
duration = self.date_done - self.date_created
|
|
614
746
|
JOB_RESULT_METRIC.labels(self.job_model.grouping, self.job_model.name, status).observe(
|
|
615
747
|
duration.total_seconds()
|
|
616
748
|
)
|
|
617
749
|
|
|
618
750
|
@classmethod
|
|
619
|
-
def execute_job(cls, job_model, user, *job_args, celery_kwargs=None, profile=False, **job_kwargs):
|
|
751
|
+
def execute_job(cls, job_model, user, *job_args, celery_kwargs=None, profile=False, job_result=None, **job_kwargs):
|
|
620
752
|
"""
|
|
621
753
|
Create a JobResult instance and run a job in the current process, blocking until the job finishes.
|
|
622
754
|
|
|
@@ -628,6 +760,7 @@ class JobResult(BaseModel, CustomFieldModel):
|
|
|
628
760
|
user (User): User object to link to the JobResult instance
|
|
629
761
|
celery_kwargs (dict, optional): Dictionary of kwargs to pass as **kwargs to Celery when job is run
|
|
630
762
|
profile (bool, optional): Whether to run cProfile on the job execution
|
|
763
|
+
job_result (JobResult, optional): Existing JobResult with status PENDING, used in kubernetes job execution
|
|
631
764
|
*job_args: positional args passed to the job task
|
|
632
765
|
**job_kwargs: keyword args passed to the job task
|
|
633
766
|
|
|
@@ -635,7 +768,14 @@ class JobResult(BaseModel, CustomFieldModel):
|
|
|
635
768
|
JobResult instance
|
|
636
769
|
"""
|
|
637
770
|
return cls.enqueue_job(
|
|
638
|
-
job_model,
|
|
771
|
+
job_model,
|
|
772
|
+
user,
|
|
773
|
+
*job_args,
|
|
774
|
+
celery_kwargs=celery_kwargs,
|
|
775
|
+
profile=profile,
|
|
776
|
+
job_result=job_result,
|
|
777
|
+
synchronous=True,
|
|
778
|
+
**job_kwargs,
|
|
639
779
|
)
|
|
640
780
|
|
|
641
781
|
@classmethod
|
|
@@ -648,10 +788,12 @@ class JobResult(BaseModel, CustomFieldModel):
|
|
|
648
788
|
profile=False,
|
|
649
789
|
schedule=None,
|
|
650
790
|
task_queue=None,
|
|
791
|
+
job_result=None,
|
|
651
792
|
synchronous=False,
|
|
793
|
+
ignore_singleton_lock=False,
|
|
652
794
|
**job_kwargs,
|
|
653
795
|
):
|
|
654
|
-
"""Create a JobResult instance and enqueue a job to be executed asynchronously by a Celery worker.
|
|
796
|
+
"""Create/Modify a JobResult instance and enqueue a job to be executed asynchronously by a Celery worker.
|
|
655
797
|
|
|
656
798
|
Args:
|
|
657
799
|
job_model (Job): The Job to be enqueued for execution.
|
|
@@ -660,7 +802,11 @@ class JobResult(BaseModel, CustomFieldModel):
|
|
|
660
802
|
profile (bool, optional): If True, dump cProfile stats on the job execution.
|
|
661
803
|
schedule (ScheduledJob, optional): ScheduledJob instance to link to the JobResult. Cannot be used with synchronous=True.
|
|
662
804
|
task_queue (str, optional): The celery queue to send the job to. If not set, use the default celery queue.
|
|
805
|
+
job_result (JobResult, optional): Existing JobResult with status PENDING, to be modified and to be used in kubernetes job execution.
|
|
663
806
|
synchronous (bool, optional): If True, run the job in the current process, blocking until the job completes.
|
|
807
|
+
ignore_singleton_lock (bool, optional): If True, invalidate the singleton lock before running the job.
|
|
808
|
+
This allows singleton jobs to run twice, or makes it possible to remove the lock when the first instance
|
|
809
|
+
of the job failed to remove it for any reason.
|
|
664
810
|
*job_args: positional args passed to the job task (UNUSED)
|
|
665
811
|
**job_kwargs: keyword args passed to the job task
|
|
666
812
|
|
|
@@ -672,20 +818,40 @@ class JobResult(BaseModel, CustomFieldModel):
|
|
|
672
818
|
if schedule is not None and synchronous:
|
|
673
819
|
raise ValueError("Scheduled jobs cannot be run synchronously")
|
|
674
820
|
|
|
675
|
-
job_result
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
821
|
+
if job_result is None:
|
|
822
|
+
job_result = cls.objects.create(
|
|
823
|
+
name=job_model.name,
|
|
824
|
+
job_model=job_model,
|
|
825
|
+
scheduled_job=schedule,
|
|
826
|
+
user=user,
|
|
827
|
+
)
|
|
828
|
+
else:
|
|
829
|
+
if job_result.user != user:
|
|
830
|
+
raise ValueError(
|
|
831
|
+
f"There is a mismatch between the user specified {user} and the user associated with the job result {job_result.user}"
|
|
832
|
+
)
|
|
833
|
+
if job_result.job_model != job_model:
|
|
834
|
+
raise ValueError(
|
|
835
|
+
f"There is a mismatch between the job specified {job_model} and the job associated with the job result {job_result.job_model}"
|
|
836
|
+
)
|
|
681
837
|
|
|
682
838
|
if task_queue is None:
|
|
683
|
-
task_queue =
|
|
839
|
+
task_queue = job_model.default_job_queue.name
|
|
840
|
+
|
|
841
|
+
job_queue = JobQueue.objects.get(name=task_queue)
|
|
842
|
+
# Kubernetes Job Queue logic
|
|
843
|
+
# As we execute Kubernetes jobs, we want to execute `run_kubernetes_job_and_return_job_result`
|
|
844
|
+
# the first time the kubernetes job is enqueued to spin up the kubernetes pod.
|
|
845
|
+
# And from the kubernetes pod, we specify "--local"/synchronous=True
|
|
846
|
+
# so that `run_kubernetes_job_and_return_job_result` is not executed again and the job will be run locally.
|
|
847
|
+
if job_queue.queue_type == JobQueueTypeChoices.TYPE_KUBERNETES and not synchronous:
|
|
848
|
+
return run_kubernetes_job_and_return_job_result(job_queue, job_result, json.dumps(job_kwargs))
|
|
684
849
|
|
|
685
850
|
job_celery_kwargs = {
|
|
686
851
|
"nautobot_job_job_model_id": job_model.id,
|
|
687
852
|
"nautobot_job_profile": profile,
|
|
688
853
|
"nautobot_job_user_id": user.id,
|
|
854
|
+
"nautobot_job_ignore_singleton_lock": ignore_singleton_lock,
|
|
689
855
|
"queue": task_queue,
|
|
690
856
|
}
|
|
691
857
|
|
|
@@ -712,12 +878,24 @@ class JobResult(BaseModel, CustomFieldModel):
|
|
|
712
878
|
redirect_logger = get_logger("celery.redirected")
|
|
713
879
|
proxy = LoggingProxy(redirect_logger, app.conf.worker_redirect_stdouts_level)
|
|
714
880
|
with contextlib.redirect_stdout(proxy), contextlib.redirect_stderr(proxy):
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
)
|
|
881
|
+
|
|
882
|
+
def alarm_handler(*args, **kwargs):
|
|
883
|
+
raise SoftTimeLimitExceeded()
|
|
884
|
+
|
|
885
|
+
# Set alarm_handler to be called on a SIGALRM, and schedule a SIGALRM based on the soft time limit
|
|
886
|
+
signal.signal(signal.SIGALRM, alarm_handler)
|
|
887
|
+
signal.alarm(int(job_model.soft_time_limit) or settings.CELERY_TASK_SOFT_TIME_LIMIT)
|
|
888
|
+
|
|
889
|
+
try:
|
|
890
|
+
eager_result = run_job.apply(
|
|
891
|
+
args=[job_model.class_path, *job_args],
|
|
892
|
+
kwargs=job_kwargs,
|
|
893
|
+
task_id=str(job_result.id),
|
|
894
|
+
**job_celery_kwargs,
|
|
895
|
+
)
|
|
896
|
+
finally:
|
|
897
|
+
# Cancel the scheduled SIGALRM if it hasn't fired already
|
|
898
|
+
signal.alarm(0)
|
|
721
899
|
|
|
722
900
|
# copy fields from eager result to job result
|
|
723
901
|
job_result.refresh_from_db()
|
|
@@ -728,9 +906,15 @@ class JobResult(BaseModel, CustomFieldModel):
|
|
|
728
906
|
"exc_message": sanitize(str(eager_result.result)),
|
|
729
907
|
}
|
|
730
908
|
else:
|
|
731
|
-
|
|
909
|
+
if eager_result.result is not None:
|
|
910
|
+
job_result.result = sanitize(eager_result.result)
|
|
911
|
+
else:
|
|
912
|
+
job_result.result = None
|
|
732
913
|
job_result.status = eager_result.status
|
|
733
|
-
|
|
914
|
+
if eager_result.traceback is not None:
|
|
915
|
+
job_result.traceback = sanitize(eager_result.traceback)
|
|
916
|
+
else:
|
|
917
|
+
job_result.traceback = None
|
|
734
918
|
job_result.date_done = timezone.now()
|
|
735
919
|
job_result.save()
|
|
736
920
|
else:
|
|
@@ -927,13 +1111,13 @@ class ScheduledJob(BaseModel):
|
|
|
927
1111
|
args = models.JSONField(blank=True, default=list, encoder=NautobotKombuJSONEncoder)
|
|
928
1112
|
kwargs = models.JSONField(blank=True, default=dict, encoder=NautobotKombuJSONEncoder)
|
|
929
1113
|
celery_kwargs = models.JSONField(blank=True, default=dict, encoder=NautobotKombuJSONEncoder)
|
|
930
|
-
|
|
931
|
-
|
|
1114
|
+
job_queue = models.ForeignKey(
|
|
1115
|
+
to="extras.JobQueue",
|
|
1116
|
+
on_delete=models.SET_NULL,
|
|
1117
|
+
related_name="scheduled_jobs",
|
|
1118
|
+
null=True,
|
|
932
1119
|
blank=True,
|
|
933
|
-
|
|
934
|
-
verbose_name="Queue Override",
|
|
935
|
-
help_text="Queue defined in CELERY_TASK_QUEUES. Leave empty for default queuing.",
|
|
936
|
-
db_index=True,
|
|
1120
|
+
verbose_name="Job Queue Override",
|
|
937
1121
|
)
|
|
938
1122
|
one_off = models.BooleanField(
|
|
939
1123
|
default=False,
|
|
@@ -1065,6 +1249,19 @@ class ScheduledJob(BaseModel):
|
|
|
1065
1249
|
|
|
1066
1250
|
return self.to_cron()
|
|
1067
1251
|
|
|
1252
|
+
@property
|
|
1253
|
+
def queue(self):
|
|
1254
|
+
"""Deprecated backward-compatibility property for the queue name this job is scheduled for."""
|
|
1255
|
+
return self.job_queue.name if self.job_queue else ""
|
|
1256
|
+
|
|
1257
|
+
@queue.setter
|
|
1258
|
+
def queue(self, value):
|
|
1259
|
+
if value:
|
|
1260
|
+
try:
|
|
1261
|
+
self.job_queue = JobQueue.objects.get(name=value)
|
|
1262
|
+
except JobQueue.DoesNotExist:
|
|
1263
|
+
raise ValidationError(f"Job Queue {value} does not exist in the database.")
|
|
1264
|
+
|
|
1068
1265
|
@staticmethod
|
|
1069
1266
|
def earliest_possible_time():
|
|
1070
1267
|
return timezone.now() + timedelta(seconds=15)
|
|
@@ -1108,6 +1305,7 @@ class ScheduledJob(BaseModel):
|
|
|
1108
1305
|
profile=False,
|
|
1109
1306
|
approval_required=False,
|
|
1110
1307
|
task_queue=None,
|
|
1308
|
+
ignore_singleton_lock=False,
|
|
1111
1309
|
**job_kwargs,
|
|
1112
1310
|
):
|
|
1113
1311
|
"""
|
|
@@ -1128,6 +1326,7 @@ class ScheduledJob(BaseModel):
|
|
|
1128
1326
|
profile (bool, optional): Flag indicating whether to profile the job. Defaults to False.
|
|
1129
1327
|
approval_required (bool, optional): Flag indicating if approval is required. Defaults to False.
|
|
1130
1328
|
task_queue (str, optional): The task queue for the job. Defaults to None, which will use the configured default celery queue.
|
|
1329
|
+
ignore_singleton_lock (bool, optional): Flag indicating whether to ignore singleton locks. Defaults to False.
|
|
1131
1330
|
**job_kwargs: Additional keyword arguments to pass to the job.
|
|
1132
1331
|
|
|
1133
1332
|
Returns:
|
|
@@ -1146,6 +1345,7 @@ class ScheduledJob(BaseModel):
|
|
|
1146
1345
|
celery_kwargs = {
|
|
1147
1346
|
"nautobot_job_profile": profile,
|
|
1148
1347
|
"queue": task_queue,
|
|
1348
|
+
"nautobot_job_ignore_singleton_lock": ignore_singleton_lock,
|
|
1149
1349
|
}
|
|
1150
1350
|
if job_model.soft_time_limit > 0:
|
|
1151
1351
|
celery_kwargs["soft_time_limit"] = job_model.soft_time_limit
|
|
@@ -1180,7 +1380,7 @@ class ScheduledJob(BaseModel):
|
|
|
1180
1380
|
|
|
1181
1381
|
def to_cron(self):
|
|
1182
1382
|
tz = self.time_zone
|
|
1183
|
-
t = self.start_time.astimezone(tz)
|
|
1383
|
+
t = self.start_time.astimezone(tz) # pylint: disable=no-member
|
|
1184
1384
|
if self.interval == JobExecutionType.TYPE_HOURLY:
|
|
1185
1385
|
return TzAwareCrontab(minute=t.minute, tz=tz)
|
|
1186
1386
|
elif self.interval == JobExecutionType.TYPE_DAILY:
|
nautobot/extras/models/models.py
CHANGED
|
@@ -207,7 +207,7 @@ class ConfigContextModel(models.Model, ConfigContextSchemaValidationMixin):
|
|
|
207
207
|
# Annotation not available, so fall back to manually querying for the config context
|
|
208
208
|
config_context_data = ConfigContext.objects.get_for_object(self).values_list("data", flat=True)
|
|
209
209
|
else:
|
|
210
|
-
config_context_data = self.config_context_data or []
|
|
210
|
+
config_context_data = self.config_context_data or [] # pylint: disable=no-member
|
|
211
211
|
config_context_data = [
|
|
212
212
|
c["data"] for c in sorted(config_context_data, key=lambda k: (k["weight"], k["name"]))
|
|
213
213
|
]
|
|
@@ -831,7 +831,7 @@ class Note(ChangeLoggedModel, BaseModel):
|
|
|
831
831
|
unique_together = [["assigned_object_type", "assigned_object_id", "user_name", "created"]]
|
|
832
832
|
|
|
833
833
|
def __str__(self):
|
|
834
|
-
return f"{self.assigned_object} - {self.created.isoformat() if self.created else None}"
|
|
834
|
+
return f"{self.assigned_object} - {self.created.isoformat() if self.created else None}" # pylint: disable=no-member
|
|
835
835
|
|
|
836
836
|
def save(self, *args, **kwargs):
|
|
837
837
|
# Record the user's name as static strings
|
|
@@ -105,7 +105,7 @@ class RelationshipModel(models.Model):
|
|
|
105
105
|
|
|
106
106
|
# Determine if the relationship is applicable to this object based on the filter
|
|
107
107
|
# To resolve the filter we are using the FilterSet for the given model
|
|
108
|
-
# If there is no match when we query
|
|
108
|
+
# If there is no match when we query our id along with the filter
|
|
109
109
|
# Then the relationship is not applicable to this object
|
|
110
110
|
if getattr(relationship, f"{side}_filter"):
|
|
111
111
|
filterset = get_filterset_for_model(self._meta.model)
|
|
@@ -222,6 +222,74 @@ class RelationshipModel(models.Model):
|
|
|
222
222
|
"""
|
|
223
223
|
return self.get_relationships_data(advanced_ui=True)
|
|
224
224
|
|
|
225
|
+
def get_relationships_with_related_objects(self, include_hidden=False, advanced_ui=None):
|
|
226
|
+
"""Alternative version of get_relationships()."""
|
|
227
|
+
src_relationships, dst_relationships = Relationship.objects.get_for_model(self)
|
|
228
|
+
|
|
229
|
+
if advanced_ui is not None:
|
|
230
|
+
src_relationships = src_relationships.filter(advanced_ui=advanced_ui)
|
|
231
|
+
dst_relationships = dst_relationships.filter(advanced_ui=advanced_ui)
|
|
232
|
+
|
|
233
|
+
resp = {
|
|
234
|
+
RelationshipSideChoices.SIDE_SOURCE: {},
|
|
235
|
+
RelationshipSideChoices.SIDE_DESTINATION: {},
|
|
236
|
+
RelationshipSideChoices.SIDE_PEER: {},
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
for side, relationships in (
|
|
240
|
+
(RelationshipSideChoices.SIDE_SOURCE, src_relationships),
|
|
241
|
+
(RelationshipSideChoices.SIDE_DESTINATION, dst_relationships),
|
|
242
|
+
):
|
|
243
|
+
peer_side = RelationshipSideChoices.OPPOSITE[side]
|
|
244
|
+
for relationship in relationships:
|
|
245
|
+
if getattr(relationship, f"{side}_hidden") and not include_hidden:
|
|
246
|
+
continue
|
|
247
|
+
|
|
248
|
+
# Determine if the relationship is applicable to this object based on the filter
|
|
249
|
+
# To resolve the filter we are using the FilterSet for the given model
|
|
250
|
+
# If there is no match when we query our id along with the filter
|
|
251
|
+
# Then the relationship is not applicable to this object
|
|
252
|
+
if getattr(relationship, f"{side}_filter"):
|
|
253
|
+
filterset = get_filterset_for_model(self._meta.model)
|
|
254
|
+
if filterset:
|
|
255
|
+
filter_params = getattr(relationship, f"{side}_filter")
|
|
256
|
+
if not filterset(filter_params, self._meta.model.objects.filter(id=self.id)).qs.exists():
|
|
257
|
+
continue
|
|
258
|
+
|
|
259
|
+
# Construct the queryset for related objects for this relationship
|
|
260
|
+
remote_ct = getattr(relationship, f"{peer_side}_type")
|
|
261
|
+
remote_model = remote_ct.model_class()
|
|
262
|
+
if remote_model is not None:
|
|
263
|
+
if not relationship.symmetric:
|
|
264
|
+
query_params = {f"{peer_side}_for_associations__relationship": relationship.pk}
|
|
265
|
+
resp[side][relationship] = remote_model.objects.filter(**query_params)
|
|
266
|
+
if not relationship.has_many(peer_side):
|
|
267
|
+
resp[side][relationship] = resp[side][relationship].first()
|
|
268
|
+
else:
|
|
269
|
+
resp[RelationshipSideChoices.SIDE_PEER][relationship] = remote_model.objects.filter(
|
|
270
|
+
Q(source_for_associations__relationship=relationship.pk)
|
|
271
|
+
| Q(destination_for_associations__relationship=relationship.pk)
|
|
272
|
+
).exclude(pk=self.pk)
|
|
273
|
+
if not relationship.has_many(peer_side):
|
|
274
|
+
resp[side][relationship] = resp[side][relationship].first()
|
|
275
|
+
else:
|
|
276
|
+
# Maybe an uninstalled App?
|
|
277
|
+
# We can't provide a relevant queryset, but we can provide a descriptive string
|
|
278
|
+
if not relationship.symmetric:
|
|
279
|
+
count = RelationshipAssociation.objects.filter(
|
|
280
|
+
relationship=relationship, **{f"{side}_id": self.pk}
|
|
281
|
+
).count()
|
|
282
|
+
resp[side][relationship] = f"{count} {remote_ct} object(s)"
|
|
283
|
+
else:
|
|
284
|
+
count = (
|
|
285
|
+
RelationshipAssociation.objects.filter(relationship=relationship)
|
|
286
|
+
.filter(Q(source_id=self.pk) | Q(destination_id=self.pk))
|
|
287
|
+
.count()
|
|
288
|
+
)
|
|
289
|
+
resp[RelationshipSideChoices.SIDE_PEER][relationship] = f"{count} {remote_ct} object(s)"
|
|
290
|
+
|
|
291
|
+
return resp
|
|
292
|
+
|
|
225
293
|
@classmethod
|
|
226
294
|
def required_related_objects_errors(
|
|
227
295
|
cls, output_for="ui", initial_data=None, relationships_key_specified=False, instance=None
|
|
@@ -46,6 +46,11 @@ class Secret(PrimaryModel):
|
|
|
46
46
|
def __str__(self):
|
|
47
47
|
return self.name
|
|
48
48
|
|
|
49
|
+
def get_provider_display(self):
|
|
50
|
+
if provider := registry["secrets_providers"].get(self.provider):
|
|
51
|
+
return provider.name
|
|
52
|
+
return self.provider
|
|
53
|
+
|
|
49
54
|
def rendered_parameters(self, obj=None):
|
|
50
55
|
"""Render self.parameters as a Jinja2 template with the given object as context."""
|
|
51
56
|
try:
|