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
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
from collections.abc import Mapping
|
|
2
2
|
from datetime import datetime, timedelta
|
|
3
|
+
import json
|
|
3
4
|
import logging
|
|
4
5
|
from pathlib import Path
|
|
6
|
+
import sys
|
|
5
7
|
|
|
6
8
|
from celery import current_app
|
|
9
|
+
from celery.beat import _evaluate_entry_args, _evaluate_entry_kwargs, reraise, SchedulingError
|
|
10
|
+
from celery.result import AsyncResult
|
|
7
11
|
from django.conf import settings
|
|
8
12
|
from django_celery_beat.schedulers import DatabaseScheduler, ModelEntry
|
|
9
13
|
from kombu.utils.json import loads
|
|
10
14
|
|
|
11
|
-
from nautobot.extras.
|
|
15
|
+
from nautobot.extras.choices import JobQueueTypeChoices
|
|
16
|
+
from nautobot.extras.models import JobResult, ScheduledJob, ScheduledJobs
|
|
17
|
+
from nautobot.extras.utils import run_kubernetes_job_and_return_job_result
|
|
12
18
|
|
|
13
19
|
logger = logging.getLogger(__name__)
|
|
14
20
|
|
|
@@ -111,7 +117,46 @@ class NautobotDatabaseScheduler(DatabaseScheduler):
|
|
|
111
117
|
|
|
112
118
|
Ref: https://github.com/celery/django-celery-beat/issues/558#issuecomment-1162730008
|
|
113
119
|
"""
|
|
114
|
-
resp =
|
|
120
|
+
resp = None
|
|
121
|
+
entry = self.reserve(entry) if advance else entry
|
|
122
|
+
task = self.app.tasks.get(entry.task)
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
entry_args = _evaluate_entry_args(entry.args)
|
|
126
|
+
entry_kwargs = _evaluate_entry_kwargs(entry.kwargs)
|
|
127
|
+
if task:
|
|
128
|
+
scheduled_job = entry.model
|
|
129
|
+
job_queue = scheduled_job.job_queue
|
|
130
|
+
# Distinguish between Celery and Kubernetes job queues
|
|
131
|
+
if job_queue.queue_type == JobQueueTypeChoices.TYPE_KUBERNETES:
|
|
132
|
+
job_result = JobResult.objects.create(
|
|
133
|
+
name=scheduled_job.job_model.name,
|
|
134
|
+
job_model=scheduled_job.job_model,
|
|
135
|
+
scheduled_job=scheduled_job,
|
|
136
|
+
user=scheduled_job.user,
|
|
137
|
+
task_name=scheduled_job.job_model.class_path,
|
|
138
|
+
celery_kwargs=entry.options,
|
|
139
|
+
)
|
|
140
|
+
job_result = run_kubernetes_job_and_return_job_result(
|
|
141
|
+
job_queue, job_result, json.dumps(entry_kwargs)
|
|
142
|
+
)
|
|
143
|
+
# Return an AsyncResult object to mimic the behavior of Celery tasks after the job is finished by Kubernetes Job Pod.
|
|
144
|
+
resp = AsyncResult(job_result.id)
|
|
145
|
+
else:
|
|
146
|
+
resp = task.apply_async(entry_args, entry_kwargs, producer=producer, **entry.options)
|
|
147
|
+
else:
|
|
148
|
+
resp = self.send_task(entry.task, entry_args, entry_kwargs, producer=producer, **entry.options)
|
|
149
|
+
except Exception as exc: # pylint: disable=broad-except
|
|
150
|
+
reraise(
|
|
151
|
+
SchedulingError,
|
|
152
|
+
SchedulingError(f"Couldn't apply scheduled task {entry.name}: {exc}"),
|
|
153
|
+
sys.exc_info()[2],
|
|
154
|
+
)
|
|
155
|
+
finally:
|
|
156
|
+
self._tasks_since_sync += 1
|
|
157
|
+
if self.should_sync():
|
|
158
|
+
self._do_sync()
|
|
159
|
+
|
|
115
160
|
if entry.total_run_count != entry.model.total_run_count:
|
|
116
161
|
entry.total_run_count = entry.model.total_run_count
|
|
117
162
|
entry.model.save()
|
nautobot/core/choices.py
CHANGED
|
@@ -182,14 +182,14 @@ class ButtonActionColorChoices(ChoiceSet):
|
|
|
182
182
|
Map standard button actions to Bootstrap color classes.
|
|
183
183
|
"""
|
|
184
184
|
|
|
185
|
-
ADD = "
|
|
185
|
+
ADD = "primary"
|
|
186
186
|
CANCEL = "default"
|
|
187
187
|
CLONE = "success"
|
|
188
188
|
CONFIGURE = "default"
|
|
189
189
|
CONNECT = "success"
|
|
190
190
|
DEFAULT = "default"
|
|
191
191
|
DELETE = "danger"
|
|
192
|
-
DISCONNECT = "
|
|
192
|
+
DISCONNECT = "danger"
|
|
193
193
|
EDIT = "warning"
|
|
194
194
|
EXPORT = "success"
|
|
195
195
|
IMPORT = "primary"
|
nautobot/core/cli/__init__.py
CHANGED
|
@@ -13,6 +13,7 @@ from django.core.management import CommandError, CommandParser, execute_from_com
|
|
|
13
13
|
from django.core.management.utils import get_random_secret_key
|
|
14
14
|
from jinja2 import BaseLoader, Environment
|
|
15
15
|
|
|
16
|
+
from nautobot.core.events import load_event_brokers
|
|
16
17
|
from nautobot.core.settings_funcs import is_truthy
|
|
17
18
|
from nautobot.extras.plugins.utils import load_plugins
|
|
18
19
|
|
|
@@ -44,6 +45,7 @@ def _preprocess_settings(settings, config_path):
|
|
|
44
45
|
- Set up 'job_logs' database mirror
|
|
45
46
|
- Handle our custom `STORAGE_BACKEND` setting.
|
|
46
47
|
- Load plugins based on settings.PLUGINS (potentially affecting INSTALLED_APPS, MIDDLEWARE, and CONSTANCE_CONFIG)
|
|
48
|
+
- Load event brokers based on settings.EVENT_BROKERS
|
|
47
49
|
"""
|
|
48
50
|
settings.SETTINGS_PATH = config_path
|
|
49
51
|
|
|
@@ -124,6 +126,12 @@ def _preprocess_settings(settings, config_path):
|
|
|
124
126
|
# passed in.
|
|
125
127
|
load_plugins(settings)
|
|
126
128
|
|
|
129
|
+
#
|
|
130
|
+
# Event Broker
|
|
131
|
+
#
|
|
132
|
+
|
|
133
|
+
load_event_brokers(settings.EVENT_BROKERS)
|
|
134
|
+
|
|
127
135
|
|
|
128
136
|
def load_settings(config_path):
|
|
129
137
|
"""Load nautobot_config.py or its equivalent into memory as a `nautobot_config` pseudo-module."""
|
nautobot/core/constants.py
CHANGED
|
@@ -110,6 +110,10 @@ CONFIG_SETTING_SEPARATOR = ","
|
|
|
110
110
|
|
|
111
111
|
CHARFIELD_MAX_LENGTH = 255
|
|
112
112
|
|
|
113
|
+
# Default values for pagination settings.
|
|
114
|
+
MAX_PAGE_SIZE_DEFAULT = 1000
|
|
115
|
+
PAGINATE_COUNT_DEFAULT = 50
|
|
116
|
+
|
|
113
117
|
# Models excluded from the global search list
|
|
114
118
|
GLOBAL_SEARCH_EXCLUDE_LIST = [
|
|
115
119
|
"anotherexamplemodel",
|
|
@@ -146,12 +150,15 @@ GLOBAL_SEARCH_EXCLUDE_LIST = [
|
|
|
146
150
|
"interfaceredundancygroup",
|
|
147
151
|
"interfaceredundancygroupassociation",
|
|
148
152
|
"interfacetemplate",
|
|
153
|
+
"interfacevdcassignment",
|
|
149
154
|
"inventoryitem",
|
|
150
155
|
"ipaddresstointerface",
|
|
151
156
|
"job",
|
|
152
157
|
"jobbutton",
|
|
153
158
|
"jobhook",
|
|
154
159
|
"joblogentry",
|
|
160
|
+
"jobqueue",
|
|
161
|
+
"jobqueueassignment",
|
|
155
162
|
"jobresult",
|
|
156
163
|
"locationtype",
|
|
157
164
|
"manufacturer",
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Module providing for the publication of event notifications via mechanisms such as Redis, Kafka, syslog, etc."""
|
|
2
|
+
|
|
3
|
+
import fnmatch
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
from django.utils.module_loading import import_string
|
|
8
|
+
|
|
9
|
+
from nautobot.core.celery import NautobotKombuJSONEncoder
|
|
10
|
+
from nautobot.core.events.exceptions import EventBrokerImproperlyConfigured, EventBrokerNotFound
|
|
11
|
+
|
|
12
|
+
from .base import EventBroker
|
|
13
|
+
from .redis_broker import RedisEventBroker
|
|
14
|
+
from .syslog_broker import SyslogEventBroker
|
|
15
|
+
|
|
16
|
+
_EVENT_BROKERS = []
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def load_event_brokers(event_broker_configs):
|
|
23
|
+
"""Process plugins and log errors if they can't be loaded."""
|
|
24
|
+
for broker_name, broker in event_broker_configs.items():
|
|
25
|
+
options = broker.get("OPTIONS", {})
|
|
26
|
+
topics = broker.get("TOPICS", {})
|
|
27
|
+
if not isinstance(topics, dict):
|
|
28
|
+
raise EventBrokerImproperlyConfigured(
|
|
29
|
+
f"{broker_name} Malformed Event Broker Settings: Expected `TOPICS` to be a 'dict', instead a '{type(topics).__name__}' was provided"
|
|
30
|
+
)
|
|
31
|
+
include_topics = topics.get("INCLUDE")
|
|
32
|
+
if include_topics and not isinstance(include_topics, (list, tuple)):
|
|
33
|
+
raise EventBrokerImproperlyConfigured(
|
|
34
|
+
f"{broker_name} Malformed Event Broker Settings: Expected `INCLUDE` to be a 'list' or 'tuple', instead a '{type(include_topics).__name__}' was provided"
|
|
35
|
+
)
|
|
36
|
+
exclude_topics = topics.get("EXCLUDE", [])
|
|
37
|
+
if exclude_topics and not isinstance(exclude_topics, (list, tuple)):
|
|
38
|
+
raise EventBrokerImproperlyConfigured(
|
|
39
|
+
f"{broker_name} Malformed Event Broker Settings: Expected `EXCLUDE` to be a 'list' or 'tuple', instead a '{type(exclude_topics).__name__}' was provided"
|
|
40
|
+
)
|
|
41
|
+
options.update({"include_topics": include_topics, "exclude_topics": exclude_topics})
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
event_broker_class = import_string(broker["CLASS"])
|
|
45
|
+
if not issubclass(event_broker_class, EventBroker):
|
|
46
|
+
raise EventBrokerImproperlyConfigured(
|
|
47
|
+
f"{broker_name} Malformed Event Broker Settings: Broker provided is not an EventBroker"
|
|
48
|
+
)
|
|
49
|
+
event_broker = event_broker_class(**options)
|
|
50
|
+
register_event_broker(event_broker)
|
|
51
|
+
except ImportError as err:
|
|
52
|
+
raise EventBrokerNotFound(f"Unable to import Event Broker {broker_name}.") from err
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def register_event_broker(event_broker):
|
|
56
|
+
"""
|
|
57
|
+
Register an `EventBroker` instance for use by Nautobot.
|
|
58
|
+
|
|
59
|
+
The `publish_event()` API will publish events to each registered broker.
|
|
60
|
+
The expectation/intent here, at least initially, is that a given deployment will instantiate zero or more
|
|
61
|
+
EventBrokers, then call `register_event_broker()` for each one, as part of Nautobot initial startup.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
event_broker (EventBroker): The initialized/configured EventBroker instance to register.
|
|
65
|
+
"""
|
|
66
|
+
if event_broker not in _EVENT_BROKERS:
|
|
67
|
+
_EVENT_BROKERS.append(event_broker)
|
|
68
|
+
logger.debug("Registered %s as an event broker", event_broker)
|
|
69
|
+
else:
|
|
70
|
+
logger.warning("Tried to register event broker %s but it was already registered", event_broker)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def deregister_event_broker(event_broker):
|
|
74
|
+
"""
|
|
75
|
+
Deregister a previously registered `EventBroker` instance so that it no longer receives published events.
|
|
76
|
+
"""
|
|
77
|
+
try:
|
|
78
|
+
_EVENT_BROKERS.remove(event_broker)
|
|
79
|
+
logger.debug("Deregistered event broker %s", event_broker)
|
|
80
|
+
except ValueError:
|
|
81
|
+
logger.warning("Tried to deregister event broker %s but it wasn't previously registered", event_broker)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def is_topic_match(topic, patterns):
|
|
85
|
+
return any(fnmatch.fnmatch(topic, pattern) for pattern in patterns)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def publish_event(*, topic, payload):
|
|
89
|
+
"""Publish the given event payload to the given topic via all registered `EventBroker` instances.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
topic (str): Topic identifier.
|
|
93
|
+
Convention is to use snake_case and use periods to delineate related groups of topics,
|
|
94
|
+
similar to Python logger naming. For example, you might use `nautobot.create.dcim.device`,
|
|
95
|
+
`nautobot.update.dcim.device`, `nautobot.delete.dcim.device`, `nautobot.create.dcim.interface`,
|
|
96
|
+
`nautobot.create.ipam.ipaddress`, etc.
|
|
97
|
+
payload (dict): JSON-serializable structured data to publish.
|
|
98
|
+
While not all EventBrokers may actually use JSON as their data format, it makes for a reasonable
|
|
99
|
+
lowest common denominator for serializability.
|
|
100
|
+
"""
|
|
101
|
+
for event_broker in _EVENT_BROKERS:
|
|
102
|
+
exclude_topics = event_broker.exclude_topics
|
|
103
|
+
include_topics = event_broker.include_topics
|
|
104
|
+
if is_topic_match(topic, include_topics) and not is_topic_match(topic, exclude_topics):
|
|
105
|
+
serialized_payload = json.dumps(payload, cls=NautobotKombuJSONEncoder)
|
|
106
|
+
event_broker.publish(topic=topic, payload=serialized_payload)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
__all__ = (
|
|
110
|
+
"EventBroker",
|
|
111
|
+
"RedisEventBroker",
|
|
112
|
+
"SyslogEventBroker",
|
|
113
|
+
"deregister_event_broker",
|
|
114
|
+
"publish_event",
|
|
115
|
+
"register_event_broker",
|
|
116
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Base classes for Nautobot event notification framework."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class EventBroker(ABC):
|
|
7
|
+
"""Abstract base class for concrete implementations of event brokers such as syslog, Redis, Kafka, etc."""
|
|
8
|
+
|
|
9
|
+
def __init__(self, *args, include_topics=None, exclude_topics=None, **kwargs) -> None:
|
|
10
|
+
self.include_topics = include_topics or ["*"]
|
|
11
|
+
self.exclude_topics = exclude_topics or []
|
|
12
|
+
super().__init__(*args, **kwargs)
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def publish(self, *, topic, payload):
|
|
16
|
+
"""
|
|
17
|
+
Possibly publish the given data `payload` to the given event `topic`.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
topic (str): Topic identifier.
|
|
21
|
+
Convention is to use snake_case and use periods to delineate related groups of topics,
|
|
22
|
+
similar to Python logger naming. For example, you might receive topics such as `create.dcim.device`,
|
|
23
|
+
`update.dcim.device`, `delete.dcim.device`, `create.dcim.interface`, `create.ipam.ipaddress`, etc.
|
|
24
|
+
payload (dict): JSON-serializable structured data to publish.
|
|
25
|
+
While not all EventBrokers may actually use JSON as their data format, it makes for a reasonable
|
|
26
|
+
lowest common denominator for serializability.
|
|
27
|
+
"""
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class EventBrokerError(Exception):
|
|
2
|
+
"""Base exception for all event-broker-related errors."""
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class EventBrokerNotFound(EventBrokerError):
|
|
6
|
+
"""Raised when a specified event broker module cannot be found."""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EventBrokerImproperlyConfigured(EventBrokerError):
|
|
10
|
+
"""Raised when a event is not properly configured."""
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Simple EventBroker for publishing events to Redis.
|
|
2
|
+
|
|
3
|
+
To verify that an instance of this broker is working, you can do the following in `nautobot-server nbshell`:
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
import redis
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
connection = redis.StrictRedis(host="redis", port=6379, db=2, password="...", charset="utf-8", decode_responses=True)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def listen():
|
|
15
|
+
sub = connection.pubsub()
|
|
16
|
+
sub.psubscribe("nautobot.*")
|
|
17
|
+
for message in sub.listen():
|
|
18
|
+
if message["type"] == "pmessage":
|
|
19
|
+
print(f"Got a pmessage on channel {message['channel']}")
|
|
20
|
+
print(json.dumps(json.loads(message["data"]), indent=2))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
listen()
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Then perform any action that triggers an event, such as creating or updating a record through the Nautobot UI.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
import redis
|
|
30
|
+
|
|
31
|
+
from .base import EventBroker
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class RedisEventBroker(EventBroker):
|
|
35
|
+
"""EventBroker for publishing events to Redis."""
|
|
36
|
+
|
|
37
|
+
def __init__(self, *args, url, **kwargs):
|
|
38
|
+
"""Initialize and configure a RedisEventBroker.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
url (str): The Redis URL to connect to.
|
|
42
|
+
"""
|
|
43
|
+
self.url = url
|
|
44
|
+
self.connection = redis.StrictRedis.from_url(self.url)
|
|
45
|
+
super().__init__(*args, **kwargs)
|
|
46
|
+
|
|
47
|
+
def publish(self, *, topic, payload):
|
|
48
|
+
self.connection.publish(topic, payload)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Simple EventBroker that just emits syslogs."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
from .base import EventBroker
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SyslogEventBroker(EventBroker):
|
|
10
|
+
def __init__(self, *args, level=logging.INFO, **kwargs):
|
|
11
|
+
"""Initialize a SyslogEventBroker that emits logs at the given level."""
|
|
12
|
+
super().__init__(*args, **kwargs)
|
|
13
|
+
self.level = level
|
|
14
|
+
|
|
15
|
+
def publish(self, *, topic, payload):
|
|
16
|
+
logger = logging.getLogger(f"nautobot.events.{topic}")
|
|
17
|
+
# Add an indent of 4 to payload
|
|
18
|
+
payload = json.dumps(json.loads(payload), indent=4)
|
|
19
|
+
logger.log(self.level, "%s", payload)
|
nautobot/core/exceptions.py
CHANGED
nautobot/core/forms/__init__.py
CHANGED
|
@@ -76,24 +76,21 @@ from nautobot.core.forms.widgets import (
|
|
|
76
76
|
)
|
|
77
77
|
|
|
78
78
|
__all__ = (
|
|
79
|
-
"add_blank_choice",
|
|
80
|
-
"add_field_to_filter_form_class",
|
|
81
|
-
"AddressFieldMixin",
|
|
82
79
|
"ALPHANUMERIC_EXPANSION_PATTERN",
|
|
80
|
+
"BOOLEAN_CHOICES",
|
|
81
|
+
"BOOLEAN_WITH_BLANK_CHOICES",
|
|
82
|
+
"IP4_EXPANSION_PATTERN",
|
|
83
|
+
"IP6_EXPANSION_PATTERN",
|
|
84
|
+
"NUMERIC_EXPANSION_PATTERN",
|
|
83
85
|
"APISelect",
|
|
84
86
|
"APISelectMultiple",
|
|
87
|
+
"AddressFieldMixin",
|
|
85
88
|
"AutoPositionField",
|
|
86
89
|
"AutoPositionPatternField",
|
|
87
|
-
"BOOLEAN_CHOICES",
|
|
88
|
-
"BOOLEAN_WITH_BLANK_CHOICES",
|
|
89
90
|
"BootstrapMixin",
|
|
90
91
|
"BulkEditForm",
|
|
91
92
|
"BulkEditNullBooleanSelect",
|
|
92
93
|
"BulkRenameForm",
|
|
93
|
-
"ColorSelect",
|
|
94
|
-
"CommentField",
|
|
95
|
-
"ConfirmationForm",
|
|
96
|
-
"ContentTypeSelect",
|
|
97
94
|
"CSVChoiceField",
|
|
98
95
|
"CSVContentTypeField",
|
|
99
96
|
"CSVDataField",
|
|
@@ -102,34 +99,29 @@ __all__ = (
|
|
|
102
99
|
"CSVModelForm",
|
|
103
100
|
"CSVMultipleChoiceField",
|
|
104
101
|
"CSVMultipleContentTypeField",
|
|
102
|
+
"ColorSelect",
|
|
103
|
+
"CommentField",
|
|
104
|
+
"ConfirmationForm",
|
|
105
|
+
"ContentTypeSelect",
|
|
105
106
|
"DatePicker",
|
|
106
107
|
"DateTimePicker",
|
|
107
108
|
"DynamicFilterForm",
|
|
108
109
|
"DynamicModelChoiceField",
|
|
109
110
|
"DynamicModelMultipleChoiceField",
|
|
110
|
-
"expand_alphanumeric_pattern",
|
|
111
|
-
"expand_ipaddress_pattern",
|
|
112
111
|
"ExpandableIPAddressField",
|
|
113
112
|
"ExpandableNameField",
|
|
114
|
-
"form_from_model",
|
|
115
113
|
"ImportForm",
|
|
116
|
-
"IP4_EXPANSION_PATTERN",
|
|
117
|
-
"IP6_EXPANSION_PATTERN",
|
|
118
114
|
"JSONArrayFormField",
|
|
119
115
|
"JSONField",
|
|
120
116
|
"LaxURLField",
|
|
121
117
|
"MACAddressField",
|
|
122
118
|
"MultiMatchModelMultipleChoiceField",
|
|
123
|
-
"MultipleContentTypeField",
|
|
124
119
|
"MultiValueCharField",
|
|
125
120
|
"MultiValueCharInput",
|
|
121
|
+
"MultipleContentTypeField",
|
|
126
122
|
"NullableDateField",
|
|
127
|
-
"NUMERIC_EXPANSION_PATTERN",
|
|
128
123
|
"NumericArrayField",
|
|
129
|
-
"parse_alphanumeric_range",
|
|
130
|
-
"parse_numeric_range",
|
|
131
124
|
"PrefixFieldMixin",
|
|
132
|
-
"restrict_form_fields",
|
|
133
125
|
"ReturnURLForm",
|
|
134
126
|
"SearchForm",
|
|
135
127
|
"SelectWithDisabled",
|
|
@@ -142,4 +134,12 @@ __all__ = (
|
|
|
142
134
|
"TableConfigForm",
|
|
143
135
|
"TagFilterField",
|
|
144
136
|
"TimePicker",
|
|
137
|
+
"add_blank_choice",
|
|
138
|
+
"add_field_to_filter_form_class",
|
|
139
|
+
"expand_alphanumeric_pattern",
|
|
140
|
+
"expand_ipaddress_pattern",
|
|
141
|
+
"form_from_model",
|
|
142
|
+
"parse_alphanumeric_range",
|
|
143
|
+
"parse_numeric_range",
|
|
144
|
+
"restrict_form_fields",
|
|
145
145
|
)
|
nautobot/core/forms/fields.py
CHANGED
|
@@ -8,7 +8,7 @@ from django.contrib.contenttypes.models import ContentType
|
|
|
8
8
|
from django.contrib.postgres.forms import SimpleArrayField
|
|
9
9
|
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist, ValidationError
|
|
10
10
|
from django.db.models import Q
|
|
11
|
-
from django.forms.fields import BoundField, InvalidJSONInput, JSONField as _JSONField
|
|
11
|
+
from django.forms.fields import BoundField, CallableChoiceIterator, InvalidJSONInput, JSONField as _JSONField
|
|
12
12
|
from django.templatetags.static import static
|
|
13
13
|
from django.urls import reverse
|
|
14
14
|
from django.utils.html import format_html
|
|
@@ -22,7 +22,6 @@ from nautobot.core.models import validators
|
|
|
22
22
|
from nautobot.core.utils import data as data_utils, lookup
|
|
23
23
|
|
|
24
24
|
__all__ = (
|
|
25
|
-
"CommentField",
|
|
26
25
|
"CSVChoiceField",
|
|
27
26
|
"CSVContentTypeField",
|
|
28
27
|
"CSVDataField",
|
|
@@ -30,16 +29,17 @@ __all__ = (
|
|
|
30
29
|
"CSVModelChoiceField",
|
|
31
30
|
"CSVMultipleChoiceField",
|
|
32
31
|
"CSVMultipleContentTypeField",
|
|
32
|
+
"CommentField",
|
|
33
33
|
"DynamicModelChoiceField",
|
|
34
34
|
"DynamicModelMultipleChoiceField",
|
|
35
35
|
"ExpandableIPAddressField",
|
|
36
36
|
"ExpandableNameField",
|
|
37
|
-
"JSONField",
|
|
38
37
|
"JSONArrayFormField",
|
|
38
|
+
"JSONField",
|
|
39
39
|
"LaxURLField",
|
|
40
40
|
"MACAddressField",
|
|
41
|
-
"MultipleContentTypeField",
|
|
42
41
|
"MultiMatchModelMultipleChoiceField",
|
|
42
|
+
"MultipleContentTypeField",
|
|
43
43
|
"NumericArrayField",
|
|
44
44
|
"SlugField",
|
|
45
45
|
"TagFilterField",
|
|
@@ -504,6 +504,8 @@ class DynamicModelChoiceMixin:
|
|
|
504
504
|
):
|
|
505
505
|
self.display_field = display_field
|
|
506
506
|
self.query_params = query_params or {}
|
|
507
|
+
# Default to "exclude_m2m=true" for improved performance, if not otherwise specified
|
|
508
|
+
self.query_params.setdefault("exclude_m2m", "true")
|
|
507
509
|
self.initial_params = initial_params or {}
|
|
508
510
|
self.null_option = null_option
|
|
509
511
|
self.disabled_indicator = disabled_indicator
|
|
@@ -536,9 +538,10 @@ class DynamicModelChoiceMixin:
|
|
|
536
538
|
# Toggle depth
|
|
537
539
|
attrs["data-depth"] = self.depth
|
|
538
540
|
|
|
539
|
-
# Attach any static query parameters
|
|
540
|
-
|
|
541
|
-
|
|
541
|
+
# Attach any static query parameters if supported
|
|
542
|
+
if isinstance(widget, widgets.APISelect) or hasattr(widget, "add_query_param"):
|
|
543
|
+
for key, value in self.query_params.items():
|
|
544
|
+
widget.add_query_param(key, value)
|
|
542
545
|
|
|
543
546
|
return attrs
|
|
544
547
|
|
|
@@ -660,11 +663,29 @@ class JSONArrayFormField(django_forms.JSONField):
|
|
|
660
663
|
and each Array element is validated by `base_field` validators.
|
|
661
664
|
"""
|
|
662
665
|
|
|
663
|
-
def __init__(self, base_field, *, delimiter=",", **kwargs):
|
|
666
|
+
def __init__(self, base_field, *, choices=None, delimiter=",", **kwargs):
|
|
667
|
+
self.has_choices = False
|
|
668
|
+
if choices:
|
|
669
|
+
self.choices = choices
|
|
670
|
+
self.widget = widgets.StaticSelect2Multiple(choices=choices)
|
|
671
|
+
self.has_choices = True
|
|
664
672
|
self.base_field = base_field
|
|
665
673
|
self.delimiter = delimiter
|
|
666
674
|
super().__init__(**kwargs)
|
|
667
675
|
|
|
676
|
+
# TODO: change this when we upgrade to Django 5, it uses a getter/setter for choices
|
|
677
|
+
def _get_choices(self):
|
|
678
|
+
return getattr(self, "_choices", None)
|
|
679
|
+
|
|
680
|
+
def _set_choices(self, value):
|
|
681
|
+
if callable(value):
|
|
682
|
+
value = CallableChoiceIterator(value)
|
|
683
|
+
else:
|
|
684
|
+
value = list(value)
|
|
685
|
+
self._choices = self.widget.choices = value
|
|
686
|
+
|
|
687
|
+
choices = property(_get_choices, _set_choices)
|
|
688
|
+
|
|
668
689
|
def clean(self, value):
|
|
669
690
|
"""
|
|
670
691
|
Validate `value` and return its "cleaned" value as an appropriate
|
|
@@ -677,10 +698,21 @@ class JSONArrayFormField(django_forms.JSONField):
|
|
|
677
698
|
"""
|
|
678
699
|
Return a string of this value.
|
|
679
700
|
"""
|
|
680
|
-
if
|
|
701
|
+
if self.has_choices:
|
|
702
|
+
if isinstance(value, list):
|
|
703
|
+
return value
|
|
704
|
+
return [value]
|
|
705
|
+
elif isinstance(value, list):
|
|
681
706
|
return self.delimiter.join(str(self.base_field.prepare_value(v)) for v in value)
|
|
682
707
|
return value
|
|
683
708
|
|
|
709
|
+
def bound_data(self, data, initial):
|
|
710
|
+
if data is None:
|
|
711
|
+
return None
|
|
712
|
+
if isinstance(data, list):
|
|
713
|
+
data = json.dumps(data)
|
|
714
|
+
return super().bound_data(data, initial)
|
|
715
|
+
|
|
684
716
|
def to_python(self, value):
|
|
685
717
|
"""
|
|
686
718
|
Convert `value` into JSON, raising django.core.exceptions.ValidationError
|
|
@@ -718,9 +750,25 @@ class JSONArrayFormField(django_forms.JSONField):
|
|
|
718
750
|
self.base_field.validate(item)
|
|
719
751
|
except ValidationError as error:
|
|
720
752
|
errors.append(error)
|
|
753
|
+
if self.has_choices and not self.valid_value(item):
|
|
754
|
+
errors.append(ValidationError(f"{item} is not a valid choice"))
|
|
721
755
|
if errors:
|
|
722
756
|
raise ValidationError(errors)
|
|
723
757
|
|
|
758
|
+
def valid_value(self, value):
|
|
759
|
+
"""Check to see if the provided value is a valid choice."""
|
|
760
|
+
text_value = str(value)
|
|
761
|
+
for k, v in self.choices:
|
|
762
|
+
if isinstance(v, (list, tuple)):
|
|
763
|
+
# This is an optgroup, so look inside the group for options
|
|
764
|
+
for k2, _ in v:
|
|
765
|
+
if value == k2 or text_value == str(k2):
|
|
766
|
+
return True
|
|
767
|
+
else:
|
|
768
|
+
if value == k or text_value == str(k):
|
|
769
|
+
return True
|
|
770
|
+
return False
|
|
771
|
+
|
|
724
772
|
def run_validators(self, value):
|
|
725
773
|
"""
|
|
726
774
|
Runs all validators against `value` and raise ValidationError if necessary.
|
nautobot/core/forms/forms.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import contextlib
|
|
1
2
|
import json
|
|
2
3
|
import logging
|
|
3
4
|
import re
|
|
4
5
|
|
|
5
6
|
from django import forms
|
|
7
|
+
from django.core.exceptions import FieldDoesNotExist
|
|
8
|
+
from django.db.models.fields.related import ManyToManyField
|
|
6
9
|
from django.forms import formset_factory
|
|
7
10
|
from django.urls import reverse
|
|
8
11
|
import yaml
|
|
@@ -15,8 +18,8 @@ __all__ = (
|
|
|
15
18
|
"BootstrapMixin",
|
|
16
19
|
"BulkEditForm",
|
|
17
20
|
"BulkRenameForm",
|
|
18
|
-
"ConfirmationForm",
|
|
19
21
|
"CSVModelForm",
|
|
22
|
+
"ConfirmationForm",
|
|
20
23
|
"DynamicFilterForm",
|
|
21
24
|
"ImportForm",
|
|
22
25
|
"PrefixFieldMixin",
|
|
@@ -124,7 +127,35 @@ class BulkEditForm(forms.Form):
|
|
|
124
127
|
|
|
125
128
|
if edit_all:
|
|
126
129
|
self.fields["pk"].required = False
|
|
127
|
-
self.fields["_all"] = forms.BooleanField(widget=forms.HiddenInput(), required=
|
|
130
|
+
self.fields["_all"] = forms.BooleanField(widget=forms.HiddenInput(), required=False, initial=True)
|
|
131
|
+
|
|
132
|
+
def _save_m2m_fields(self, obj):
|
|
133
|
+
"""Save M2M fields"""
|
|
134
|
+
from nautobot.core.models.fields import TagsField # Avoid circular dependency
|
|
135
|
+
|
|
136
|
+
m2m_field_names = []
|
|
137
|
+
# Handle M2M Save
|
|
138
|
+
for key in self.cleaned_data.keys():
|
|
139
|
+
if key.startswith(("add_", "remove_")):
|
|
140
|
+
field_name = key.lstrip("add_")
|
|
141
|
+
if field_name in m2m_field_names:
|
|
142
|
+
continue
|
|
143
|
+
with contextlib.suppress(FieldDoesNotExist):
|
|
144
|
+
field = obj._meta.get_field(field_name)
|
|
145
|
+
is_m2m_field = isinstance(field, (ManyToManyField, TagsField))
|
|
146
|
+
if is_m2m_field:
|
|
147
|
+
m2m_field_names.append(field_name)
|
|
148
|
+
|
|
149
|
+
for field_name in m2m_field_names:
|
|
150
|
+
m2m_field = getattr(obj, field_name)
|
|
151
|
+
if self.cleaned_data.get(f"add_{field_name}", None):
|
|
152
|
+
m2m_field.add(*self.cleaned_data[f"add_{field_name}"])
|
|
153
|
+
if self.cleaned_data.get(f"remove_{field_name}", None):
|
|
154
|
+
m2m_field.remove(*self.cleaned_data[f"remove_{field_name}"])
|
|
155
|
+
|
|
156
|
+
def post_save(self, obj):
|
|
157
|
+
"""Post save action"""
|
|
158
|
+
self._save_m2m_fields(obj)
|
|
128
159
|
|
|
129
160
|
|
|
130
161
|
class BulkRenameForm(forms.Form):
|
nautobot/core/forms/utils.py
CHANGED
|
@@ -43,7 +43,8 @@ def parse_numeric_range(input_string, base=10):
|
|
|
43
43
|
begin, end = dash_range, dash_range
|
|
44
44
|
begin, end = int(begin.strip(), base=base), int(end.strip(), base=base) + 1
|
|
45
45
|
values.extend(range(begin, end))
|
|
46
|
-
|
|
46
|
+
# Remove duplicates and sort
|
|
47
|
+
return sorted(set(values))
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
def parse_alphanumeric_range(string):
|