nautobot 2.3.16__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 +140 -23
- nautobot/cloud/api/views.py +6 -10
- nautobot/cloud/factory.py +4 -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/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 +45 -259
- nautobot/core/api/urls.py +3 -4
- nautobot/core/api/utils.py +0 -62
- nautobot/core/api/views.py +99 -157
- nautobot/core/apps/__init__.py +22 -578
- nautobot/core/celery/__init__.py +13 -0
- nautobot/core/celery/schedulers.py +47 -2
- 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/forms/__init__.py +19 -19
- nautobot/core/forms/fields.py +57 -9
- nautobot/core/forms/forms.py +33 -2
- nautobot/core/forms/utils.py +2 -1
- nautobot/core/graphql/schema.py +3 -1
- nautobot/core/jobs/__init__.py +24 -3
- nautobot/core/jobs/bulk_actions.py +248 -0
- nautobot/core/jobs/cleanup.py +1 -1
- nautobot/core/management/commands/generate_test_data.py +21 -0
- nautobot/core/middleware.py +16 -0
- nautobot/core/models/fields.py +11 -7
- nautobot/core/settings.py +68 -4
- nautobot/core/settings.yaml +99 -0
- nautobot/core/tables.py +10 -46
- 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/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 +13 -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 +41 -35
- nautobot/core/testing/forms.py +2 -0
- nautobot/core/testing/views.py +65 -148
- nautobot/core/tests/integration/test_view_authentication.py +1 -1
- nautobot/core/tests/nautobot_config.py +198 -0
- nautobot/core/tests/runner.py +2 -2
- 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 +124 -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 +6 -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 +37 -140
- nautobot/core/views/mixins.py +82 -32
- 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 +34 -141
- 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 +219 -9
- 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/devices.py +180 -2
- nautobot/dcim/models/racks.py +2 -2
- nautobot/dcim/navigation.py +25 -224
- nautobot/dcim/signals.py +44 -0
- nautobot/dcim/tables/__init__.py +2 -0
- nautobot/dcim/tables/devices.py +103 -7
- 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 +171 -76
- nautobot/dcim/tests/test_jobs.py +118 -0
- nautobot/dcim/tests/test_models.py +157 -6
- 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 +356 -61
- nautobot/extras/api/serializers.py +39 -18
- nautobot/extras/api/urls.py +4 -0
- nautobot/extras/api/views.py +89 -31
- 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 +2 -2
- nautobot/extras/graphql/types.py +25 -1
- nautobot/extras/jobs.py +109 -15
- 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/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/groups.py +0 -2
- nautobot/extras/models/jobs.py +233 -33
- 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 +103 -60
- nautobot/extras/registry.py +1 -1
- nautobot/extras/secrets/__init__.py +2 -2
- nautobot/extras/signals.py +39 -1
- nautobot/extras/tables.py +37 -1
- 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/singleton.py +16 -0
- nautobot/extras/tests/test_api.py +145 -43
- nautobot/extras/tests/test_context_managers.py +4 -1
- nautobot/extras/tests/test_filters.py +213 -529
- nautobot/extras/tests/test_job_variables.py +73 -152
- nautobot/extras/tests/test_jobs.py +181 -51
- nautobot/extras/tests/test_models.py +61 -6
- nautobot/extras/tests/test_plugins.py +62 -9
- nautobot/extras/tests/test_relationships.py +123 -9
- nautobot/extras/tests/test_utils.py +23 -2
- nautobot/extras/tests/test_views.py +146 -145
- nautobot/extras/tests/test_webhooks.py +2 -1
- nautobot/extras/urls.py +2 -20
- nautobot/extras/utils.py +119 -4
- nautobot/extras/views.py +168 -125
- nautobot/extras/webhooks.py +5 -2
- nautobot/ipam/api/serializers.py +10 -103
- nautobot/ipam/api/views.py +31 -49
- 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/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 +7 -5
- nautobot/ipam/tests/test_filters.py +39 -119
- nautobot/ipam/tests/test_forms.py +0 -2
- nautobot/ipam/tests/test_models.py +56 -36
- 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 +461 -17
- nautobot/project-static/docs/apps/index.html +461 -17
- nautobot/project-static/docs/apps/nautobot-apps.html +462 -19
- nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
- nautobot/project-static/docs/assets/extra.css +5 -1
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +477 -23
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +474 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +790 -289
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +505 -31
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +510 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +471 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +467 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +497 -33
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +9883 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +523 -75
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +546 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +670 -94
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1030 -177
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +524 -49
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +874 -188
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +955 -235
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +475 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +486 -28
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +661 -99
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +947 -479
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +6425 -1234
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +474 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +877 -344
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +828 -171
- nautobot/project-static/docs/development/apps/api/configuration-view.html +461 -17
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +461 -17
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +461 -17
- nautobot/project-static/docs/development/apps/api/models/global-search.html +461 -17
- nautobot/project-static/docs/development/apps/api/models/graphql.html +461 -17
- nautobot/project-static/docs/development/apps/api/models/index.html +461 -17
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +461 -17
- nautobot/project-static/docs/development/apps/api/prometheus.html +461 -17
- nautobot/project-static/docs/development/apps/api/setup.html +465 -153
- nautobot/project-static/docs/development/apps/api/testing.html +461 -17
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +461 -17
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +461 -17
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +461 -17
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +461 -17
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +741 -128
- nautobot/project-static/docs/development/apps/api/views/base-template.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/index.html +463 -18
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +465 -17
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +491 -17
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/notes.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +467 -19
- nautobot/project-static/docs/development/apps/api/views/urls.html +461 -17
- nautobot/project-static/docs/development/apps/index.html +461 -17
- nautobot/project-static/docs/development/apps/migration/code-updates.html +462 -50
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +462 -18
- nautobot/project-static/docs/development/apps/migration/from-v1.html +461 -17
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +461 -17
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +461 -17
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +461 -17
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +464 -20
- 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 +464 -20
- nautobot/project-static/docs/development/core/application-registry.html +461 -17
- nautobot/project-static/docs/development/core/best-practices.html +461 -17
- nautobot/project-static/docs/development/core/bootstrap-ui.html +461 -17
- nautobot/project-static/docs/development/core/caching.html +461 -17
- nautobot/project-static/docs/development/core/controllers.html +463 -17
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +464 -20
- nautobot/project-static/docs/development/core/generic-views.html +461 -17
- nautobot/project-static/docs/development/core/getting-started.html +539 -127
- nautobot/project-static/docs/development/core/homepage.html +472 -28
- nautobot/project-static/docs/development/core/index.html +461 -17
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +9754 -0
- nautobot/project-static/docs/development/core/model-checklist.html +471 -25
- nautobot/project-static/docs/development/core/model-features.html +461 -17
- nautobot/project-static/docs/development/core/natural-keys.html +461 -17
- nautobot/project-static/docs/development/core/navigation-menu.html +478 -24
- nautobot/project-static/docs/development/core/release-checklist.html +478 -46
- nautobot/project-static/docs/development/core/role-internals.html +461 -17
- nautobot/project-static/docs/development/core/settings.html +461 -17
- nautobot/project-static/docs/development/core/style-guide.html +464 -20
- nautobot/project-static/docs/development/core/templates.html +471 -20
- nautobot/project-static/docs/development/core/testing.html +461 -17
- nautobot/project-static/docs/development/core/ui-component-framework.html +11116 -0
- nautobot/project-static/docs/development/core/user-preferences.html +464 -20
- nautobot/project-static/docs/development/index.html +461 -17
- nautobot/project-static/docs/development/jobs/index.html +499 -19
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +461 -17
- nautobot/project-static/docs/index.html +469 -36
- 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 +467 -21
- nautobot/project-static/docs/overview/design_philosophy.html +461 -17
- nautobot/project-static/docs/release-notes/index.html +483 -20
- nautobot/project-static/docs/release-notes/version-1.0.html +649 -206
- nautobot/project-static/docs/release-notes/version-1.1.html +646 -203
- nautobot/project-static/docs/release-notes/version-1.2.html +721 -278
- nautobot/project-static/docs/release-notes/version-1.3.html +747 -304
- nautobot/project-static/docs/release-notes/version-1.4.html +832 -390
- nautobot/project-static/docs/release-notes/version-1.5.html +1020 -579
- nautobot/project-static/docs/release-notes/version-1.6.html +940 -516
- nautobot/project-static/docs/release-notes/version-2.0.html +943 -502
- nautobot/project-static/docs/release-notes/version-2.1.html +778 -337
- nautobot/project-static/docs/release-notes/version-2.2.html +771 -330
- nautobot/project-static/docs/release-notes/version-2.3.html +914 -471
- nautobot/project-static/docs/release-notes/version-2.4.html +10323 -0
- 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 +461 -17
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +461 -17
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +461 -17
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +473 -30
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +461 -17
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +842 -155
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +474 -27
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +461 -17
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +461 -17
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +461 -17
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +481 -21
- nautobot/project-static/docs/user-guide/administration/installation/index.html +466 -18
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +462 -18
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +461 -17
- nautobot/project-static/docs/user-guide/administration/installation/services.html +461 -17
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +461 -17
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +482 -39
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +475 -64
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +475 -64
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +464 -21
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +461 -17
- 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 +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +467 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +497 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +487 -20
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +461 -17
- 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 +468 -28
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +464 -20
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +464 -20
- 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 +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +466 -20
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +461 -17
- 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 +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +464 -20
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
- nautobot/project-static/docs/user-guide/index.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +465 -21
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +9617 -0
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +470 -21
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +461 -17
- 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 +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +465 -21
- 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 +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +509 -38
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +492 -21
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +529 -54
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +461 -17
- 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 +2 -0
- nautobot/users/api/views.py +2 -2
- 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/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.16.dist-info → nautobot-2.4.0.dist-info}/METADATA +9 -12
- {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/RECORD +720 -549
- nautobot/core/utils/navigation.py +0 -54
- {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/NOTICE +0 -0
- {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/WHEEL +0 -0
- {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Generated by Django 4.2.15 on 2024-08-20 14:58
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
from nautobot.extras.choices import JobQueueTypeChoices
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def migrate_task_queues_to_job_queues(apps, schema):
|
|
9
|
+
# Get the relevant models
|
|
10
|
+
Job = apps.get_model("extras", "Job")
|
|
11
|
+
ScheduledJob = apps.get_model("extras", "ScheduledJob")
|
|
12
|
+
JobQueue = apps.get_model("extras", "JobQueue")
|
|
13
|
+
|
|
14
|
+
# should always create default job queue
|
|
15
|
+
JobQueue.objects.get_or_create(name="default", defaults={"queue_type": JobQueueTypeChoices.TYPE_CELERY})
|
|
16
|
+
for job in Job.objects.all():
|
|
17
|
+
task_queues = job.task_queues
|
|
18
|
+
if len(task_queues) > 0:
|
|
19
|
+
default_job_queue, _ = JobQueue.objects.get_or_create(
|
|
20
|
+
name=task_queues[0], defaults={"queue_type": JobQueueTypeChoices.TYPE_CELERY}
|
|
21
|
+
)
|
|
22
|
+
else:
|
|
23
|
+
default_job_queue = JobQueue.objects.get(name="default")
|
|
24
|
+
job.default_job_queue = default_job_queue
|
|
25
|
+
job.save()
|
|
26
|
+
# Go through each task_queue
|
|
27
|
+
# make or get the corresponding job_queue object and assign it to the job
|
|
28
|
+
job_queues = [job.default_job_queue]
|
|
29
|
+
for task_queue in task_queues[1:]:
|
|
30
|
+
job_queue, _ = JobQueue.objects.get_or_create(
|
|
31
|
+
name=task_queue, defaults={"queue_type": JobQueueTypeChoices.TYPE_CELERY}
|
|
32
|
+
)
|
|
33
|
+
job_queues.append(job_queue)
|
|
34
|
+
job.job_queues.set(job_queues)
|
|
35
|
+
|
|
36
|
+
for sj in ScheduledJob.objects.all():
|
|
37
|
+
queue = sj.queue
|
|
38
|
+
job_queue = None
|
|
39
|
+
if queue:
|
|
40
|
+
job_queue, _ = JobQueue.objects.get_or_create(
|
|
41
|
+
name=queue, defaults={"queue_type": JobQueueTypeChoices.TYPE_CELERY}
|
|
42
|
+
)
|
|
43
|
+
sj.job_queue = job_queue
|
|
44
|
+
sj.save()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def reverse_migrate_task_queues_to_job_queues(apps, schema):
|
|
48
|
+
Job = apps.get_model("extras", "Job")
|
|
49
|
+
ScheduledJob = apps.get_model("extras", "ScheduledJob")
|
|
50
|
+
JobQueueAssignment = apps.get_model("extras", "JobQueueAssignment")
|
|
51
|
+
|
|
52
|
+
for job in Job.objects.all():
|
|
53
|
+
queue_names = list(job.job_queues.all().values_list("name", flat=True))
|
|
54
|
+
job.task_queues = queue_names
|
|
55
|
+
job.save()
|
|
56
|
+
JobQueueAssignment.objects.all().delete()
|
|
57
|
+
|
|
58
|
+
for sj in ScheduledJob.objects.all():
|
|
59
|
+
job_queue = sj.job_queue
|
|
60
|
+
if job_queue:
|
|
61
|
+
sj.queue = job_queue.name
|
|
62
|
+
else:
|
|
63
|
+
sj.queue = ""
|
|
64
|
+
sj.job_queue = None
|
|
65
|
+
sj.save()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class Migration(migrations.Migration):
|
|
69
|
+
dependencies = [
|
|
70
|
+
("extras", "0117_create_job_queue_model"),
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
operations = [
|
|
74
|
+
migrations.RunPython(
|
|
75
|
+
code=migrate_task_queues_to_job_queues,
|
|
76
|
+
reverse_code=reverse_migrate_task_queues_to_job_queues,
|
|
77
|
+
)
|
|
78
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Generated by Django 4.2.15 on 2024-08-28 15:49
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
import django.db.models.deletion
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
dependencies = [
|
|
9
|
+
("extras", "0118_task_queue_to_job_queue_migration"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.RemoveField(
|
|
14
|
+
model_name="job",
|
|
15
|
+
name="task_queues",
|
|
16
|
+
),
|
|
17
|
+
migrations.RemoveField(
|
|
18
|
+
model_name="scheduledjob",
|
|
19
|
+
name="queue",
|
|
20
|
+
),
|
|
21
|
+
migrations.AlterField(
|
|
22
|
+
model_name="job",
|
|
23
|
+
name="default_job_queue",
|
|
24
|
+
field=models.ForeignKey(
|
|
25
|
+
on_delete=django.db.models.deletion.PROTECT, related_name="default_for_jobs", to="extras.jobqueue"
|
|
26
|
+
),
|
|
27
|
+
),
|
|
28
|
+
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Generated by Django 4.2.16 on 2024-11-11 07:04
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("extras", "0119_remove_task_queues_from_job_and_queue_from_scheduled_job"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AddField(
|
|
13
|
+
model_name="job",
|
|
14
|
+
name="is_singleton",
|
|
15
|
+
field=models.BooleanField(default=False),
|
|
16
|
+
),
|
|
17
|
+
migrations.AddField(
|
|
18
|
+
model_name="job",
|
|
19
|
+
name="is_singleton_override",
|
|
20
|
+
field=models.BooleanField(default=False),
|
|
21
|
+
),
|
|
22
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Generated by Django 4.2.16 on 2024-12-03 15:32
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("extras", "0120_job_is_singleton_job_is_singleton_override"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AlterField(
|
|
13
|
+
model_name="team",
|
|
14
|
+
name="contacts",
|
|
15
|
+
field=models.ManyToManyField(blank=True, related_name="teams", to="extras.contact"),
|
|
16
|
+
),
|
|
17
|
+
]
|
|
@@ -8,6 +8,8 @@ from .jobs import (
|
|
|
8
8
|
JobButton,
|
|
9
9
|
JobHook,
|
|
10
10
|
JobLogEntry,
|
|
11
|
+
JobQueue,
|
|
12
|
+
JobQueueAssignment,
|
|
11
13
|
JobResult,
|
|
12
14
|
ScheduledJob,
|
|
13
15
|
ScheduledJobs,
|
|
@@ -66,6 +68,8 @@ __all__ = (
|
|
|
66
68
|
"JobButton",
|
|
67
69
|
"JobHook",
|
|
68
70
|
"JobLogEntry",
|
|
71
|
+
"JobQueue",
|
|
72
|
+
"JobQueueAssignment",
|
|
69
73
|
"JobResult",
|
|
70
74
|
"MetadataChoice",
|
|
71
75
|
"MetadataType",
|
|
@@ -73,8 +77,8 @@ __all__ = (
|
|
|
73
77
|
"ObjectChange",
|
|
74
78
|
"ObjectMetadata",
|
|
75
79
|
"Relationship",
|
|
76
|
-
"RelationshipModel",
|
|
77
80
|
"RelationshipAssociation",
|
|
81
|
+
"RelationshipModel",
|
|
78
82
|
"Role",
|
|
79
83
|
"RoleField",
|
|
80
84
|
"SavedView",
|
|
@@ -169,14 +169,18 @@ class ObjectChange(BaseModel):
|
|
|
169
169
|
def get_action_class(self):
|
|
170
170
|
return ObjectChangeActionChoices.CSS_CLASSES.get(self.action)
|
|
171
171
|
|
|
172
|
-
def get_next_change(self, user=None):
|
|
172
|
+
def get_next_change(self, user=None, only=None):
|
|
173
173
|
"""Return next change for this changed object, optionally restricting by user view permission"""
|
|
174
174
|
related_changes = self.get_related_changes(user=user)
|
|
175
|
+
if only:
|
|
176
|
+
related_changes = related_changes.only(*only)
|
|
175
177
|
return related_changes.filter(time__gt=self.time).order_by("time").first()
|
|
176
178
|
|
|
177
|
-
def get_prev_change(self, user=None):
|
|
179
|
+
def get_prev_change(self, user=None, only=None):
|
|
178
180
|
"""Return previous change for this changed object, optionally restricting by user view permission"""
|
|
179
181
|
related_changes = self.get_related_changes(user=user)
|
|
182
|
+
if only:
|
|
183
|
+
related_changes = related_changes.only(*only)
|
|
180
184
|
return related_changes.filter(time__lt=self.time).order_by("-time").first()
|
|
181
185
|
|
|
182
186
|
def get_related_changes(self, user=None, permission="view"):
|
|
@@ -207,7 +211,7 @@ class ObjectChange(BaseModel):
|
|
|
207
211
|
prechange = None
|
|
208
212
|
postchange = None
|
|
209
213
|
|
|
210
|
-
prior_change = self.get_prev_change()
|
|
214
|
+
prior_change = self.get_prev_change(only=["object_data_v2", "object_data"])
|
|
211
215
|
|
|
212
216
|
if self.action != ObjectChangeActionChoices.ACTION_CREATE and prior_change is not None:
|
|
213
217
|
prechange = prior_change.object_data_v2
|
|
@@ -61,7 +61,7 @@ class Contact(ContactTeamSharedBase):
|
|
|
61
61
|
class Team(ContactTeamSharedBase):
|
|
62
62
|
"""A group of Contacts, usable interchangeably with a single Contact in most cases."""
|
|
63
63
|
|
|
64
|
-
contacts = models.ManyToManyField(to=Contact, related_name="teams")
|
|
64
|
+
contacts = models.ManyToManyField(to=Contact, related_name="teams", blank=True)
|
|
65
65
|
|
|
66
66
|
class Meta(ContactTeamSharedBase.Meta):
|
|
67
67
|
abstract = False
|
nautobot/extras/models/groups.py
CHANGED
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"
|
|
@@ -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
|
#
|
|
@@ -616,7 +748,7 @@ class JobResult(BaseModel, CustomFieldModel):
|
|
|
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
|