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
nautobot/extras/utils.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import collections
|
|
2
2
|
import contextlib
|
|
3
|
+
import copy
|
|
3
4
|
import hashlib
|
|
4
5
|
import hmac
|
|
5
6
|
import logging
|
|
@@ -15,13 +16,15 @@ from django.db import transaction
|
|
|
15
16
|
from django.db.models import Q
|
|
16
17
|
from django.template.loader import get_template, TemplateDoesNotExist
|
|
17
18
|
from django.utils.deconstruct import deconstructible
|
|
19
|
+
import kubernetes.client
|
|
18
20
|
import redis.exceptions
|
|
19
21
|
|
|
20
22
|
from nautobot.core.choices import ColorChoices
|
|
21
23
|
from nautobot.core.constants import CHARFIELD_MAX_LENGTH
|
|
22
24
|
from nautobot.core.models.managers import TagsManager
|
|
23
25
|
from nautobot.core.models.utils import find_models_with_matching_fields
|
|
24
|
-
from nautobot.
|
|
26
|
+
from nautobot.core.utils.data import is_uuid
|
|
27
|
+
from nautobot.extras.choices import DynamicGroupTypeChoices, JobQueueTypeChoices, ObjectChangeActionChoices
|
|
25
28
|
from nautobot.extras.constants import (
|
|
26
29
|
CHANGELOG_MAX_CHANGE_CONTEXT_DETAIL,
|
|
27
30
|
EXTRAS_FEATURES,
|
|
@@ -395,15 +398,68 @@ def get_celery_queues():
|
|
|
395
398
|
|
|
396
399
|
|
|
397
400
|
def get_worker_count(request=None, queue=None):
|
|
401
|
+
"""
|
|
402
|
+
Return a count of the active Celery workers in a specified queue (Could be a JobQueue instance, instance pk or instance name).
|
|
403
|
+
Defaults to the `CELERY_TASK_DEFAULT_QUEUE` setting.
|
|
404
|
+
"""
|
|
405
|
+
from nautobot.extras.models import JobQueue
|
|
406
|
+
|
|
407
|
+
celery_queues = get_celery_queues()
|
|
408
|
+
if isinstance(queue, str):
|
|
409
|
+
if is_uuid(queue):
|
|
410
|
+
try:
|
|
411
|
+
# check if the string passed in is a valid UUID
|
|
412
|
+
queue = JobQueue.objects.get(pk=queue).name
|
|
413
|
+
except JobQueue.DoesNotExist:
|
|
414
|
+
return 0
|
|
415
|
+
else:
|
|
416
|
+
return celery_queues.get(queue, 0)
|
|
417
|
+
elif isinstance(queue, JobQueue):
|
|
418
|
+
queue = queue.name
|
|
419
|
+
else:
|
|
420
|
+
queue = settings.CELERY_TASK_DEFAULT_QUEUE
|
|
421
|
+
|
|
422
|
+
return celery_queues.get(queue, 0)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def get_job_queue_worker_count(request=None, job_queue=None):
|
|
398
426
|
"""
|
|
399
427
|
Return a count of the active Celery workers in a specified queue. Defaults to the `CELERY_TASK_DEFAULT_QUEUE` setting.
|
|
428
|
+
Same as get_worker_count() method above, but job_queue is an actual JobQueue model instance.
|
|
400
429
|
"""
|
|
430
|
+
# TODO currently this method is only retrieve celery specific queues and their respective worker counts
|
|
431
|
+
# Refactor it to support retrieving kubernetes queues as well.
|
|
401
432
|
celery_queues = get_celery_queues()
|
|
402
|
-
if not
|
|
433
|
+
if not job_queue:
|
|
403
434
|
queue = settings.CELERY_TASK_DEFAULT_QUEUE
|
|
435
|
+
else:
|
|
436
|
+
queue = job_queue.name
|
|
404
437
|
return celery_queues.get(queue, 0)
|
|
405
438
|
|
|
406
439
|
|
|
440
|
+
def get_job_queue(job_queue):
|
|
441
|
+
"""
|
|
442
|
+
Search for a JobQueue instance based on the str job_queue.
|
|
443
|
+
If no existing Job Queue not found, return None
|
|
444
|
+
"""
|
|
445
|
+
from nautobot.extras.models import JobQueue
|
|
446
|
+
|
|
447
|
+
queue = None
|
|
448
|
+
if is_uuid(job_queue):
|
|
449
|
+
try:
|
|
450
|
+
# check if the string passed in is a valid UUID
|
|
451
|
+
queue = JobQueue.objects.get(pk=job_queue)
|
|
452
|
+
except JobQueue.DoesNotExist:
|
|
453
|
+
queue = None
|
|
454
|
+
else:
|
|
455
|
+
try:
|
|
456
|
+
# check if the string passed in is a valid name
|
|
457
|
+
queue = JobQueue.objects.get(name=job_queue)
|
|
458
|
+
except JobQueue.DoesNotExist:
|
|
459
|
+
queue = None
|
|
460
|
+
return queue
|
|
461
|
+
|
|
462
|
+
|
|
407
463
|
def task_queues_as_choices(task_queues):
|
|
408
464
|
"""
|
|
409
465
|
Returns a list of 2-tuples for use in the form field `choices` argument. Appends
|
|
@@ -424,13 +480,17 @@ def task_queues_as_choices(task_queues):
|
|
|
424
480
|
return choices
|
|
425
481
|
|
|
426
482
|
|
|
427
|
-
def refresh_job_model_from_job_class(job_model_class, job_class):
|
|
483
|
+
def refresh_job_model_from_job_class(job_model_class, job_class, job_queue_class=None):
|
|
428
484
|
"""
|
|
429
485
|
Create or update a job_model record based on the metadata of the provided job_class.
|
|
430
486
|
|
|
431
|
-
Note that job_model_class
|
|
487
|
+
Note that `job_model_class` and `job_queue_class` are parameters rather than local imports because
|
|
432
488
|
this function may be called from various initialization processes (such as the "nautobot_database_ready" signal)
|
|
433
489
|
and in that case we need to not import models ourselves.
|
|
490
|
+
|
|
491
|
+
The `job_queue_class` parameter really should be required, but for some reason we decided to make this function
|
|
492
|
+
part of the `nautobot.apps.utils` API surface and so we need it to stay backwards-compatible with Apps that might
|
|
493
|
+
be calling the two-argument form of this function.
|
|
434
494
|
"""
|
|
435
495
|
from nautobot.extras.jobs import (
|
|
436
496
|
JobButtonReceiver,
|
|
@@ -502,6 +562,10 @@ def refresh_job_model_from_job_class(job_model_class, job_class):
|
|
|
502
562
|
|
|
503
563
|
try:
|
|
504
564
|
with transaction.atomic():
|
|
565
|
+
default_job_queue, _ = job_queue_class.objects.get_or_create(
|
|
566
|
+
name=job_class.task_queues[0] if job_class.task_queues else settings.CELERY_TASK_DEFAULT_QUEUE,
|
|
567
|
+
defaults={"queue_type": JobQueueTypeChoices.TYPE_CELERY},
|
|
568
|
+
)
|
|
505
569
|
job_model, created = job_model_class.objects.get_or_create(
|
|
506
570
|
module_name=job_class.__module__[:JOB_MAX_NAME_LENGTH],
|
|
507
571
|
job_class_name=job_class.__name__[:JOB_MAX_NAME_LENGTH],
|
|
@@ -514,6 +578,8 @@ def refresh_job_model_from_job_class(job_model_class, job_class):
|
|
|
514
578
|
"supports_dryrun": job_class.supports_dryrun,
|
|
515
579
|
"installed": True,
|
|
516
580
|
"enabled": False,
|
|
581
|
+
"default_job_queue": default_job_queue,
|
|
582
|
+
"is_singleton": job_class.is_singleton,
|
|
517
583
|
},
|
|
518
584
|
)
|
|
519
585
|
|
|
@@ -530,6 +596,19 @@ def refresh_job_model_from_job_class(job_model_class, job_class):
|
|
|
530
596
|
# It was inherited and not overridden
|
|
531
597
|
setattr(job_model, field_name, getattr(job_class, field_name))
|
|
532
598
|
|
|
599
|
+
# Special case for backward compatibility
|
|
600
|
+
# Note that the `job_model.task_queues` setter does NOT auto-create Celery JobQueue records;
|
|
601
|
+
# this is a special case where we DO want to do so.
|
|
602
|
+
if job_queue_class is not None and not job_model.job_queues_override:
|
|
603
|
+
job_queues = []
|
|
604
|
+
task_queues = job_class.task_queues or [settings.CELERY_TASK_DEFAULT_QUEUE]
|
|
605
|
+
for task_queue in task_queues:
|
|
606
|
+
job_queue, _ = job_queue_class.objects.get_or_create(
|
|
607
|
+
name=task_queue, defaults={"queue_type": JobQueueTypeChoices.TYPE_CELERY}
|
|
608
|
+
)
|
|
609
|
+
job_queues.append(job_queue)
|
|
610
|
+
job_model.job_queues.set(job_queues)
|
|
611
|
+
|
|
533
612
|
if not created:
|
|
534
613
|
# Mark it as installed regardless
|
|
535
614
|
job_model.installed = True
|
|
@@ -558,6 +637,42 @@ def refresh_job_model_from_job_class(job_model_class, job_class):
|
|
|
558
637
|
return (job_model, created)
|
|
559
638
|
|
|
560
639
|
|
|
640
|
+
def run_kubernetes_job_and_return_job_result(job_queue, job_result, job_kwargs):
|
|
641
|
+
"""
|
|
642
|
+
Pass the job to a kubernetes pod and execute it there.
|
|
643
|
+
"""
|
|
644
|
+
pod_name = settings.KUBERNETES_JOB_POD_NAME
|
|
645
|
+
pod_namespace = settings.KUBERNETES_JOB_POD_NAMESPACE
|
|
646
|
+
pod_manifest = copy.deepcopy(settings.KUBERNETES_JOB_MANIFEST)
|
|
647
|
+
pod_ssl_ca_cert = settings.KUBERNETES_SSL_CA_CERT_PATH
|
|
648
|
+
pod_token = settings.KUBERNETES_TOKEN_PATH
|
|
649
|
+
|
|
650
|
+
configuration = kubernetes.client.Configuration()
|
|
651
|
+
configuration.host = settings.KUBERNETES_DEFAULT_SERVICE_ADDRESS
|
|
652
|
+
configuration.ssl_ca_cert = pod_ssl_ca_cert
|
|
653
|
+
with open(pod_token, "r") as token_file:
|
|
654
|
+
token = token_file.read().strip()
|
|
655
|
+
# configure API Key authorization: BearerToken
|
|
656
|
+
configuration.api_key_prefix["authorization"] = "Bearer"
|
|
657
|
+
configuration.api_key["authorization"] = token
|
|
658
|
+
with kubernetes.client.ApiClient(configuration) as api_client:
|
|
659
|
+
api_instance = kubernetes.client.BatchV1Api(api_client)
|
|
660
|
+
|
|
661
|
+
job_result.task_kwargs = job_kwargs
|
|
662
|
+
job_result.save()
|
|
663
|
+
pod_manifest["metadata"]["name"] = "nautobot-job-" + str(job_result.pk)
|
|
664
|
+
pod_manifest["spec"]["template"]["spec"]["containers"][0]["command"] = [
|
|
665
|
+
"nautobot-server",
|
|
666
|
+
"runjob_with_job_result",
|
|
667
|
+
f"{job_result.pk}",
|
|
668
|
+
]
|
|
669
|
+
job_result.log(f"Creating job pod {pod_name} in namespace {pod_namespace}")
|
|
670
|
+
api_instance.create_namespaced_job(body=pod_manifest, namespace=pod_namespace)
|
|
671
|
+
job_result.log(f"Reading job pod {pod_name} in namespace {pod_namespace}")
|
|
672
|
+
api_instance.read_namespaced_job(name="nautobot-job-" + str(job_result.pk), namespace=pod_namespace)
|
|
673
|
+
return job_result
|
|
674
|
+
|
|
675
|
+
|
|
561
676
|
def remove_prefix_from_cf_key(field_name):
|
|
562
677
|
"""
|
|
563
678
|
field_name (str): f"cf_{cf.key}"
|
nautobot/extras/views.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from urllib.parse import parse_qs
|
|
3
3
|
|
|
4
|
-
from celery import chain
|
|
5
|
-
from django.conf import settings
|
|
6
4
|
from django.contrib import messages
|
|
7
5
|
from django.contrib.contenttypes.models import ContentType
|
|
8
6
|
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
|
@@ -18,21 +16,21 @@ from django.utils import timezone
|
|
|
18
16
|
from django.utils.encoding import iri_to_uri
|
|
19
17
|
from django.utils.html import format_html
|
|
20
18
|
from django.utils.http import url_has_allowed_host_and_scheme
|
|
19
|
+
from django.utils.timezone import get_current_timezone
|
|
21
20
|
from django.views.generic import View
|
|
22
21
|
from django_tables2 import RequestConfig
|
|
23
22
|
from jsonschema.validators import Draft7Validator
|
|
24
23
|
from rest_framework.decorators import action
|
|
25
24
|
from rest_framework.permissions import IsAuthenticated
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
except ImportError: # python 3.8
|
|
30
|
-
from backports.zoneinfo import ZoneInfo
|
|
31
|
-
|
|
26
|
+
from nautobot.core.constants import PAGINATE_COUNT_DEFAULT
|
|
27
|
+
from nautobot.core.events import publish_event
|
|
32
28
|
from nautobot.core.forms import restrict_form_fields
|
|
33
29
|
from nautobot.core.models.querysets import count_related
|
|
34
|
-
from nautobot.core.models.utils import pretty_print_query
|
|
30
|
+
from nautobot.core.models.utils import pretty_print_query, serialize_object_v2
|
|
35
31
|
from nautobot.core.tables import ButtonsColumn
|
|
32
|
+
from nautobot.core.ui import object_detail
|
|
33
|
+
from nautobot.core.ui.choices import SectionChoices
|
|
36
34
|
from nautobot.core.utils.config import get_settings_or_config
|
|
37
35
|
from nautobot.core.utils.lookup import (
|
|
38
36
|
get_filterset_for_model,
|
|
@@ -45,6 +43,7 @@ from nautobot.core.utils.requests import normalize_querydict
|
|
|
45
43
|
from nautobot.core.views import generic, viewsets
|
|
46
44
|
from nautobot.core.views.mixins import (
|
|
47
45
|
GetReturnURLMixin,
|
|
46
|
+
ObjectBulkCreateViewMixin,
|
|
48
47
|
ObjectBulkDestroyViewMixin,
|
|
49
48
|
ObjectBulkUpdateViewMixin,
|
|
50
49
|
ObjectChangeLogViewMixin,
|
|
@@ -52,18 +51,23 @@ from nautobot.core.views.mixins import (
|
|
|
52
51
|
ObjectDetailViewMixin,
|
|
53
52
|
ObjectEditViewMixin,
|
|
54
53
|
ObjectListViewMixin,
|
|
54
|
+
ObjectNotesViewMixin,
|
|
55
55
|
ObjectPermissionRequiredMixin,
|
|
56
56
|
)
|
|
57
57
|
from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
|
|
58
58
|
from nautobot.core.views.utils import prepare_cloned_fields
|
|
59
59
|
from nautobot.core.views.viewsets import NautobotUIViewSet
|
|
60
|
-
from nautobot.dcim.models import Controller, Device, Interface, Module, Rack
|
|
61
|
-
from nautobot.dcim.tables import
|
|
62
|
-
|
|
60
|
+
from nautobot.dcim.models import Controller, Device, Interface, Module, Rack, VirtualDeviceContext
|
|
61
|
+
from nautobot.dcim.tables import (
|
|
62
|
+
ControllerTable,
|
|
63
|
+
DeviceTable,
|
|
64
|
+
InterfaceTable,
|
|
65
|
+
ModuleTable,
|
|
66
|
+
RackTable,
|
|
67
|
+
VirtualDeviceContextTable,
|
|
68
|
+
)
|
|
63
69
|
from nautobot.extras.context_managers import deferred_change_logging_for_bulk_operation
|
|
64
|
-
from nautobot.extras.
|
|
65
|
-
from nautobot.extras.tasks import delete_custom_field_data
|
|
66
|
-
from nautobot.extras.utils import get_base_template, get_worker_count
|
|
70
|
+
from nautobot.extras.utils import get_base_template, get_job_queue, get_worker_count
|
|
67
71
|
from nautobot.ipam.models import IPAddress, Prefix, VLAN
|
|
68
72
|
from nautobot.ipam.tables import IPAddressTable, PrefixTable, VLANTable
|
|
69
73
|
from nautobot.virtualization.models import VirtualMachine, VMInterface
|
|
@@ -71,7 +75,13 @@ from nautobot.virtualization.tables import VirtualMachineTable, VMInterfaceTable
|
|
|
71
75
|
|
|
72
76
|
from . import filters, forms, tables
|
|
73
77
|
from .api import serializers
|
|
74
|
-
from .choices import
|
|
78
|
+
from .choices import (
|
|
79
|
+
DynamicGroupTypeChoices,
|
|
80
|
+
JobExecutionType,
|
|
81
|
+
JobQueueTypeChoices,
|
|
82
|
+
JobResultStatusChoices,
|
|
83
|
+
LogLevelChoices,
|
|
84
|
+
)
|
|
75
85
|
from .datasources import (
|
|
76
86
|
enqueue_git_repository_diff_origin_and_local,
|
|
77
87
|
enqueue_pull_git_repository_and_refresh_data,
|
|
@@ -96,6 +106,7 @@ from .models import (
|
|
|
96
106
|
JobButton,
|
|
97
107
|
JobHook,
|
|
98
108
|
JobLogEntry,
|
|
109
|
+
JobQueue,
|
|
99
110
|
JobResult,
|
|
100
111
|
MetadataType,
|
|
101
112
|
Note,
|
|
@@ -643,37 +654,7 @@ class CustomFieldBulkDeleteView(generic.BulkDeleteView):
|
|
|
643
654
|
queryset = CustomField.objects.all()
|
|
644
655
|
table = tables.CustomFieldTable
|
|
645
656
|
filterset = filters.CustomFieldFilterSet
|
|
646
|
-
|
|
647
|
-
def construct_custom_field_delete_tasks(self, queryset):
|
|
648
|
-
"""
|
|
649
|
-
Helper method to construct a list of celery tasks to execute when bulk deleting custom fields.
|
|
650
|
-
"""
|
|
651
|
-
change_context = change_context_state.get()
|
|
652
|
-
if change_context is None:
|
|
653
|
-
context = None
|
|
654
|
-
else:
|
|
655
|
-
context = change_context.as_dict(queryset)
|
|
656
|
-
context["context_detail"] = "bulk delete custom field data"
|
|
657
|
-
tasks = [
|
|
658
|
-
delete_custom_field_data.si(obj.key, set(obj.content_types.values_list("pk", flat=True)), context)
|
|
659
|
-
for obj in queryset
|
|
660
|
-
]
|
|
661
|
-
return tasks
|
|
662
|
-
|
|
663
|
-
def perform_pre_delete(self, request, queryset):
|
|
664
|
-
"""
|
|
665
|
-
Remove all Custom Field Keys/Values from _custom_field_data of the related ContentType in the background.
|
|
666
|
-
"""
|
|
667
|
-
if not get_worker_count():
|
|
668
|
-
messages.error(
|
|
669
|
-
request, "Celery worker process not running. Object custom fields may fail to reflect this deletion."
|
|
670
|
-
)
|
|
671
|
-
return
|
|
672
|
-
tasks = self.construct_custom_field_delete_tasks(queryset)
|
|
673
|
-
# Executing the tasks in the background sequentially using chain() aligns with how a single
|
|
674
|
-
# CustomField object is deleted. We decided to not check the result because it needs at least one worker
|
|
675
|
-
# to be active and comes with extra performance penalty.
|
|
676
|
-
chain(*tasks).apply_async()
|
|
657
|
+
form = forms.CustomFieldBulkDeleteForm
|
|
677
658
|
|
|
678
659
|
|
|
679
660
|
#
|
|
@@ -1006,6 +987,27 @@ class ExternalIntegrationUIViewSet(NautobotUIViewSet):
|
|
|
1006
987
|
serializer_class = serializers.ExternalIntegrationSerializer
|
|
1007
988
|
table_class = tables.ExternalIntegrationTable
|
|
1008
989
|
|
|
990
|
+
object_detail_content = object_detail.ObjectDetailContent(
|
|
991
|
+
panels=(
|
|
992
|
+
object_detail.ObjectFieldsPanel(
|
|
993
|
+
section=SectionChoices.LEFT_HALF,
|
|
994
|
+
weight=100,
|
|
995
|
+
# Default ordering with __all__ leaves something to be desired
|
|
996
|
+
fields=[
|
|
997
|
+
"name",
|
|
998
|
+
"remote_url",
|
|
999
|
+
"http_method",
|
|
1000
|
+
"headers",
|
|
1001
|
+
"verify_ssl",
|
|
1002
|
+
"ca_file_path",
|
|
1003
|
+
"secrets_group",
|
|
1004
|
+
"timeout",
|
|
1005
|
+
"extra_config",
|
|
1006
|
+
],
|
|
1007
|
+
),
|
|
1008
|
+
),
|
|
1009
|
+
)
|
|
1010
|
+
|
|
1009
1011
|
|
|
1010
1012
|
#
|
|
1011
1013
|
# Git repositories
|
|
@@ -1319,10 +1321,18 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
|
|
|
1319
1321
|
# for example "?kwargs_from_job_result=<UUID>&integervar=22"
|
|
1320
1322
|
explicit_initial = initial
|
|
1321
1323
|
initial = job_result.task_kwargs.copy()
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1324
|
+
job_queue = job_result.celery_kwargs.get("queue", None)
|
|
1325
|
+
jq = None
|
|
1326
|
+
if job_queue is not None:
|
|
1327
|
+
try:
|
|
1328
|
+
jq = JobQueue.objects.get(name=job_queue, queue_type=JobQueueTypeChoices.TYPE_CELERY)
|
|
1329
|
+
except JobQueue.DoesNotExist:
|
|
1330
|
+
pass
|
|
1331
|
+
initial["_job_queue"] = jq
|
|
1325
1332
|
initial["_profile"] = job_result.celery_kwargs.get("nautobot_job_profile", False)
|
|
1333
|
+
initial["_ignore_singleton_lock"] = job_result.celery_kwargs.get(
|
|
1334
|
+
"nautobot_job_ignore_singleton_lock", False
|
|
1335
|
+
)
|
|
1326
1336
|
initial.update(explicit_initial)
|
|
1327
1337
|
except JobResult.DoesNotExist:
|
|
1328
1338
|
messages.warning(
|
|
@@ -1362,7 +1372,7 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
|
|
|
1362
1372
|
job_class = get_job(job_model.class_path, reload=True)
|
|
1363
1373
|
job_form = job_class.as_form(request.POST, request.FILES) if job_class is not None else None
|
|
1364
1374
|
schedule_form = forms.JobScheduleForm(request.POST)
|
|
1365
|
-
|
|
1375
|
+
job_queue = request.POST.get("_job_queue")
|
|
1366
1376
|
|
|
1367
1377
|
return_url = request.POST.get("_return_url")
|
|
1368
1378
|
if return_url is not None and url_has_allowed_host_and_scheme(url=return_url, allowed_hosts=request.get_host()):
|
|
@@ -1370,8 +1380,11 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
|
|
|
1370
1380
|
else:
|
|
1371
1381
|
return_url = None
|
|
1372
1382
|
|
|
1373
|
-
|
|
1374
|
-
if
|
|
1383
|
+
queue = get_job_queue(job_queue)
|
|
1384
|
+
if queue is None:
|
|
1385
|
+
queue = job_model.default_job_queue
|
|
1386
|
+
# Allow execution only if a worker process is running on a celery queue and the job is runnable.
|
|
1387
|
+
if queue.queue_type == JobQueueTypeChoices.TYPE_CELERY and not get_worker_count(queue=job_queue):
|
|
1375
1388
|
messages.error(request, "Unable to run or schedule job: Celery worker process not running.")
|
|
1376
1389
|
elif not job_model.installed or job_class is None:
|
|
1377
1390
|
messages.error(request, "Unable to run or schedule job: Job is not presently installed.")
|
|
@@ -1390,10 +1403,21 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
|
|
|
1390
1403
|
"One of these two flags must be removed before this job can be scheduled or run.",
|
|
1391
1404
|
)
|
|
1392
1405
|
elif job_form is not None and job_form.is_valid() and schedule_form.is_valid():
|
|
1393
|
-
|
|
1406
|
+
job_queue = job_form.cleaned_data.pop("_job_queue", None)
|
|
1407
|
+
jq = None
|
|
1408
|
+
if job_queue is not None:
|
|
1409
|
+
try:
|
|
1410
|
+
jq = JobQueue.objects.get(pk=job_queue)
|
|
1411
|
+
except (ValidationError, JobQueue.DoesNotExist):
|
|
1412
|
+
try:
|
|
1413
|
+
jq = JobQueue.objects.get(name=job_queue)
|
|
1414
|
+
except JobQueue.DoesNotExist:
|
|
1415
|
+
pass
|
|
1416
|
+
|
|
1394
1417
|
dryrun = job_form.cleaned_data.get("dryrun", False)
|
|
1395
1418
|
# Run the job. A new JobResult is created.
|
|
1396
1419
|
profile = job_form.cleaned_data.pop("_profile")
|
|
1420
|
+
ignore_singleton_lock = job_form.cleaned_data.pop("_ignore_singleton_lock", False)
|
|
1397
1421
|
schedule_type = schedule_form.cleaned_data["_schedule_type"]
|
|
1398
1422
|
|
|
1399
1423
|
if (not dryrun and job_model.approval_required) or schedule_type in JobExecutionType.SCHEDULE_CHOICES:
|
|
@@ -1405,8 +1429,9 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
|
|
|
1405
1429
|
interval=schedule_type,
|
|
1406
1430
|
crontab=schedule_form.cleaned_data.get("_recurrence_custom_time"),
|
|
1407
1431
|
approval_required=job_model.approval_required,
|
|
1408
|
-
task_queue=
|
|
1432
|
+
task_queue=jq.name if jq else None,
|
|
1409
1433
|
profile=profile,
|
|
1434
|
+
ignore_singleton_lock=ignore_singleton_lock,
|
|
1410
1435
|
**job_class.serialize_data(job_form.cleaned_data),
|
|
1411
1436
|
)
|
|
1412
1437
|
|
|
@@ -1424,7 +1449,8 @@ class JobRunView(ObjectPermissionRequiredMixin, View):
|
|
|
1424
1449
|
job_model,
|
|
1425
1450
|
request.user,
|
|
1426
1451
|
profile=profile,
|
|
1427
|
-
|
|
1452
|
+
ignore_singleton_lock=ignore_singleton_lock,
|
|
1453
|
+
task_queue=jq.name if jq else None,
|
|
1428
1454
|
**job_class.serialize_data(job_kwargs),
|
|
1429
1455
|
)
|
|
1430
1456
|
|
|
@@ -1482,23 +1508,6 @@ class JobBulkEditView(generic.BulkEditView):
|
|
|
1482
1508
|
form = forms.JobBulkEditForm
|
|
1483
1509
|
template_name = "extras/job_bulk_edit.html"
|
|
1484
1510
|
|
|
1485
|
-
def extra_post_save_action(self, obj, form):
|
|
1486
|
-
cleaned_data = form.cleaned_data
|
|
1487
|
-
|
|
1488
|
-
# Handle text related fields
|
|
1489
|
-
for overridable_field in JOB_OVERRIDABLE_FIELDS:
|
|
1490
|
-
override_field = overridable_field + "_override"
|
|
1491
|
-
clear_override_field = "clear_" + overridable_field + "_override"
|
|
1492
|
-
reset_override = cleaned_data.get(clear_override_field, False)
|
|
1493
|
-
override_value = cleaned_data.get(overridable_field)
|
|
1494
|
-
if reset_override:
|
|
1495
|
-
setattr(obj, override_field, False)
|
|
1496
|
-
elif not reset_override and override_value not in [None, ""]:
|
|
1497
|
-
setattr(obj, override_field, True)
|
|
1498
|
-
setattr(obj, overridable_field, override_value)
|
|
1499
|
-
|
|
1500
|
-
obj.validated_save()
|
|
1501
|
-
|
|
1502
1511
|
|
|
1503
1512
|
class JobDeleteView(generic.ObjectDeleteView):
|
|
1504
1513
|
queryset = JobModel.objects.all()
|
|
@@ -1538,7 +1547,7 @@ class JobApprovalRequestView(generic.ObjectView):
|
|
|
1538
1547
|
if job_class is not None:
|
|
1539
1548
|
# Render the form with all fields disabled
|
|
1540
1549
|
initial = instance.kwargs
|
|
1541
|
-
initial["
|
|
1550
|
+
initial["_job_queue"] = instance.queue
|
|
1542
1551
|
initial["_profile"] = instance.celery_kwargs.get("profile", False)
|
|
1543
1552
|
job_form = job_class().as_form(initial=initial, approval_view=True)
|
|
1544
1553
|
else:
|
|
@@ -1597,12 +1606,15 @@ class JobApprovalRequestView(generic.ObjectView):
|
|
|
1597
1606
|
messages.error(request, "You do not have permission to deny this request.")
|
|
1598
1607
|
else:
|
|
1599
1608
|
# Delete the scheduled_job instance
|
|
1609
|
+
publish_event_payload = {"data": serialize_object_v2(scheduled_job)}
|
|
1600
1610
|
scheduled_job.delete()
|
|
1601
1611
|
if request.user == scheduled_job.user:
|
|
1602
1612
|
messages.error(request, f"Approval request for {scheduled_job.name} was revoked")
|
|
1603
1613
|
else:
|
|
1604
1614
|
messages.error(request, f"Approval of {scheduled_job.name} was denied")
|
|
1605
1615
|
|
|
1616
|
+
publish_event(topic="nautobot.jobs.approval.denied", payload=publish_event_payload)
|
|
1617
|
+
|
|
1606
1618
|
return redirect("extras:scheduledjob_approval_queue_list")
|
|
1607
1619
|
|
|
1608
1620
|
elif approve or force_approve:
|
|
@@ -1624,6 +1636,9 @@ class JobApprovalRequestView(generic.ObjectView):
|
|
|
1624
1636
|
scheduled_job.approved_at = timezone.now()
|
|
1625
1637
|
scheduled_job.save()
|
|
1626
1638
|
|
|
1639
|
+
publish_event_payload = {"data": serialize_object_v2(scheduled_job)}
|
|
1640
|
+
publish_event(topic="nautobot.jobs.approval.approved", payload=publish_event_payload)
|
|
1641
|
+
|
|
1627
1642
|
messages.success(request, f"{scheduled_job.name} was approved and will now begin execution")
|
|
1628
1643
|
|
|
1629
1644
|
return redirect("extras:scheduledjob_approval_queue_list")
|
|
@@ -1638,6 +1653,28 @@ class JobApprovalRequestView(generic.ObjectView):
|
|
|
1638
1653
|
)
|
|
1639
1654
|
|
|
1640
1655
|
|
|
1656
|
+
class JobQueueUIViewSet(NautobotUIViewSet):
|
|
1657
|
+
bulk_update_form_class = forms.JobQueueBulkEditForm
|
|
1658
|
+
filterset_form_class = forms.JobQueueFilterForm
|
|
1659
|
+
queryset = JobQueue.objects.all()
|
|
1660
|
+
form_class = forms.JobQueueForm
|
|
1661
|
+
filterset_class = filters.JobQueueFilterSet
|
|
1662
|
+
serializer_class = serializers.JobQueueSerializer
|
|
1663
|
+
table_class = tables.JobQueueTable
|
|
1664
|
+
|
|
1665
|
+
def get_extra_context(self, request, instance):
|
|
1666
|
+
context = super().get_extra_context(request, instance)
|
|
1667
|
+
|
|
1668
|
+
if self.action == "retrieve":
|
|
1669
|
+
jobs = instance.jobs.restrict(request.user, "view")
|
|
1670
|
+
jobs_table = tables.JobTable(jobs, orderable=False)
|
|
1671
|
+
paginate = {"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
|
|
1672
|
+
RequestConfig(request, paginate).configure(jobs_table)
|
|
1673
|
+
context["jobs_table"] = jobs_table
|
|
1674
|
+
|
|
1675
|
+
return context
|
|
1676
|
+
|
|
1677
|
+
|
|
1641
1678
|
#
|
|
1642
1679
|
# Saved Views
|
|
1643
1680
|
#
|
|
@@ -1837,7 +1874,7 @@ class SavedViewUIViewSet(
|
|
|
1837
1874
|
if derived_instance and derived_instance.config.get("pagination_count", None):
|
|
1838
1875
|
pagination_count = derived_instance.config["pagination_count"]
|
|
1839
1876
|
else:
|
|
1840
|
-
pagination_count = get_settings_or_config("PAGINATE_COUNT")
|
|
1877
|
+
pagination_count = get_settings_or_config("PAGINATE_COUNT", fallback=PAGINATE_COUNT_DEFAULT)
|
|
1841
1878
|
sv.config["pagination_count"] = int(pagination_count)
|
|
1842
1879
|
sort_order = param_dict.get("sort", [])
|
|
1843
1880
|
if not sort_order:
|
|
@@ -1931,7 +1968,7 @@ class ScheduledJobView(generic.ObjectView):
|
|
|
1931
1968
|
return {
|
|
1932
1969
|
"labels": labels,
|
|
1933
1970
|
"job_class_found": (job_class is not None),
|
|
1934
|
-
"default_time_zone":
|
|
1971
|
+
"default_time_zone": get_current_timezone(),
|
|
1935
1972
|
**super().get_extra_context(request, instance),
|
|
1936
1973
|
}
|
|
1937
1974
|
|
|
@@ -1990,6 +2027,9 @@ def get_annotated_jobresult_queryset():
|
|
|
1990
2027
|
debug_log_count=count_related(
|
|
1991
2028
|
JobLogEntry, "job_result", filter_dict={"log_level": LogLevelChoices.LOG_DEBUG}
|
|
1992
2029
|
),
|
|
2030
|
+
success_log_count=count_related(
|
|
2031
|
+
JobLogEntry, "job_result", filter_dict={"log_level": LogLevelChoices.LOG_SUCCESS}
|
|
2032
|
+
),
|
|
1993
2033
|
info_log_count=count_related(
|
|
1994
2034
|
JobLogEntry, "job_result", filter_dict={"log_level": LogLevelChoices.LOG_INFO}
|
|
1995
2035
|
),
|
|
@@ -2469,6 +2509,12 @@ class RoleUIViewSet(viewsets.NautobotUIViewSet):
|
|
|
2469
2509
|
module_table.columns.hide("role")
|
|
2470
2510
|
RequestConfig(request, paginate).configure(module_table)
|
|
2471
2511
|
context["module_table"] = module_table
|
|
2512
|
+
if ContentType.objects.get_for_model(VirtualDeviceContext) in context["content_types"]:
|
|
2513
|
+
vdcs = instance.virtual_device_contexts.restrict(request.user, "view")
|
|
2514
|
+
vdc_table = VirtualDeviceContextTable(vdcs)
|
|
2515
|
+
vdc_table.columns.hide("role")
|
|
2516
|
+
RequestConfig(request, paginate).configure(vdc_table)
|
|
2517
|
+
context["vdc_table"] = vdc_table
|
|
2472
2518
|
return context
|
|
2473
2519
|
|
|
2474
2520
|
|
|
@@ -2477,38 +2523,56 @@ class RoleUIViewSet(viewsets.NautobotUIViewSet):
|
|
|
2477
2523
|
#
|
|
2478
2524
|
|
|
2479
2525
|
|
|
2480
|
-
class
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2526
|
+
class SecretUIViewSet(
|
|
2527
|
+
ObjectDetailViewMixin,
|
|
2528
|
+
ObjectListViewMixin,
|
|
2529
|
+
ObjectEditViewMixin,
|
|
2530
|
+
ObjectDestroyViewMixin,
|
|
2531
|
+
ObjectBulkCreateViewMixin, # 3.0 TODO: remove, unused
|
|
2532
|
+
ObjectBulkDestroyViewMixin,
|
|
2533
|
+
# no ObjectBulkUpdateViewMixin here yet
|
|
2534
|
+
ObjectChangeLogViewMixin,
|
|
2535
|
+
ObjectNotesViewMixin,
|
|
2536
|
+
):
|
|
2488
2537
|
queryset = Secret.objects.all()
|
|
2538
|
+
form_class = forms.SecretForm
|
|
2539
|
+
filterset_class = filters.SecretFilterSet
|
|
2540
|
+
filterset_form_class = forms.SecretFilterForm
|
|
2541
|
+
table_class = tables.SecretTable
|
|
2542
|
+
|
|
2543
|
+
object_detail_content = object_detail.ObjectDetailContent(
|
|
2544
|
+
panels=[
|
|
2545
|
+
object_detail.ObjectFieldsPanel(
|
|
2546
|
+
weight=100, section=SectionChoices.LEFT_HALF, fields="__all__", exclude_fields=["parameters"]
|
|
2547
|
+
),
|
|
2548
|
+
object_detail.KeyValueTablePanel(
|
|
2549
|
+
weight=200, section=SectionChoices.LEFT_HALF, label="Parameters", context_data_key="parameters"
|
|
2550
|
+
),
|
|
2551
|
+
object_detail.ObjectsTablePanel(
|
|
2552
|
+
weight=100,
|
|
2553
|
+
section=SectionChoices.RIGHT_HALF,
|
|
2554
|
+
table_title="Groups containing this secret",
|
|
2555
|
+
table_class=tables.SecretsGroupTable,
|
|
2556
|
+
table_attribute="secrets_groups",
|
|
2557
|
+
footer_content_template_path=None,
|
|
2558
|
+
),
|
|
2559
|
+
],
|
|
2560
|
+
extra_buttons=[
|
|
2561
|
+
object_detail.Button(
|
|
2562
|
+
weight=100,
|
|
2563
|
+
label="Check Secret",
|
|
2564
|
+
icon="mdi-test-tube",
|
|
2565
|
+
javascript_template_path="extras/secret_check.js",
|
|
2566
|
+
attributes={"onClick": "checkSecret()"},
|
|
2567
|
+
),
|
|
2568
|
+
],
|
|
2569
|
+
)
|
|
2489
2570
|
|
|
2490
2571
|
def get_extra_context(self, request, instance):
|
|
2491
|
-
|
|
2492
|
-
if
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
request.user.set_config("extras.configcontext.format", format_, commit=True)
|
|
2496
|
-
elif request.user.is_authenticated:
|
|
2497
|
-
format_ = request.user.get_config("extras.configcontext.format", "json")
|
|
2498
|
-
else:
|
|
2499
|
-
format_ = "json"
|
|
2500
|
-
|
|
2501
|
-
provider = registry["secrets_providers"].get(instance.provider)
|
|
2502
|
-
|
|
2503
|
-
groups = instance.secrets_groups.distinct()
|
|
2504
|
-
groups_table = tables.SecretsGroupTable(groups, orderable=False)
|
|
2505
|
-
|
|
2506
|
-
return {
|
|
2507
|
-
"format": format_,
|
|
2508
|
-
"provider_name": provider.name if provider else instance.provider,
|
|
2509
|
-
"groups_table": groups_table,
|
|
2510
|
-
**super().get_extra_context(request, instance),
|
|
2511
|
-
}
|
|
2572
|
+
ctx = super().get_extra_context(request, instance)
|
|
2573
|
+
if self.action == "retrieve":
|
|
2574
|
+
ctx["parameters"] = instance.parameters
|
|
2575
|
+
return ctx
|
|
2512
2576
|
|
|
2513
2577
|
|
|
2514
2578
|
class SecretProviderParametersFormView(generic.GenericView):
|
|
@@ -2527,27 +2591,6 @@ class SecretProviderParametersFormView(generic.GenericView):
|
|
|
2527
2591
|
)
|
|
2528
2592
|
|
|
2529
2593
|
|
|
2530
|
-
class SecretEditView(generic.ObjectEditView):
|
|
2531
|
-
queryset = Secret.objects.all()
|
|
2532
|
-
model_form = forms.SecretForm
|
|
2533
|
-
template_name = "extras/secret_edit.html"
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
class SecretDeleteView(generic.ObjectDeleteView):
|
|
2537
|
-
queryset = Secret.objects.all()
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
class SecretBulkImportView(generic.BulkImportView): # 3.0 TODO: remove, unused
|
|
2541
|
-
queryset = Secret.objects.all()
|
|
2542
|
-
table = tables.SecretTable
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
class SecretBulkDeleteView(generic.BulkDeleteView):
|
|
2546
|
-
queryset = Secret.objects.all()
|
|
2547
|
-
filterset = filters.SecretFilterSet
|
|
2548
|
-
table = tables.SecretTable
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
2594
|
class SecretsGroupListView(generic.ObjectListView):
|
|
2552
2595
|
queryset = SecretsGroup.objects.all()
|
|
2553
2596
|
filterset = filters.SecretsGroupFilterSet
|