nautobot 2.2.9__py3-none-any.whl → 2.3.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/apps/forms.py +4 -0
- nautobot/apps/models.py +10 -1
- nautobot/circuits/__init__.py +0 -1
- nautobot/circuits/apps.py +1 -0
- nautobot/circuits/factory.py +15 -3
- nautobot/circuits/filters.py +13 -0
- nautobot/circuits/forms.py +13 -0
- nautobot/circuits/migrations/0021_alter_circuit_status_alter_circuittermination__path.py +32 -0
- nautobot/circuits/migrations/0022_circuittermination_cloud_network.py +25 -0
- nautobot/circuits/models.py +16 -3
- nautobot/circuits/tables.py +16 -2
- nautobot/circuits/templates/circuits/circuittermination_create.html +10 -2
- nautobot/circuits/templates/circuits/circuittermination_retrieve.html +6 -0
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -1
- nautobot/circuits/tests/test_api.py +7 -5
- nautobot/circuits/tests/test_filters.py +12 -5
- nautobot/circuits/tests/test_models.py +33 -2
- nautobot/circuits/views.py +2 -3
- nautobot/cloud/__init__.py +0 -0
- nautobot/cloud/api/__init__.py +0 -0
- nautobot/cloud/api/serializers.py +54 -0
- nautobot/cloud/api/urls.py +16 -0
- nautobot/cloud/api/views.py +48 -0
- nautobot/cloud/apps.py +13 -0
- nautobot/cloud/factory.py +111 -0
- nautobot/cloud/filters.py +184 -0
- nautobot/cloud/forms.py +333 -0
- nautobot/cloud/homepage.py +43 -0
- nautobot/cloud/migrations/0001_initial.py +304 -0
- nautobot/cloud/migrations/__init__.py +0 -0
- nautobot/cloud/models.py +247 -0
- nautobot/cloud/navigation.py +85 -0
- nautobot/cloud/tables.py +173 -0
- nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +43 -0
- nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +128 -0
- nautobot/cloud/templates/cloud/cloudnetwork_update.html +33 -0
- nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +100 -0
- nautobot/cloud/templates/cloud/cloudservice_retrieve.html +65 -0
- nautobot/cloud/templates/cloud/cloudservice_update.html +25 -0
- nautobot/cloud/tests/__init__.py +0 -0
- nautobot/cloud/tests/test_api.py +248 -0
- nautobot/cloud/tests/test_filters.py +113 -0
- nautobot/cloud/tests/test_models.py +43 -0
- nautobot/cloud/tests/test_views.py +153 -0
- nautobot/cloud/urls.py +14 -0
- nautobot/cloud/views.py +181 -0
- nautobot/core/__init__.py +0 -3
- nautobot/core/api/metadata.py +1 -0
- nautobot/core/api/parsers.py +7 -1
- nautobot/core/api/urls.py +1 -0
- nautobot/core/api/utils.py +1 -0
- nautobot/core/api/views.py +4 -0
- nautobot/core/apps/__init__.py +6 -3
- nautobot/core/constants.py +8 -0
- nautobot/core/factory.py +32 -1
- nautobot/core/filters.py +96 -28
- nautobot/core/forms/fields.py +10 -4
- nautobot/core/forms/forms.py +1 -1
- nautobot/core/forms/widgets.py +18 -1
- nautobot/core/graphql/generators.py +2 -2
- nautobot/core/graphql/schema.py +34 -4
- nautobot/core/jobs/__init__.py +17 -6
- nautobot/core/jobs/cleanup.py +100 -0
- nautobot/core/jobs/groups.py +38 -0
- nautobot/core/management/commands/generate_test_data.py +116 -3
- nautobot/core/models/__init__.py +34 -9
- nautobot/core/models/generics.py +19 -3
- nautobot/core/models/name_color_content_types.py +7 -28
- nautobot/core/models/querysets.py +4 -3
- nautobot/core/models/tree_queries.py +1 -1
- nautobot/core/models/utils.py +21 -5
- nautobot/core/settings.py +4 -30
- nautobot/core/settings.yaml +34 -27
- nautobot/core/settings_funcs.py +103 -0
- nautobot/core/tables.py +127 -56
- nautobot/core/templates/admin/search_form.html +1 -1
- nautobot/core/templates/buttons/add.html +11 -3
- nautobot/core/templates/buttons/consolidated_bulk_action_buttons.html +13 -0
- nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +13 -0
- nautobot/core/templates/buttons/export.html +101 -53
- nautobot/core/templates/buttons/job_import.html +11 -3
- nautobot/core/templates/generic/object_bulk_destroy.html +3 -1
- nautobot/core/templates/generic/object_bulk_update.html +3 -1
- nautobot/core/templates/generic/object_changelog.html +0 -9
- nautobot/core/templates/generic/object_list.html +156 -17
- nautobot/core/templates/generic/object_retrieve.html +80 -16
- nautobot/core/templates/inc/extras_features_edit_form_fields.html +8 -0
- nautobot/core/templates/inc/javascript.html +2 -0
- nautobot/core/templates/inc/media.html +2 -2
- nautobot/core/templates/inc/nav_menu.html +1 -0
- nautobot/core/templates/inc/paginator.html +7 -7
- nautobot/core/templates/inc/search_panel.html +2 -2
- nautobot/core/templates/inc/table.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +13 -23
- nautobot/core/templates/utilities/templatetags/dynamic_group_assignment_modal.html +37 -0
- nautobot/core/templates/utilities/templatetags/filter_form_modal.html +2 -2
- nautobot/core/templates/utilities/templatetags/saved_view_modal.html +38 -0
- nautobot/core/templates/utilities/theme_preview.html +25 -8
- nautobot/core/templates/utilities/worker_status.html +152 -0
- nautobot/core/templatetags/buttons.py +335 -38
- nautobot/core/templatetags/form_helpers.py +1 -1
- nautobot/core/templatetags/helpers.py +181 -11
- nautobot/core/testing/api.py +5 -4
- nautobot/core/testing/filters.py +51 -13
- nautobot/core/testing/mixins.py +46 -0
- nautobot/core/testing/models.py +22 -0
- nautobot/core/testing/schema.py +4 -8
- nautobot/core/testing/views.py +31 -14
- nautobot/core/tests/integration/test_general_functionality.py +1 -1
- nautobot/core/tests/integration/test_import_objects_ui.py +1 -0
- nautobot/core/tests/integration/test_swagger.py +1 -1
- nautobot/core/tests/nautobot_config.py +0 -1
- nautobot/core/tests/runner.py +2 -2
- nautobot/core/tests/test_api.py +1 -0
- nautobot/core/tests/test_authentication.py +7 -2
- nautobot/core/tests/test_filters.py +11 -9
- nautobot/core/tests/test_forms.py +9 -0
- nautobot/core/tests/test_graphql.py +27 -16
- nautobot/core/tests/test_jobs.py +123 -74
- nautobot/core/tests/test_tables.py +3 -1
- nautobot/core/tests/test_templatetags_helpers.py +12 -5
- nautobot/core/tests/test_utils.py +31 -20
- nautobot/core/tests/test_views.py +6 -6
- nautobot/core/urls.py +8 -3
- nautobot/core/utils/deprecation.py +29 -0
- nautobot/core/utils/filtering.py +12 -9
- nautobot/core/utils/lookup.py +37 -2
- nautobot/core/utils/requests.py +4 -1
- nautobot/core/views/__init__.py +137 -24
- nautobot/core/views/generic.py +118 -66
- nautobot/core/views/mixins.py +104 -35
- nautobot/core/views/paginator.py +9 -3
- nautobot/core/views/renderers.py +121 -56
- nautobot/core/views/utils.py +79 -1
- nautobot/dcim/__init__.py +0 -1
- nautobot/dcim/api/serializers.py +180 -44
- nautobot/dcim/api/urls.py +7 -3
- nautobot/dcim/api/views.py +53 -7
- nautobot/dcim/apps.py +3 -0
- nautobot/dcim/choices.py +25 -0
- nautobot/dcim/constants.py +7 -0
- nautobot/dcim/factory.py +249 -18
- nautobot/dcim/filters/__init__.py +369 -193
- nautobot/dcim/filters/mixins.py +274 -1
- nautobot/dcim/forms.py +817 -109
- nautobot/dcim/graphql/types.py +2 -2
- nautobot/dcim/homepage.py +1 -1
- nautobot/dcim/migrations/0059_add_role_field_to_interface_models.py +27 -0
- nautobot/dcim/migrations/0060_alter_cable_status_alter_consoleport__path_and_more.py +303 -0
- nautobot/dcim/migrations/0061_module_models.py +861 -0
- nautobot/dcim/migrations/0062_module_data_migration.py +25 -0
- nautobot/dcim/models/__init__.py +8 -0
- nautobot/dcim/models/cables.py +15 -0
- nautobot/dcim/models/device_component_templates.py +207 -53
- nautobot/dcim/models/device_components.py +275 -106
- nautobot/dcim/models/devices.py +466 -13
- nautobot/dcim/navigation.py +47 -0
- nautobot/dcim/signals.py +3 -3
- nautobot/dcim/tables/__init__.py +35 -23
- nautobot/dcim/tables/devices.py +231 -59
- nautobot/dcim/tables/devicetypes.py +65 -9
- nautobot/dcim/tables/racks.py +5 -1
- nautobot/dcim/tables/template_code.py +46 -26
- nautobot/dcim/templates/dcim/cable_connect.html +76 -3
- nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -5
- nautobot/dcim/templates/dcim/device/base.html +15 -7
- nautobot/dcim/templates/dcim/device/consoleports.html +2 -3
- nautobot/dcim/templates/dcim/device/consoleserverports.html +2 -3
- nautobot/dcim/templates/dcim/device/devicebays.html +6 -7
- nautobot/dcim/templates/dcim/device/frontports.html +2 -3
- nautobot/dcim/templates/dcim/device/interfaces.html +2 -3
- nautobot/dcim/templates/dcim/device/inventory.html +2 -3
- nautobot/dcim/templates/dcim/device/modulebays.html +49 -0
- nautobot/dcim/templates/dcim/device/poweroutlets.html +2 -3
- nautobot/dcim/templates/dcim/device/powerports.html +2 -3
- nautobot/dcim/templates/dcim/device/rearports.html +2 -3
- nautobot/dcim/templates/dcim/device.html +45 -1
- nautobot/dcim/templates/dcim/device_component.html +13 -5
- nautobot/dcim/templates/dcim/device_list.html +2 -1
- nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +0 -6
- nautobot/dcim/templates/dcim/devicetype.html +99 -98
- nautobot/dcim/templates/dcim/devicetype_list.html +8 -16
- nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
- nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +39 -0
- nautobot/dcim/templates/dcim/interface.html +17 -2
- nautobot/dcim/templates/dcim/interface_connection_list.html +7 -5
- nautobot/dcim/templates/dcim/interface_edit.html +1 -0
- nautobot/dcim/templates/dcim/manufacturer.html +24 -0
- nautobot/dcim/templates/dcim/module/base.html +97 -0
- nautobot/dcim/templates/dcim/module_bulk_destroy.html +5 -0
- nautobot/dcim/templates/dcim/module_consoleports.html +53 -0
- nautobot/dcim/templates/dcim/module_consoleserverports.html +53 -0
- nautobot/dcim/templates/dcim/module_destroy.html +5 -0
- nautobot/dcim/templates/dcim/module_frontports.html +53 -0
- nautobot/dcim/templates/dcim/module_interfaces.html +57 -0
- nautobot/dcim/templates/dcim/module_list.html +20 -0
- nautobot/dcim/templates/dcim/module_modulebays.html +49 -0
- nautobot/dcim/templates/dcim/module_poweroutlets.html +53 -0
- nautobot/dcim/templates/dcim/module_powerports.html +53 -0
- nautobot/dcim/templates/dcim/module_rearports.html +53 -0
- nautobot/dcim/templates/dcim/module_retrieve.html +63 -0
- nautobot/dcim/templates/dcim/module_update.html +71 -0
- nautobot/dcim/templates/dcim/modulebay_bulk_destroy.html +5 -0
- nautobot/dcim/templates/dcim/modulebay_destroy.html +8 -0
- nautobot/dcim/templates/dcim/modulebay_retrieve.html +101 -0
- nautobot/dcim/templates/dcim/moduletype_list.html +11 -0
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +142 -0
- nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -5
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +65 -19
- nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
- nautobot/dcim/tests/test_api.py +691 -208
- nautobot/dcim/tests/test_filters.py +836 -217
- nautobot/dcim/tests/test_models.py +1072 -39
- nautobot/dcim/tests/test_views.py +1488 -358
- nautobot/dcim/urls.py +17 -2
- nautobot/dcim/utils.py +2 -3
- nautobot/dcim/views.py +1107 -120
- nautobot/extras/__init__.py +0 -1
- nautobot/extras/api/serializers.py +115 -3
- nautobot/extras/api/urls.py +12 -0
- nautobot/extras/api/views.py +125 -7
- nautobot/extras/apps.py +2 -2
- nautobot/extras/choices.py +43 -0
- nautobot/extras/context_managers.py +13 -8
- nautobot/extras/datasources/git.py +2 -0
- nautobot/extras/factory.py +422 -9
- nautobot/extras/filters/__init__.py +174 -3
- nautobot/extras/filters/mixins.py +46 -43
- nautobot/extras/forms/base.py +17 -4
- nautobot/extras/forms/forms.py +227 -8
- nautobot/extras/forms/mixins.py +93 -0
- nautobot/extras/graphql/types.py +23 -10
- nautobot/extras/homepage.py +16 -13
- nautobot/extras/jobs.py +2 -2
- nautobot/extras/management/__init__.py +1 -0
- nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +1 -16
- nautobot/extras/migrations/0021_customfield_changelog_data.py +1 -0
- nautobot/extras/migrations/0109_dynamicgroup_group_type_dynamicgroup_tags_and_more.py +108 -0
- nautobot/extras/migrations/0110_alter_configcontext_cluster_groups_and_more.py +111 -0
- nautobot/extras/migrations/0111_metadata.py +162 -0
- nautobot/extras/migrations/0112_dynamic_group_group_type_data_migration.py +28 -0
- nautobot/extras/migrations/0113_saved_views.py +77 -0
- nautobot/extras/models/__init__.py +15 -1
- nautobot/extras/models/change_logging.py +3 -3
- nautobot/extras/models/contacts.py +4 -0
- nautobot/extras/models/customfields.py +18 -3
- nautobot/extras/models/groups.py +389 -225
- nautobot/extras/models/jobs.py +4 -84
- nautobot/extras/models/metadata.py +441 -0
- nautobot/extras/models/mixins.py +72 -62
- nautobot/extras/models/models.py +116 -9
- nautobot/extras/models/relationships.py +9 -2
- nautobot/extras/models/tags.py +13 -2
- nautobot/extras/navigation.py +57 -0
- nautobot/extras/plugins/__init__.py +3 -1
- nautobot/extras/querysets.py +30 -66
- nautobot/extras/signals.py +96 -114
- nautobot/extras/tables.py +171 -47
- nautobot/extras/templates/extras/dynamicgroup.html +44 -15
- nautobot/extras/templates/extras/dynamicgroup_edit.html +2 -0
- nautobot/extras/templates/extras/job.html +1 -1
- nautobot/extras/templates/extras/job_detail.html +0 -11
- nautobot/extras/templates/extras/jobresult.html +61 -74
- nautobot/extras/templates/extras/metadatatype_create.html +89 -0
- nautobot/extras/templates/extras/metadatatype_retrieve.html +67 -0
- nautobot/extras/templates/extras/object_dynamicgroups.html +7 -0
- nautobot/extras/templates/extras/objectchange_list.html +0 -12
- nautobot/extras/templates/extras/plugins_list.html +1 -3
- nautobot/extras/templates/extras/role_retrieve.html +48 -0
- nautobot/extras/templates/extras/staticgroupassociation_retrieve.html +20 -0
- nautobot/extras/tests/integration/test_customfields.py +1 -0
- nautobot/extras/tests/test_api.py +501 -22
- nautobot/extras/tests/test_changelog.py +20 -9
- nautobot/extras/tests/test_context_managers.py +22 -15
- nautobot/extras/tests/test_datasources.py +13 -1
- nautobot/extras/tests/test_dynamicgroups.py +201 -171
- nautobot/extras/tests/test_filters.py +211 -12
- nautobot/extras/tests/test_jobs.py +4 -4
- nautobot/extras/tests/test_models.py +499 -4
- nautobot/extras/tests/test_relationships.py +1 -0
- nautobot/extras/tests/test_views.py +565 -28
- nautobot/extras/tests/test_webhooks.py +1 -1
- nautobot/extras/urls.py +5 -0
- nautobot/extras/utils.py +56 -45
- nautobot/extras/views.py +585 -96
- nautobot/ipam/__init__.py +0 -1
- nautobot/ipam/apps.py +1 -0
- nautobot/ipam/factory.py +17 -19
- nautobot/ipam/filters.py +14 -1
- nautobot/ipam/forms.py +9 -5
- nautobot/ipam/graphql/types.py +2 -2
- nautobot/ipam/migrations/0047_alter_ipaddress_role_alter_ipaddress_status_and_more.py +59 -0
- nautobot/ipam/models.py +23 -9
- nautobot/ipam/querysets.py +1 -1
- nautobot/ipam/signals.py +4 -2
- nautobot/ipam/tables.py +1 -0
- nautobot/ipam/templates/ipam/ipaddress_interfaces.html +1 -1
- nautobot/ipam/templates/ipam/ipaddress_vm_interfaces.html +1 -1
- nautobot/ipam/templates/ipam/prefix.html +1 -0
- nautobot/ipam/tests/test_api.py +37 -18
- nautobot/ipam/tests/test_filters.py +26 -2
- nautobot/ipam/tests/test_models.py +8 -3
- nautobot/ipam/tests/test_querysets.py +1 -1
- nautobot/ipam/tests/test_views.py +3 -2
- nautobot/ipam/urls.py +2 -2
- nautobot/ipam/views.py +25 -28
- nautobot/project-static/css/base.css +20 -1
- nautobot/project-static/css/dark.css +11 -0
- nautobot/project-static/docs/404.html +884 -80
- nautobot/project-static/docs/apps/index.html +884 -80
- nautobot/project-static/docs/apps/nautobot-apps.html +884 -80
- nautobot/project-static/docs/assets/_mkdocstrings.css +5 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +911 -112
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +896 -93
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1457 -790
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +927 -136
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +969 -180
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +893 -91
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +889 -85
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +983 -185
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +938 -143
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +1064 -274
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1190 -346
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1663 -865
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +1156 -373
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2200 -1502
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2229 -1421
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +904 -103
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +955 -155
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1002 -215
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +1911 -1275
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1835 -1091
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +896 -93
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +2323 -1693
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +1785 -1023
- nautobot/project-static/docs/development/apps/api/configuration-view.html +884 -80
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +884 -80
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +884 -80
- nautobot/project-static/docs/development/apps/api/models/global-search.html +884 -80
- nautobot/project-static/docs/development/apps/api/models/graphql.html +884 -80
- nautobot/project-static/docs/development/apps/api/models/index.html +922 -81
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +884 -80
- nautobot/project-static/docs/development/apps/api/prometheus.html +884 -80
- nautobot/project-static/docs/development/apps/api/setup.html +884 -80
- nautobot/project-static/docs/development/apps/api/testing.html +884 -80
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +884 -80
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +884 -80
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +884 -80
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +884 -80
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/base-template.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/index.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/notes.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/urls.html +884 -80
- nautobot/project-static/docs/development/apps/index.html +884 -80
- nautobot/project-static/docs/development/apps/migration/code-updates.html +884 -80
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +884 -80
- nautobot/project-static/docs/development/apps/migration/from-v1.html +884 -80
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +884 -80
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +884 -80
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +884 -80
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +884 -80
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +884 -80
- nautobot/project-static/docs/development/core/application-registry.html +884 -80
- nautobot/project-static/docs/development/core/best-practices.html +885 -80
- nautobot/project-static/docs/development/core/bootstrap-ui.html +884 -80
- nautobot/project-static/docs/development/core/caching.html +884 -80
- nautobot/project-static/docs/development/core/controllers.html +884 -80
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +884 -80
- nautobot/project-static/docs/development/core/generic-views.html +884 -80
- nautobot/project-static/docs/development/core/getting-started.html +884 -80
- nautobot/project-static/docs/development/core/homepage.html +884 -80
- nautobot/project-static/docs/development/core/index.html +884 -91
- nautobot/project-static/docs/development/core/model-checklist.html +887 -81
- nautobot/project-static/docs/development/core/model-features.html +884 -80
- nautobot/project-static/docs/development/core/natural-keys.html +884 -80
- nautobot/project-static/docs/development/core/navigation-menu.html +884 -80
- nautobot/project-static/docs/development/core/release-checklist.html +887 -83
- nautobot/project-static/docs/development/core/role-internals.html +884 -80
- nautobot/project-static/docs/development/core/settings.html +884 -80
- nautobot/project-static/docs/development/core/style-guide.html +885 -81
- nautobot/project-static/docs/development/core/templates.html +896 -81
- nautobot/project-static/docs/development/core/testing.html +884 -80
- nautobot/project-static/docs/development/core/user-preferences.html +884 -80
- nautobot/project-static/docs/development/index.html +884 -80
- nautobot/project-static/docs/development/jobs/index.html +1247 -457
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +884 -80
- nautobot/project-static/docs/index.html +13 -8228
- nautobot/project-static/docs/media/models/cloud_aws_direct_connect_dark.png +0 -0
- nautobot/project-static/docs/media/models/cloud_aws_direct_connect_light.png +0 -0
- nautobot/project-static/docs/models/cloud/cloudaccount.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudnetwork.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudnetworkprefixassignment.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudresourcetype.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudservice.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudservicenetworkassignment.html +15 -0
- nautobot/project-static/docs/models/dcim/module.html +15 -0
- nautobot/project-static/docs/models/dcim/modulebay.html +15 -0
- nautobot/project-static/docs/models/dcim/modulebaytemplate.html +15 -0
- nautobot/project-static/docs/models/dcim/moduletype.html +15 -0
- nautobot/project-static/docs/models/extras/metadatachoice.html +15 -0
- nautobot/project-static/docs/models/extras/metadatatype.html +15 -0
- nautobot/project-static/docs/models/extras/objectmetadata.html +15 -0
- nautobot/project-static/docs/models/extras/role.html +15 -0
- nautobot/project-static/docs/models/extras/savedview.html +15 -0
- nautobot/project-static/docs/models/extras/staticgroupassociation.html +15 -0
- nautobot/project-static/docs/models/extras/status.html +15 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +892 -81
- nautobot/project-static/docs/overview/design_philosophy.html +886 -82
- nautobot/project-static/docs/overview/index.html +9032 -13
- nautobot/project-static/docs/release-notes/index.html +887 -83
- nautobot/project-static/docs/release-notes/version-1.0.html +884 -80
- nautobot/project-static/docs/release-notes/version-1.1.html +884 -80
- nautobot/project-static/docs/release-notes/version-1.2.html +884 -80
- nautobot/project-static/docs/release-notes/version-1.3.html +884 -80
- nautobot/project-static/docs/release-notes/version-1.4.html +884 -80
- nautobot/project-static/docs/release-notes/version-1.5.html +885 -81
- nautobot/project-static/docs/release-notes/version-1.6.html +885 -81
- nautobot/project-static/docs/release-notes/version-2.0.html +884 -80
- nautobot/project-static/docs/release-notes/version-2.1.html +884 -80
- nautobot/project-static/docs/release-notes/version-2.2.html +990 -323
- nautobot/project-static/docs/release-notes/version-2.3.html +9524 -0
- nautobot/project-static/docs/requirements.txt +4 -4
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +335 -260
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +884 -80
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +884 -80
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +884 -80
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +884 -80
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +983 -197
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +884 -80
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +888 -84
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/index.html +888 -80
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/services.html +888 -80
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +900 -91
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +884 -80
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +884 -80
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +884 -80
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +915 -163
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +885 -81
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +888 -80
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +887 -83
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +8984 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +8829 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +8829 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +8833 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +915 -97
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +915 -97
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +910 -92
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +915 -97
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +905 -97
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +912 -108
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +913 -109
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +910 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +906 -97
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +918 -100
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +928 -110
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +920 -98
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +929 -111
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +920 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +910 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +913 -109
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +914 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +8846 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +8843 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +8823 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +932 -75
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +916 -98
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +935 -78
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +913 -95
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +921 -117
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +910 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +914 -96
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +916 -98
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +889 -81
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +889 -81
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +893 -88
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +889 -81
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/clear-view-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/cleared-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/config-table-columns-to-locations.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/configure-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/create-saved-view-success.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/current-saved-view-drop-down-menu.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/default-location-list-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/dropdown-button-after-new-saved-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-application-to-locations.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/global-default-location-list-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/location-list-view-with-saved-views.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/navigation-menu.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-as-new-view-drop-down.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-view-modal.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-buttons.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-success.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view-unchecked.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-different-user.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-modal-unchecked.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-success.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/unsaved-saved-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/updated-saved-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +884 -80
- nautobot/project-static/docs/user-guide/index.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +1250 -777
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +887 -83
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +887 -83
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +888 -80
- nautobot/project-static/docs/user-guide/platform-functionality/metadata.html +8948 -0
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +887 -83
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +887 -83
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +9137 -0
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +887 -83
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +8933 -0
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +942 -113
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +884 -80
- nautobot/project-static/js/forms.js +71 -0
- nautobot/project-static/js/table_sorting_indicator.js +46 -0
- nautobot/project-static/js/tableconfig.js +6 -1
- nautobot/project-static/materialdesignicons-7.4.47/css/materialdesignicons.min.css +3 -0
- nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.eot +0 -0
- nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.ttf +0 -0
- nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff +0 -0
- nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff2 +0 -0
- nautobot/tenancy/__init__.py +0 -1
- nautobot/tenancy/apps.py +1 -0
- nautobot/tenancy/factory.py +3 -2
- nautobot/tenancy/filters/__init__.py +1 -0
- nautobot/tenancy/forms.py +1 -1
- nautobot/tenancy/templates/tenancy/tenant.html +22 -18
- nautobot/tenancy/views.py +11 -10
- nautobot/users/__init__.py +0 -1
- nautobot/users/api/serializers.py +1 -1
- nautobot/users/api/views.py +4 -2
- nautobot/users/apps.py +3 -2
- nautobot/users/factory.py +3 -3
- nautobot/users/migrations/0010_user_default_saved_views.py +20 -0
- nautobot/users/models.py +12 -0
- nautobot/users/tests/test_filters.py +6 -3
- nautobot/users/urls.py +8 -0
- nautobot/virtualization/__init__.py +0 -1
- nautobot/virtualization/apps.py +1 -0
- nautobot/virtualization/filters.py +6 -1
- nautobot/virtualization/forms.py +11 -3
- nautobot/virtualization/graphql/types.py +2 -2
- nautobot/virtualization/migrations/0029_add_role_field_to_interface_models.py +27 -0
- nautobot/virtualization/migrations/0030_alter_virtualmachine_local_config_context_data_owner_content_type_and_more.py +67 -0
- nautobot/virtualization/tables.py +15 -5
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
- nautobot/virtualization/templates/virtualization/vminterface.html +7 -1
- nautobot/virtualization/templates/virtualization/vminterface_edit.html +1 -0
- nautobot/virtualization/tests/test_api.py +9 -4
- nautobot/virtualization/tests/test_filters.py +22 -0
- nautobot/virtualization/tests/test_models.py +7 -3
- nautobot/virtualization/tests/test_views.py +19 -3
- nautobot/virtualization/urls.py +2 -2
- nautobot/virtualization/views.py +10 -32
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/METADATA +21 -19
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/RECORD +679 -559
- nautobot/project-static/materialdesignicons-6.5.95/.github/ISSUE_TEMPLATE.md +0 -3
- nautobot/project-static/materialdesignicons-6.5.95/README.md +0 -25
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css +0 -26654
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css.map +0 -16
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css +0 -3
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css.map +0 -16
- nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff +0 -0
- nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff2 +0 -0
- nautobot/project-static/materialdesignicons-6.5.95/package.json +0 -28
- nautobot/project-static/materialdesignicons-6.5.95/preview.html +0 -717
- nautobot/project-static/materialdesignicons-6.5.95/scss/_animated.scss +0 -27
- nautobot/project-static/materialdesignicons-6.5.95/scss/_core.scss +0 -10
- nautobot/project-static/materialdesignicons-6.5.95/scss/_extras.scss +0 -65
- nautobot/project-static/materialdesignicons-6.5.95/scss/_functions.scss +0 -20
- nautobot/project-static/materialdesignicons-6.5.95/scss/_icons.scss +0 -10
- nautobot/project-static/materialdesignicons-6.5.95/scss/_path.scss +0 -10
- nautobot/project-static/materialdesignicons-6.5.95/scss/_variables.scss +0 -6606
- nautobot/project-static/materialdesignicons-6.5.95/scss/materialdesignicons.scss +0 -8
- /nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/LICENSE +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/NOTICE +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/WHEEL +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/entry_points.txt +0 -0
nautobot/core/filters.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from collections import OrderedDict
|
|
2
1
|
from copy import deepcopy
|
|
3
2
|
import logging
|
|
4
3
|
import uuid
|
|
@@ -7,11 +6,9 @@ from django import forms as django_forms
|
|
|
7
6
|
from django.conf import settings
|
|
8
7
|
from django.db import models
|
|
9
8
|
from django.forms.utils import ErrorDict, ErrorList
|
|
10
|
-
from django.utils.encoding import force_str
|
|
11
|
-
from django.utils.text import capfirst
|
|
12
9
|
import django_filters
|
|
13
10
|
from django_filters.constants import EMPTY_VALUES
|
|
14
|
-
from django_filters.utils import get_model_field,
|
|
11
|
+
from django_filters.utils import get_model_field, resolve_field
|
|
15
12
|
from drf_spectacular.types import OpenApiTypes
|
|
16
13
|
from drf_spectacular.utils import extend_schema_field
|
|
17
14
|
|
|
@@ -125,8 +122,8 @@ class MultiValueUUIDFilter(django_filters.UUIDFilter, django_filters.MultipleCho
|
|
|
125
122
|
|
|
126
123
|
class RelatedMembershipBooleanFilter(django_filters.BooleanFilter):
|
|
127
124
|
"""
|
|
128
|
-
BooleanFilter for related objects that will explicitly perform `
|
|
129
|
-
|
|
125
|
+
BooleanFilter for related objects that will explicitly perform `isnull` lookups.
|
|
126
|
+
The `field_name` argument is required and must be set to the related field on the
|
|
130
127
|
model.
|
|
131
128
|
|
|
132
129
|
This should be used instead of a default `BooleanFilter` paired `method=`
|
|
@@ -134,15 +131,33 @@ class RelatedMembershipBooleanFilter(django_filters.BooleanFilter):
|
|
|
134
131
|
|
|
135
132
|
Example:
|
|
136
133
|
|
|
137
|
-
|
|
138
|
-
field_name="
|
|
139
|
-
label="Has
|
|
134
|
+
has_modules = RelatedMembershipBooleanFilter(
|
|
135
|
+
field_name="module_bays__installed_module",
|
|
136
|
+
label="Has modules",
|
|
140
137
|
)
|
|
138
|
+
|
|
139
|
+
This would generate a filter that returns instances that have at least one module
|
|
140
|
+
bay with an installed module. The `has_modules=False` filter would exclude instances
|
|
141
|
+
with at least one module bay with an installed module.
|
|
142
|
+
|
|
143
|
+
Set `exclude=True` to reverse the behavior of the filter. This __may__ be useful
|
|
144
|
+
for filtering on null directly related fields but this filter is not smart enough
|
|
145
|
+
to differentiate between `fieldA__fieldB__isnull` and `fieldA__isnull` so it's not
|
|
146
|
+
suitable for cases like the `has_empty_module_bays` filter where an instance may
|
|
147
|
+
not have any module bays.
|
|
148
|
+
|
|
149
|
+
See the below table for more information:
|
|
150
|
+
|
|
151
|
+
| value | exclude | Result
|
|
152
|
+
|-------------|------------------|-------
|
|
153
|
+
| True | False (default) | Return instances with at least one non-null match -- qs.filter(field_name__isnull=False)
|
|
154
|
+
| False | False (default) | Exclude instances with at least one non-null match -- qs.exclude(field_name__isnull=False)
|
|
155
|
+
| True | True | Return instances with at least one null match -- qs.filter(field_name__isnull=True)
|
|
156
|
+
| False | True | Exclude instances with at least one null match -- qs.exclude(field_name__isnull=True)
|
|
157
|
+
|
|
141
158
|
"""
|
|
142
159
|
|
|
143
|
-
def __init__(
|
|
144
|
-
self, field_name=None, lookup_expr="isnull", *, label=None, method=None, distinct=False, exclude=True, **kwargs
|
|
145
|
-
):
|
|
160
|
+
def __init__(self, field_name=None, lookup_expr="isnull", *, label=None, method=None, distinct=True, **kwargs):
|
|
146
161
|
if field_name is None:
|
|
147
162
|
raise ValueError(f"Field name is required for {self.__class__.__name__}")
|
|
148
163
|
|
|
@@ -152,11 +167,23 @@ class RelatedMembershipBooleanFilter(django_filters.BooleanFilter):
|
|
|
152
167
|
label=label,
|
|
153
168
|
method=method,
|
|
154
169
|
distinct=distinct,
|
|
155
|
-
exclude=exclude,
|
|
156
170
|
widget=forms.StaticSelect2(choices=forms.BOOLEAN_CHOICES),
|
|
157
171
|
**kwargs,
|
|
158
172
|
)
|
|
159
173
|
|
|
174
|
+
def filter(self, qs, value):
|
|
175
|
+
if value in EMPTY_VALUES:
|
|
176
|
+
return qs
|
|
177
|
+
if self.distinct:
|
|
178
|
+
qs = qs.distinct()
|
|
179
|
+
lookup = f"{self.field_name}__{self.lookup_expr}"
|
|
180
|
+
if bool(value):
|
|
181
|
+
# if self.exclude=False, return instances with field populated
|
|
182
|
+
return qs.filter(**{lookup: self.exclude})
|
|
183
|
+
else:
|
|
184
|
+
# if self.exclude=False, exclude instances with field populated
|
|
185
|
+
return qs.exclude(**{lookup: self.exclude})
|
|
186
|
+
|
|
160
187
|
|
|
161
188
|
class NumericArrayFilter(django_filters.NumberFilter):
|
|
162
189
|
"""
|
|
@@ -403,12 +430,22 @@ class NaturalKeyOrPKMultipleChoiceFilter(django_filters.ModelMultipleChoiceFilte
|
|
|
403
430
|
Filter that supports filtering on values matching the `pk` field and another
|
|
404
431
|
field of a foreign-key related object. The desired field is set using the `to_field_name`
|
|
405
432
|
keyword argument on filter initialization (defaults to `name`).
|
|
433
|
+
|
|
434
|
+
NOTE that the `to_field_name` field does not have to be a "true" natural key (ie. unique), it
|
|
435
|
+
was just the best name we could come up with for this filter
|
|
436
|
+
|
|
406
437
|
"""
|
|
407
438
|
|
|
408
439
|
field_class = forms.MultiMatchModelMultipleChoiceField
|
|
409
440
|
|
|
410
|
-
def __init__(self, *args, **kwargs):
|
|
441
|
+
def __init__(self, *args, prefers_id=False, **kwargs):
|
|
442
|
+
"""Initialize the NaturalKeyOrPKMultipleChoiceFilter.
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
prefers_id (bool, optional): Prefer PK (ID) over the 'to_field_name'. Defaults to False.
|
|
446
|
+
"""
|
|
411
447
|
self.natural_key = kwargs.setdefault("to_field_name", "name")
|
|
448
|
+
self.prefers_id = prefers_id
|
|
412
449
|
super().__init__(*args, **kwargs)
|
|
413
450
|
|
|
414
451
|
def get_filter_predicate(self, v):
|
|
@@ -683,18 +720,6 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
683
720
|
# Of course setting the negation of the existing filter's exclude attribute handles both cases
|
|
684
721
|
new_filter.exclude = not filter_field.exclude
|
|
685
722
|
|
|
686
|
-
# If the base filter_field has a custom label, django_filters won't adjust it for the new_filter lookup,
|
|
687
|
-
# so we have to do it.
|
|
688
|
-
if filter_field.label and filter_field.label != label_for_filter(
|
|
689
|
-
cls.Meta.model, filter_field.field_name, filter_field.lookup_expr, filter_field.exclude
|
|
690
|
-
):
|
|
691
|
-
# Lightly adjusted from label_for_filter() implementation:
|
|
692
|
-
verbose_expression = ["exclude", filter_field.label] if new_filter.exclude else [filter_field.label]
|
|
693
|
-
if isinstance(lookup_expr, str):
|
|
694
|
-
verbose_expression.append(verbose_lookup_expr(lookup_expr))
|
|
695
|
-
verbose_expression = [force_str(part) for part in verbose_expression if part]
|
|
696
|
-
new_filter.label = capfirst(" ".join(verbose_expression))
|
|
697
|
-
|
|
698
723
|
magic_filters[new_filter_name] = new_filter
|
|
699
724
|
|
|
700
725
|
return magic_filters
|
|
@@ -725,8 +750,8 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
725
750
|
def get_fields(cls):
|
|
726
751
|
fields = super().get_fields()
|
|
727
752
|
if "id" not in fields and (cls._meta.exclude is None or "id" not in cls._meta.exclude):
|
|
728
|
-
# Add "id" as the first key in the `fields`
|
|
729
|
-
fields =
|
|
753
|
+
# Add "id" as the first key in the `fields` dict
|
|
754
|
+
fields = {"id": [django_filters.conf.settings.DEFAULT_LOOKUP_EXPR], **fields}
|
|
730
755
|
return fields
|
|
731
756
|
|
|
732
757
|
@classmethod
|
|
@@ -741,8 +766,51 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
741
766
|
if filter_name.startswith("_"):
|
|
742
767
|
del filters[filter_name]
|
|
743
768
|
|
|
769
|
+
if getattr(cls._meta.model, "is_contact_associable_model", False):
|
|
770
|
+
# Add "contacts" and "teams" filters
|
|
771
|
+
from nautobot.extras.models import Contact, Team
|
|
772
|
+
|
|
773
|
+
if "contacts" not in filters:
|
|
774
|
+
filters["contacts"] = NaturalKeyOrPKMultipleChoiceFilter(
|
|
775
|
+
queryset=Contact.objects.all(),
|
|
776
|
+
field_name="associated_contacts__contact",
|
|
777
|
+
to_field_name="name",
|
|
778
|
+
label="Contacts (name or ID)",
|
|
779
|
+
)
|
|
780
|
+
|
|
781
|
+
if "teams" not in filters:
|
|
782
|
+
filters["teams"] = NaturalKeyOrPKMultipleChoiceFilter(
|
|
783
|
+
queryset=Team.objects.all(),
|
|
784
|
+
field_name="associated_contacts__team",
|
|
785
|
+
to_field_name="name",
|
|
786
|
+
label="Teams (name or ID)",
|
|
787
|
+
)
|
|
788
|
+
|
|
789
|
+
if "dynamic_groups" not in filters and getattr(cls._meta.model, "is_dynamic_group_associable_model", False):
|
|
790
|
+
if not hasattr(cls._meta.model, "static_group_association_set"):
|
|
791
|
+
logger.warning(
|
|
792
|
+
"Model %s has 'is_dynamic_group_associable_model = True' but lacks "
|
|
793
|
+
"a 'static_group_association_set' attribute. Perhaps this is due to it inheriting from "
|
|
794
|
+
"the deprecated DynamicGroupMixin class instead of the preferred DynamicGroupsModelMixin?",
|
|
795
|
+
cls._meta.model,
|
|
796
|
+
)
|
|
797
|
+
else:
|
|
798
|
+
# Add "dynamic_groups" field as the last key
|
|
799
|
+
from nautobot.extras.models import DynamicGroup
|
|
800
|
+
|
|
801
|
+
filters["dynamic_groups"] = NaturalKeyOrPKMultipleChoiceFilter(
|
|
802
|
+
queryset=DynamicGroup.objects.all(),
|
|
803
|
+
field_name="static_group_association_set__dynamic_group",
|
|
804
|
+
to_field_name="name",
|
|
805
|
+
query_params={"content_type": cls._meta.model._meta.label_lower},
|
|
806
|
+
label="Dynamic groups (name or ID)",
|
|
807
|
+
)
|
|
808
|
+
|
|
744
809
|
# django-filters has no concept of "abstract" filtersets, so we have to fake it
|
|
745
810
|
if cls._meta.model is not None:
|
|
811
|
+
if "tags" in filters and isinstance(filters["tags"], TagFilter):
|
|
812
|
+
filters["tags"].extra["query_params"] = {"content_types": [cls._meta.model._meta.label_lower]}
|
|
813
|
+
|
|
746
814
|
new_filters = {}
|
|
747
815
|
for existing_filter_name, existing_filter in filters.items():
|
|
748
816
|
new_filters.update(
|
nautobot/core/forms/fields.py
CHANGED
|
@@ -228,6 +228,10 @@ class MultipleContentTypeField(django_forms.ModelMultipleChoiceField):
|
|
|
228
228
|
|
|
229
229
|
if "queryset" not in kwargs:
|
|
230
230
|
if feature is not None:
|
|
231
|
+
from nautobot.extras.registry import registry
|
|
232
|
+
|
|
233
|
+
if feature not in registry["model_features"]:
|
|
234
|
+
raise KeyError
|
|
231
235
|
kwargs["queryset"] = ContentType.objects.filter(
|
|
232
236
|
extras_utils.FeatureQuery(feature).get_query()
|
|
233
237
|
).order_by("app_label", "model")
|
|
@@ -453,6 +457,7 @@ class DynamicModelChoiceMixin:
|
|
|
453
457
|
|
|
454
458
|
filter = django_filters.ModelChoiceFilter # 2.0 TODO(Glenn): can we rename this? pylint: disable=redefined-builtin
|
|
455
459
|
widget = widgets.APISelect
|
|
460
|
+
iterator = widgets.MinimalModelChoiceIterator
|
|
456
461
|
|
|
457
462
|
def __init__(
|
|
458
463
|
self,
|
|
@@ -475,6 +480,7 @@ class DynamicModelChoiceMixin:
|
|
|
475
480
|
# to_field_name is set by ModelChoiceField.__init__(), but we need to set it early for reference
|
|
476
481
|
# by widget_attrs()
|
|
477
482
|
self.to_field_name = kwargs.get("to_field_name")
|
|
483
|
+
self.data_queryset = kwargs.get("queryset") # may be updated in get_bound_field()
|
|
478
484
|
|
|
479
485
|
super().__init__(*args, **kwargs)
|
|
480
486
|
|
|
@@ -539,12 +545,12 @@ class DynamicModelChoiceMixin:
|
|
|
539
545
|
field_name = getattr(self, "to_field_name") or "pk"
|
|
540
546
|
filter_ = self.filter(field_name=field_name)
|
|
541
547
|
try:
|
|
542
|
-
self.
|
|
543
|
-
except (TypeError, ValidationError):
|
|
548
|
+
self.data_queryset = filter_.filter(self.queryset, data)
|
|
549
|
+
except (TypeError, ValueError, ValidationError):
|
|
544
550
|
# Catch any error caused by invalid initial data passed from the user
|
|
545
|
-
self.
|
|
551
|
+
self.data_queryset = self.queryset.none()
|
|
546
552
|
else:
|
|
547
|
-
self.
|
|
553
|
+
self.data_queryset = self.queryset.none()
|
|
548
554
|
|
|
549
555
|
# Set the data URL on the APISelect widget (if not already set)
|
|
550
556
|
widget = bound_field.field.widget
|
nautobot/core/forms/forms.py
CHANGED
|
@@ -121,7 +121,7 @@ class BulkRenameForm(forms.Form):
|
|
|
121
121
|
"""
|
|
122
122
|
|
|
123
123
|
find = forms.CharField()
|
|
124
|
-
replace = forms.CharField()
|
|
124
|
+
replace = forms.CharField(required=False, strip=False)
|
|
125
125
|
use_regex = forms.BooleanField(required=False, initial=True, label="Use regular expressions")
|
|
126
126
|
|
|
127
127
|
def clean(self):
|
nautobot/core/forms/widgets.py
CHANGED
|
@@ -116,6 +116,23 @@ class ContentTypeSelect(StaticSelect2):
|
|
|
116
116
|
option_template_name = "widgets/select_contenttype.html"
|
|
117
117
|
|
|
118
118
|
|
|
119
|
+
class MinimalModelChoiceIterator(ModelChoiceIterator):
|
|
120
|
+
"""
|
|
121
|
+
Helper class for APISelect and APISelectMultiple.
|
|
122
|
+
|
|
123
|
+
Allows the widget to keep a full `queryset` for data validation, but, for performance reasons, returns a minimal
|
|
124
|
+
subset of choices at render time derived from the widget's `data_queryset`.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def queryset(self):
|
|
129
|
+
return self.field.data_queryset
|
|
130
|
+
|
|
131
|
+
@queryset.setter
|
|
132
|
+
def queryset(self, value):
|
|
133
|
+
return self.field.data_queryset
|
|
134
|
+
|
|
135
|
+
|
|
119
136
|
class APISelect(SelectWithDisabled):
|
|
120
137
|
"""
|
|
121
138
|
A select widget populated via an API call
|
|
@@ -173,7 +190,7 @@ class APISelect(SelectWithDisabled):
|
|
|
173
190
|
and isinstance(self.choices, Iterable)
|
|
174
191
|
):
|
|
175
192
|
|
|
176
|
-
class ModelChoiceIteratorWithNullOption(
|
|
193
|
+
class ModelChoiceIteratorWithNullOption(MinimalModelChoiceIterator):
|
|
177
194
|
def __init__(self, *args, **kwargs):
|
|
178
195
|
self.null_options = kwargs.pop("null_option", None)
|
|
179
196
|
super().__init__(*args, **kwargs)
|
|
@@ -64,8 +64,8 @@ def generate_filter_resolver(schema_type, resolver_name, field_name):
|
|
|
64
64
|
"""
|
|
65
65
|
filterset_class = schema_type._meta.filterset_class
|
|
66
66
|
|
|
67
|
-
def resolve_filter(self,
|
|
68
|
-
if not filterset_class
|
|
67
|
+
def resolve_filter(self, *args, **kwargs):
|
|
68
|
+
if not filterset_class:
|
|
69
69
|
return getattr(self, field_name).all()
|
|
70
70
|
|
|
71
71
|
# Inverse of substitution logic from get_filtering_args_from_filterset() - transform "_type" back to "type"
|
nautobot/core/graphql/schema.py
CHANGED
|
@@ -42,7 +42,7 @@ from nautobot.dcim.graphql.types import (
|
|
|
42
42
|
RearPortType,
|
|
43
43
|
)
|
|
44
44
|
from nautobot.extras.choices import CustomFieldTypeChoices, RelationshipSideChoices
|
|
45
|
-
from nautobot.extras.graphql.types import DynamicGroupType, TagType
|
|
45
|
+
from nautobot.extras.graphql.types import ContactAssociationType, DynamicGroupType, TagType
|
|
46
46
|
from nautobot.extras.models import ComputedField, CustomField, Relationship
|
|
47
47
|
from nautobot.extras.registry import registry
|
|
48
48
|
from nautobot.extras.utils import check_if_key_is_graphql_safe
|
|
@@ -68,8 +68,9 @@ registry["graphql_types"]["dcim.powerport"] = PowerPortType
|
|
|
68
68
|
registry["graphql_types"]["dcim.rack"] = RackType
|
|
69
69
|
registry["graphql_types"]["dcim.rearport"] = RearPortType
|
|
70
70
|
registry["graphql_types"]["dcim.location"] = LocationType
|
|
71
|
-
registry["graphql_types"]["extras.
|
|
71
|
+
registry["graphql_types"]["extras.contactassociation"] = ContactAssociationType
|
|
72
72
|
registry["graphql_types"]["extras.dynamicgroup"] = DynamicGroupType
|
|
73
|
+
registry["graphql_types"]["extras.tag"] = TagType
|
|
73
74
|
registry["graphql_types"]["ipam.ipaddress"] = IPAddressType
|
|
74
75
|
registry["graphql_types"]["ipam.prefix"] = PrefixType
|
|
75
76
|
registry["graphql_types"]["ipam.vlan"] = VLANType
|
|
@@ -127,6 +128,11 @@ def extend_schema_type(schema_type):
|
|
|
127
128
|
#
|
|
128
129
|
schema_type = extend_schema_type_config_context(schema_type, model)
|
|
129
130
|
|
|
131
|
+
#
|
|
132
|
+
# Global features (contacts, teams, dynamic groups)
|
|
133
|
+
#
|
|
134
|
+
schema_type = extend_schema_type_global_features(schema_type, model)
|
|
135
|
+
|
|
130
136
|
#
|
|
131
137
|
# Relationships
|
|
132
138
|
#
|
|
@@ -366,13 +372,37 @@ def extend_schema_type_config_context(schema_type, model):
|
|
|
366
372
|
return schema_type
|
|
367
373
|
|
|
368
374
|
|
|
375
|
+
def extend_schema_type_global_features(schema_type, model):
|
|
376
|
+
"""
|
|
377
|
+
Extend schema_type object to have attributes and resolvers for global features (contacts, dynamic groups, etc.).
|
|
378
|
+
"""
|
|
379
|
+
if getattr(model, "is_contact_associable_model", False):
|
|
380
|
+
|
|
381
|
+
def resolve_associated_contacts(self, args):
|
|
382
|
+
return self.associated_contacts.all()
|
|
383
|
+
|
|
384
|
+
setattr(schema_type, "resolve_associated_contacts", resolve_associated_contacts)
|
|
385
|
+
schema_type._meta.fields["associated_contacts"] = graphene.Field.mounted(graphene.List(ContactAssociationType))
|
|
386
|
+
|
|
387
|
+
if getattr(model, "is_dynamic_group_associable_model", False):
|
|
388
|
+
|
|
389
|
+
def resolve_dynamic_groups(self, args):
|
|
390
|
+
return self.dynamic_groups
|
|
391
|
+
|
|
392
|
+
setattr(schema_type, "resolve_dynamic_groups", resolve_dynamic_groups)
|
|
393
|
+
schema_type._meta.fields["dynamic_groups"] = graphene.Field.mounted(graphene.List(DynamicGroupType))
|
|
394
|
+
|
|
395
|
+
return schema_type
|
|
396
|
+
|
|
397
|
+
|
|
369
398
|
def extend_schema_type_relationships(schema_type, model):
|
|
370
399
|
"""Extend the schema type with attributes and resolvers corresponding
|
|
371
400
|
to the relationships associated with this model."""
|
|
372
401
|
|
|
402
|
+
ct = ContentType.objects.get_for_model(model)
|
|
373
403
|
relationships_by_side = {
|
|
374
|
-
"source": Relationship.objects.
|
|
375
|
-
"destination": Relationship.objects.
|
|
404
|
+
"source": Relationship.objects.filter(source_type=ct),
|
|
405
|
+
"destination": Relationship.objects.filter(destination_type=ct),
|
|
376
406
|
}
|
|
377
407
|
|
|
378
408
|
prefix = ""
|
nautobot/core/jobs/__init__.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import codecs
|
|
2
1
|
import contextlib
|
|
3
2
|
from io import BytesIO
|
|
4
3
|
|
|
@@ -15,6 +14,8 @@ from nautobot.core.api.renderers import NautobotCSVRenderer
|
|
|
15
14
|
from nautobot.core.api.utils import get_serializer_for_model
|
|
16
15
|
from nautobot.core.celery import app, register_jobs
|
|
17
16
|
from nautobot.core.exceptions import AbortTransaction
|
|
17
|
+
from nautobot.core.jobs.cleanup import LogsCleanup
|
|
18
|
+
from nautobot.core.jobs.groups import RefreshDynamicGroupCaches
|
|
18
19
|
from nautobot.core.utils.lookup import get_filterset_for_model
|
|
19
20
|
from nautobot.core.utils.requests import get_filterable_params_from_filter_params
|
|
20
21
|
from nautobot.extras.datasources import ensure_git_repository, git_repository_dry_run, refresh_datasource_content
|
|
@@ -37,6 +38,7 @@ class GitRepositorySync(Job):
|
|
|
37
38
|
|
|
38
39
|
class Meta:
|
|
39
40
|
name = "Git Repository: Sync"
|
|
41
|
+
description = "Clone and/or pull a Git repository, then refresh data sourced from this repository."
|
|
40
42
|
has_sensitive_variables = False
|
|
41
43
|
|
|
42
44
|
def run(self, repository):
|
|
@@ -66,6 +68,7 @@ class GitRepositoryDryRun(Job):
|
|
|
66
68
|
|
|
67
69
|
class Meta:
|
|
68
70
|
name = "Git Repository: Dry-Run"
|
|
71
|
+
description = "Dry run of Git repository sync - will not update data sourced from this repository."
|
|
69
72
|
has_sensitive_variables = False
|
|
70
73
|
|
|
71
74
|
def run(self, repository):
|
|
@@ -112,6 +115,7 @@ class ExportObjectList(Job):
|
|
|
112
115
|
|
|
113
116
|
class Meta:
|
|
114
117
|
name = "Export Object List"
|
|
118
|
+
description = "Export a list of objects to CSV or YAML, or render a specified Export Template."
|
|
115
119
|
has_sensitive_variables = False
|
|
116
120
|
# Exporting large querysets may take substantial processing time
|
|
117
121
|
soft_time_limit = 1800
|
|
@@ -136,7 +140,15 @@ class ExportObjectList(Job):
|
|
|
136
140
|
# such that they never are even seen here.
|
|
137
141
|
query_params = QueryDict(query_string)
|
|
138
142
|
self.logger.debug("Parsed query_params: `%s`", query_params.dict())
|
|
139
|
-
default_non_filter_params = (
|
|
143
|
+
default_non_filter_params = (
|
|
144
|
+
"all_filters_removed",
|
|
145
|
+
"export",
|
|
146
|
+
"page",
|
|
147
|
+
"per_page",
|
|
148
|
+
"saved_view",
|
|
149
|
+
"sort",
|
|
150
|
+
"table_changes_pending",
|
|
151
|
+
)
|
|
140
152
|
filter_params = get_filterable_params_from_filter_params(
|
|
141
153
|
query_params, default_non_filter_params, filterset_class()
|
|
142
154
|
)
|
|
@@ -213,6 +225,7 @@ class ImportObjects(Job):
|
|
|
213
225
|
|
|
214
226
|
class Meta:
|
|
215
227
|
name = "Import Objects"
|
|
228
|
+
description = "Import objects from CSV-formatted data."
|
|
216
229
|
has_sensitive_variables = False
|
|
217
230
|
# Importing large files may take substantial processing time
|
|
218
231
|
soft_time_limit = 1800
|
|
@@ -283,9 +296,7 @@ class ImportObjects(Job):
|
|
|
283
296
|
if not csv_data and not csv_file:
|
|
284
297
|
raise RunJobTaskFailed("Either csv_data or csv_file must be provided")
|
|
285
298
|
if csv_file:
|
|
286
|
-
|
|
287
|
-
# Bytes read from the original file are decoded according to file_encoding, and the result is encoded using data_encoding.
|
|
288
|
-
csv_bytes = codecs.EncodedFile(csv_file, "utf-8", "utf-8-sig")
|
|
299
|
+
csv_bytes = csv_file
|
|
289
300
|
else:
|
|
290
301
|
csv_bytes = BytesIO(csv_data.encode("utf-8"))
|
|
291
302
|
|
|
@@ -317,5 +328,5 @@ class ImportObjects(Job):
|
|
|
317
328
|
raise RunJobTaskFailed("CSV import not fully successful, see logs")
|
|
318
329
|
|
|
319
330
|
|
|
320
|
-
jobs = [ExportObjectList, GitRepositorySync, GitRepositoryDryRun, ImportObjects]
|
|
331
|
+
jobs = [ExportObjectList, GitRepositorySync, GitRepositoryDryRun, ImportObjects, LogsCleanup, RefreshDynamicGroupCaches]
|
|
321
332
|
register_jobs(*jobs)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from datetime import timedelta
|
|
2
|
+
|
|
3
|
+
from django.core.exceptions import PermissionDenied
|
|
4
|
+
from django.db.models.signals import pre_delete
|
|
5
|
+
from django.utils import timezone
|
|
6
|
+
|
|
7
|
+
from nautobot.core.choices import ChoiceSet
|
|
8
|
+
from nautobot.core.utils.config import get_settings_or_config
|
|
9
|
+
from nautobot.extras.jobs import IntegerVar, Job, MultiChoiceVar
|
|
10
|
+
from nautobot.extras.models import JobResult, ObjectChange
|
|
11
|
+
from nautobot.extras.signals import _handle_deleted_object
|
|
12
|
+
|
|
13
|
+
name = "System Jobs"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CleanupTypes(ChoiceSet):
|
|
17
|
+
JOB_RESULT = "extras.JobResult"
|
|
18
|
+
OBJECT_CHANGE = "extras.ObjectChange"
|
|
19
|
+
|
|
20
|
+
CHOICES = (
|
|
21
|
+
(JOB_RESULT, "Job results"),
|
|
22
|
+
(OBJECT_CHANGE, "Change logs"),
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class LogsCleanup(Job):
|
|
27
|
+
"""
|
|
28
|
+
System job to clean up ObjectChange and/or JobResult (and JobLogEntry) records older than a given age.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
cleanup_types = MultiChoiceVar(
|
|
32
|
+
choices=CleanupTypes.CHOICES,
|
|
33
|
+
required=True,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
max_age = IntegerVar(
|
|
37
|
+
description=(
|
|
38
|
+
"Maximum age of records to retain, in days. "
|
|
39
|
+
"Leave empty to use the CHANGELOG_RETENTION setting as the maximum."
|
|
40
|
+
),
|
|
41
|
+
label="Max Age",
|
|
42
|
+
min_value=0,
|
|
43
|
+
required=False,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
class Meta:
|
|
47
|
+
name = "Logs Cleanup"
|
|
48
|
+
description = "Delete ObjectChange and/or JobResult/JobLogEntry records older than a specified cutoff."
|
|
49
|
+
has_sensitive_variables = False
|
|
50
|
+
|
|
51
|
+
def run(self, *, cleanup_types, max_age=None):
|
|
52
|
+
if max_age in (None, ""):
|
|
53
|
+
max_age = get_settings_or_config("CHANGELOG_RETENTION")
|
|
54
|
+
if max_age == 0:
|
|
55
|
+
self.logger.warning(
|
|
56
|
+
"CHANGELOG_RETENTION setting is set to zero, disabling this Job. "
|
|
57
|
+
"If you wish to use this Job to delete records, you must specify a `max_age` value."
|
|
58
|
+
)
|
|
59
|
+
return 0
|
|
60
|
+
|
|
61
|
+
if CleanupTypes.JOB_RESULT in cleanup_types and not self.user.has_perm("extras.delete_jobresult"):
|
|
62
|
+
self.logger.error('User "%s" does not have permission to delete JobResult records', self.user)
|
|
63
|
+
raise PermissionDenied("User does not have delete permissions for JobResult records")
|
|
64
|
+
|
|
65
|
+
if CleanupTypes.OBJECT_CHANGE in cleanup_types and not self.user.has_perm("extras.delete_objectchange"):
|
|
66
|
+
self.logger.error('User "%s" does not have permission to delete ObjectChange records', self.user)
|
|
67
|
+
raise PermissionDenied("User does not have delete permissions for ObjectChange records")
|
|
68
|
+
|
|
69
|
+
# Bulk delete goes much faster if Django doesn't have signals to process.
|
|
70
|
+
# Temporarily detach the ones we *know* to be irrelevant.
|
|
71
|
+
self.logger.debug("Temporarily disconnecting some signals for performance")
|
|
72
|
+
pre_delete.disconnect(_handle_deleted_object)
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
cutoff = timezone.now() - timedelta(days=max_age)
|
|
76
|
+
result = {}
|
|
77
|
+
|
|
78
|
+
if CleanupTypes.JOB_RESULT in cleanup_types:
|
|
79
|
+
self.logger.info("Deleting JobResult records prior to %s", cutoff)
|
|
80
|
+
_, deleted_dict = JobResult.objects.restrict(self.user, "delete").filter(date_done__lt=cutoff).delete()
|
|
81
|
+
result.setdefault("extras.JobResult", 0)
|
|
82
|
+
result.setdefault("extras.JobLogEntry", 0)
|
|
83
|
+
result.update(**deleted_dict)
|
|
84
|
+
self.logger.info(
|
|
85
|
+
"Deleted %d JobResult records and their associated %d JobLogEntry records",
|
|
86
|
+
result["extras.JobResult"],
|
|
87
|
+
result["extras.JobLogEntry"],
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if CleanupTypes.OBJECT_CHANGE in cleanup_types:
|
|
91
|
+
self.logger.info("Deleting ObjectChange records prior to %s", cutoff)
|
|
92
|
+
deleted_count, _ = ObjectChange.objects.restrict(self.user, "delete").filter(time__lt=cutoff).delete()
|
|
93
|
+
self.logger.info("Deleted %d ObjectChange records", deleted_count)
|
|
94
|
+
result["extras.ObjectChange"] = deleted_count
|
|
95
|
+
|
|
96
|
+
return result
|
|
97
|
+
finally:
|
|
98
|
+
# Be sure to clean up after ourselves!
|
|
99
|
+
self.logger.debug("Re-connecting signals")
|
|
100
|
+
pre_delete.connect(_handle_deleted_object)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from nautobot.extras.choices import DynamicGroupTypeChoices
|
|
2
|
+
from nautobot.extras.jobs import Job, ObjectVar
|
|
3
|
+
from nautobot.extras.models import DynamicGroup
|
|
4
|
+
|
|
5
|
+
name = "System Jobs"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RefreshDynamicGroupCaches(Job):
|
|
9
|
+
"""
|
|
10
|
+
System job to recalculate and re-cache the members of Dynamic Groups for improved performance.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
single_group = ObjectVar(
|
|
14
|
+
description="Select to refresh only a single specified group instead of all groups",
|
|
15
|
+
model=DynamicGroup,
|
|
16
|
+
query_params={
|
|
17
|
+
"group_type": [DynamicGroupTypeChoices.TYPE_DYNAMIC_FILTER, DynamicGroupTypeChoices.TYPE_DYNAMIC_SET],
|
|
18
|
+
},
|
|
19
|
+
required=False,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
class Meta:
|
|
23
|
+
name = "Refresh Dynamic Group Caches"
|
|
24
|
+
description = "Re-calculate and re-cache the membership lists of Dynamic Groups."
|
|
25
|
+
has_sensitive_variables = False
|
|
26
|
+
|
|
27
|
+
def run(self, single_group=None):
|
|
28
|
+
groups = DynamicGroup.objects.restrict(self.user, "view").exclude(
|
|
29
|
+
group_type=DynamicGroupTypeChoices.TYPE_STATIC
|
|
30
|
+
)
|
|
31
|
+
if single_group is not None:
|
|
32
|
+
groups = groups.filter(pk=single_group.pk)
|
|
33
|
+
|
|
34
|
+
for group in groups:
|
|
35
|
+
group.update_cached_members()
|
|
36
|
+
self.logger.info("Cache refreshed successfully, now with %d members", group.count, extra={"object": group})
|
|
37
|
+
|
|
38
|
+
self.logger.info("Cache(s) refreshed")
|