nautobot 2.2.9__py3-none-any.whl → 2.3.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/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 +113 -0
- nautobot/cloud/filters.py +187 -0
- nautobot/cloud/forms.py +339 -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 +246 -0
- nautobot/cloud/navigation.py +85 -0
- nautobot/cloud/tables.py +157 -0
- nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +43 -0
- nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +122 -0
- nautobot/cloud/templates/cloud/cloudnetwork_update.html +33 -0
- nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +111 -0
- nautobot/cloud/templates/cloud/cloudservice_retrieve.html +69 -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 +125 -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 +95 -13
- nautobot/core/forms/fields.py +10 -4
- nautobot/core/forms/forms.py +11 -3
- nautobot/core/forms/widgets.py +18 -1
- nautobot/core/graphql/schema.py +26 -4
- nautobot/core/jobs/__init__.py +16 -2
- 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 +2 -17
- nautobot/core/settings.yaml +34 -13
- nautobot/core/settings_funcs.py +103 -0
- nautobot/core/tables.py +130 -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 -8
- 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 +63 -14
- 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_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 +122 -0
- 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 +119 -67
- nautobot/core/views/mixins.py +105 -36
- nautobot/core/views/paginator.py +9 -3
- nautobot/core/views/renderers.py +121 -56
- nautobot/core/views/utils.py +81 -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 +252 -18
- nautobot/dcim/filters/__init__.py +373 -193
- nautobot/dcim/filters/mixins.py +274 -1
- nautobot/dcim/forms.py +834 -121
- 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 +862 -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 -99
- nautobot/dcim/models/devices.py +468 -13
- nautobot/dcim/models/racks.py +0 -1
- nautobot/dcim/navigation.py +47 -0
- nautobot/dcim/signals.py +3 -3
- nautobot/dcim/tables/__init__.py +35 -23
- nautobot/dcim/tables/devices.py +229 -43
- 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 +14 -6
- 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/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 +159 -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 +693 -208
- nautobot/dcim/tests/test_filters.py +843 -217
- nautobot/dcim/tests/test_models.py +1072 -8
- nautobot/dcim/tests/test_views.py +1510 -341
- nautobot/dcim/urls.py +17 -2
- nautobot/dcim/utils.py +2 -3
- nautobot/dcim/views.py +1106 -116
- 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 +66 -0
- 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 +460 -9
- nautobot/extras/filters/__init__.py +174 -3
- nautobot/extras/filters/mixins.py +46 -43
- nautobot/extras/forms/base.py +24 -5
- 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 +14 -1
- 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 +6 -3
- nautobot/extras/models/metadata.py +441 -0
- nautobot/extras/models/mixins.py +72 -62
- nautobot/extras/models/models.py +118 -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 +95 -100
- nautobot/extras/tables.py +165 -12
- 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/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 +509 -23
- 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 +6 -6
- nautobot/extras/tests/test_models.py +501 -4
- nautobot/extras/tests/test_relationships.py +1 -0
- nautobot/extras/tests/test_views.py +565 -8
- nautobot/extras/tests/test_webhooks.py +1 -1
- nautobot/extras/urls.py +5 -0
- nautobot/extras/utils.py +51 -11
- nautobot/extras/views.py +542 -76
- nautobot/ipam/__init__.py +0 -1
- nautobot/ipam/apps.py +1 -0
- nautobot/ipam/factory.py +17 -19
- nautobot/ipam/filters.py +13 -0
- nautobot/ipam/forms.py +8 -4
- 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 +11 -8
- nautobot/ipam/querysets.py +1 -1
- nautobot/ipam/signals.py +4 -2
- nautobot/ipam/tables.py +5 -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 +6 -0
- 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 +18 -26
- nautobot/project-static/css/base.css +20 -0
- nautobot/project-static/css/dark.css +11 -0
- nautobot/project-static/docs/404.html +892 -88
- nautobot/project-static/docs/apps/index.html +892 -88
- nautobot/project-static/docs/apps/nautobot-apps.html +892 -88
- nautobot/project-static/docs/assets/_mkdocstrings.css +5 -0
- nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +919 -120
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +904 -101
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1618 -903
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +935 -144
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +977 -188
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +901 -99
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +897 -93
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +991 -193
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +974 -131
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +1078 -272
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1242 -334
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1727 -875
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +1164 -381
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2088 -1374
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2246 -1422
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +912 -111
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +963 -163
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1010 -223
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +1913 -1277
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1846 -1102
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +904 -101
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +2331 -1699
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +1802 -1024
- nautobot/project-static/docs/development/apps/api/configuration-view.html +892 -88
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +892 -88
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +892 -88
- nautobot/project-static/docs/development/apps/api/models/global-search.html +892 -88
- nautobot/project-static/docs/development/apps/api/models/graphql.html +892 -88
- nautobot/project-static/docs/development/apps/api/models/index.html +942 -90
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +892 -88
- nautobot/project-static/docs/development/apps/api/prometheus.html +892 -88
- nautobot/project-static/docs/development/apps/api/setup.html +892 -88
- nautobot/project-static/docs/development/apps/api/testing.html +892 -88
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +892 -88
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +892 -88
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +892 -88
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +892 -88
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/base-template.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/index.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/notes.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/urls.html +892 -88
- nautobot/project-static/docs/development/apps/index.html +892 -88
- nautobot/project-static/docs/development/apps/migration/code-updates.html +892 -88
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +892 -88
- nautobot/project-static/docs/development/apps/migration/from-v1.html +892 -88
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +892 -88
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +892 -88
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +892 -88
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +892 -88
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +892 -88
- nautobot/project-static/docs/development/core/application-registry.html +892 -88
- nautobot/project-static/docs/development/core/best-practices.html +893 -88
- nautobot/project-static/docs/development/core/bootstrap-ui.html +892 -88
- nautobot/project-static/docs/development/core/caching.html +892 -88
- nautobot/project-static/docs/development/core/controllers.html +892 -88
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +892 -88
- nautobot/project-static/docs/development/core/generic-views.html +892 -88
- nautobot/project-static/docs/development/core/getting-started.html +892 -88
- nautobot/project-static/docs/development/core/homepage.html +892 -88
- nautobot/project-static/docs/development/core/index.html +892 -88
- nautobot/project-static/docs/development/core/model-checklist.html +901 -89
- nautobot/project-static/docs/development/core/model-features.html +892 -88
- nautobot/project-static/docs/development/core/natural-keys.html +892 -88
- nautobot/project-static/docs/development/core/navigation-menu.html +892 -88
- nautobot/project-static/docs/development/core/release-checklist.html +895 -91
- nautobot/project-static/docs/development/core/role-internals.html +892 -88
- nautobot/project-static/docs/development/core/settings.html +892 -88
- nautobot/project-static/docs/development/core/style-guide.html +893 -89
- nautobot/project-static/docs/development/core/templates.html +904 -89
- nautobot/project-static/docs/development/core/testing.html +892 -88
- nautobot/project-static/docs/development/core/user-preferences.html +892 -88
- nautobot/project-static/docs/development/index.html +892 -88
- nautobot/project-static/docs/development/jobs/index.html +893 -89
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +892 -88
- nautobot/project-static/docs/index.html +892 -88
- 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 +900 -89
- nautobot/project-static/docs/overview/design_philosophy.html +892 -88
- nautobot/project-static/docs/release-notes/index.html +1129 -92
- nautobot/project-static/docs/release-notes/version-1.0.html +892 -88
- nautobot/project-static/docs/release-notes/version-1.1.html +892 -88
- nautobot/project-static/docs/release-notes/version-1.2.html +892 -88
- nautobot/project-static/docs/release-notes/version-1.3.html +892 -88
- nautobot/project-static/docs/release-notes/version-1.4.html +892 -88
- nautobot/project-static/docs/release-notes/version-1.5.html +893 -89
- nautobot/project-static/docs/release-notes/version-1.6.html +893 -89
- nautobot/project-static/docs/release-notes/version-2.0.html +892 -88
- nautobot/project-static/docs/release-notes/version-2.1.html +892 -88
- nautobot/project-static/docs/release-notes/version-2.2.html +895 -91
- nautobot/project-static/docs/release-notes/version-2.3.html +9954 -0
- nautobot/project-static/docs/requirements.txt +5 -5
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +331 -256
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +892 -88
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +892 -88
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +892 -88
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +892 -88
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +992 -174
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +892 -88
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +896 -88
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +892 -88
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +892 -88
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +892 -88
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +944 -153
- nautobot/project-static/docs/user-guide/administration/installation/index.html +901 -93
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +934 -122
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +954 -157
- nautobot/project-static/docs/user-guide/administration/installation/services.html +913 -112
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +908 -99
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +892 -88
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +892 -88
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +892 -88
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +892 -88
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +893 -89
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +893 -89
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +896 -88
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +895 -91
- 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 +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +923 -105
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +923 -105
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +918 -100
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +923 -105
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +913 -105
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +920 -116
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +921 -117
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +918 -114
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +914 -105
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +926 -108
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +936 -118
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +928 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +937 -119
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +928 -110
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +918 -114
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +921 -117
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +923 -115
- 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 +916 -112
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +940 -83
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +924 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +943 -86
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +921 -103
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +929 -125
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +918 -114
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +922 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +924 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +936 -88
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +897 -89
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +897 -89
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +901 -96
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +897 -89
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +892 -88
- 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 +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +892 -88
- nautobot/project-static/docs/user-guide/index.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +1258 -785
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +895 -91
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +896 -88
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +895 -91
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +9061 -0
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +895 -91
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +895 -91
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +9137 -0
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +895 -91
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +8933 -0
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +950 -121
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +892 -88
- 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 +24 -20
- 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/models.py +0 -2
- nautobot/virtualization/tables.py +10 -3
- 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.0.dist-info}/METADATA +20 -18
- {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/RECORD +677 -557
- nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css.map +0 -1
- 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.0.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/NOTICE +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/WHEEL +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0.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
|
|
@@ -125,8 +124,8 @@ class MultiValueUUIDFilter(django_filters.UUIDFilter, django_filters.MultipleCho
|
|
|
125
124
|
|
|
126
125
|
class RelatedMembershipBooleanFilter(django_filters.BooleanFilter):
|
|
127
126
|
"""
|
|
128
|
-
BooleanFilter for related objects that will explicitly perform `
|
|
129
|
-
|
|
127
|
+
BooleanFilter for related objects that will explicitly perform `isnull` lookups.
|
|
128
|
+
The `field_name` argument is required and must be set to the related field on the
|
|
130
129
|
model.
|
|
131
130
|
|
|
132
131
|
This should be used instead of a default `BooleanFilter` paired `method=`
|
|
@@ -134,15 +133,33 @@ class RelatedMembershipBooleanFilter(django_filters.BooleanFilter):
|
|
|
134
133
|
|
|
135
134
|
Example:
|
|
136
135
|
|
|
137
|
-
|
|
138
|
-
field_name="
|
|
139
|
-
label="Has
|
|
136
|
+
has_modules = RelatedMembershipBooleanFilter(
|
|
137
|
+
field_name="module_bays__installed_module",
|
|
138
|
+
label="Has modules",
|
|
140
139
|
)
|
|
140
|
+
|
|
141
|
+
This would generate a filter that returns instances that have at least one module
|
|
142
|
+
bay with an installed module. The `has_modules=False` filter would exclude instances
|
|
143
|
+
with at least one module bay with an installed module.
|
|
144
|
+
|
|
145
|
+
Set `exclude=True` to reverse the behavior of the filter. This __may__ be useful
|
|
146
|
+
for filtering on null directly related fields but this filter is not smart enough
|
|
147
|
+
to differentiate between `fieldA__fieldB__isnull` and `fieldA__isnull` so it's not
|
|
148
|
+
suitable for cases like the `has_empty_module_bays` filter where an instance may
|
|
149
|
+
not have any module bays.
|
|
150
|
+
|
|
151
|
+
See the below table for more information:
|
|
152
|
+
|
|
153
|
+
| value | exclude | Result
|
|
154
|
+
|-------------|------------------|-------
|
|
155
|
+
| True | False (default) | Return instances with at least one non-null match -- qs.filter(field_name__isnull=False)
|
|
156
|
+
| False | False (default) | Exclude instances with at least one non-null match -- qs.exclude(field_name__isnull=False)
|
|
157
|
+
| True | True | Return instances with at least one null match -- qs.filter(field_name__isnull=True)
|
|
158
|
+
| False | True | Exclude instances with at least one null match -- qs.exclude(field_name__isnull=True)
|
|
159
|
+
|
|
141
160
|
"""
|
|
142
161
|
|
|
143
|
-
def __init__(
|
|
144
|
-
self, field_name=None, lookup_expr="isnull", *, label=None, method=None, distinct=False, exclude=True, **kwargs
|
|
145
|
-
):
|
|
162
|
+
def __init__(self, field_name=None, lookup_expr="isnull", *, label=None, method=None, distinct=True, **kwargs):
|
|
146
163
|
if field_name is None:
|
|
147
164
|
raise ValueError(f"Field name is required for {self.__class__.__name__}")
|
|
148
165
|
|
|
@@ -152,11 +169,23 @@ class RelatedMembershipBooleanFilter(django_filters.BooleanFilter):
|
|
|
152
169
|
label=label,
|
|
153
170
|
method=method,
|
|
154
171
|
distinct=distinct,
|
|
155
|
-
exclude=exclude,
|
|
156
172
|
widget=forms.StaticSelect2(choices=forms.BOOLEAN_CHOICES),
|
|
157
173
|
**kwargs,
|
|
158
174
|
)
|
|
159
175
|
|
|
176
|
+
def filter(self, qs, value):
|
|
177
|
+
if value in EMPTY_VALUES:
|
|
178
|
+
return qs
|
|
179
|
+
if self.distinct:
|
|
180
|
+
qs = qs.distinct()
|
|
181
|
+
lookup = f"{self.field_name}__{self.lookup_expr}"
|
|
182
|
+
if bool(value):
|
|
183
|
+
# if self.exclude=False, return instances with field populated
|
|
184
|
+
return qs.filter(**{lookup: self.exclude})
|
|
185
|
+
else:
|
|
186
|
+
# if self.exclude=False, exclude instances with field populated
|
|
187
|
+
return qs.exclude(**{lookup: self.exclude})
|
|
188
|
+
|
|
160
189
|
|
|
161
190
|
class NumericArrayFilter(django_filters.NumberFilter):
|
|
162
191
|
"""
|
|
@@ -403,12 +432,22 @@ class NaturalKeyOrPKMultipleChoiceFilter(django_filters.ModelMultipleChoiceFilte
|
|
|
403
432
|
Filter that supports filtering on values matching the `pk` field and another
|
|
404
433
|
field of a foreign-key related object. The desired field is set using the `to_field_name`
|
|
405
434
|
keyword argument on filter initialization (defaults to `name`).
|
|
435
|
+
|
|
436
|
+
NOTE that the `to_field_name` field does not have to be a "true" natural key (ie. unique), it
|
|
437
|
+
was just the best name we could come up with for this filter
|
|
438
|
+
|
|
406
439
|
"""
|
|
407
440
|
|
|
408
441
|
field_class = forms.MultiMatchModelMultipleChoiceField
|
|
409
442
|
|
|
410
|
-
def __init__(self, *args, **kwargs):
|
|
443
|
+
def __init__(self, *args, prefers_id=False, **kwargs):
|
|
444
|
+
"""Initialize the NaturalKeyOrPKMultipleChoiceFilter.
|
|
445
|
+
|
|
446
|
+
Args:
|
|
447
|
+
prefers_id (bool, optional): Prefer PK (ID) over the 'to_field_name'. Defaults to False.
|
|
448
|
+
"""
|
|
411
449
|
self.natural_key = kwargs.setdefault("to_field_name", "name")
|
|
450
|
+
self.prefers_id = prefers_id
|
|
412
451
|
super().__init__(*args, **kwargs)
|
|
413
452
|
|
|
414
453
|
def get_filter_predicate(self, v):
|
|
@@ -725,8 +764,8 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
725
764
|
def get_fields(cls):
|
|
726
765
|
fields = super().get_fields()
|
|
727
766
|
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 =
|
|
767
|
+
# Add "id" as the first key in the `fields` dict
|
|
768
|
+
fields = {"id": [django_filters.conf.settings.DEFAULT_LOOKUP_EXPR], **fields}
|
|
730
769
|
return fields
|
|
731
770
|
|
|
732
771
|
@classmethod
|
|
@@ -741,8 +780,51 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
741
780
|
if filter_name.startswith("_"):
|
|
742
781
|
del filters[filter_name]
|
|
743
782
|
|
|
783
|
+
if getattr(cls._meta.model, "is_contact_associable_model", False):
|
|
784
|
+
# Add "contacts" and "teams" filters
|
|
785
|
+
from nautobot.extras.models import Contact, Team
|
|
786
|
+
|
|
787
|
+
if "contacts" not in filters:
|
|
788
|
+
filters["contacts"] = NaturalKeyOrPKMultipleChoiceFilter(
|
|
789
|
+
queryset=Contact.objects.all(),
|
|
790
|
+
field_name="associated_contacts__contact",
|
|
791
|
+
to_field_name="name",
|
|
792
|
+
label="Contacts (name or ID)",
|
|
793
|
+
)
|
|
794
|
+
|
|
795
|
+
if "teams" not in filters:
|
|
796
|
+
filters["teams"] = NaturalKeyOrPKMultipleChoiceFilter(
|
|
797
|
+
queryset=Team.objects.all(),
|
|
798
|
+
field_name="associated_contacts__team",
|
|
799
|
+
to_field_name="name",
|
|
800
|
+
label="Teams (name or ID)",
|
|
801
|
+
)
|
|
802
|
+
|
|
803
|
+
if "dynamic_groups" not in filters and getattr(cls._meta.model, "is_dynamic_group_associable_model", False):
|
|
804
|
+
if not hasattr(cls._meta.model, "static_group_association_set"):
|
|
805
|
+
logger.warning(
|
|
806
|
+
"Model %s has 'is_dynamic_group_associable_model = True' but lacks "
|
|
807
|
+
"a 'static_group_association_set' attribute. Perhaps this is due to it inheriting from "
|
|
808
|
+
"the deprecated DynamicGroupMixin class instead of the preferred DynamicGroupsModelMixin?",
|
|
809
|
+
cls._meta.model,
|
|
810
|
+
)
|
|
811
|
+
else:
|
|
812
|
+
# Add "dynamic_groups" field as the last key
|
|
813
|
+
from nautobot.extras.models import DynamicGroup
|
|
814
|
+
|
|
815
|
+
filters["dynamic_groups"] = NaturalKeyOrPKMultipleChoiceFilter(
|
|
816
|
+
queryset=DynamicGroup.objects.all(),
|
|
817
|
+
field_name="static_group_association_set__dynamic_group",
|
|
818
|
+
to_field_name="name",
|
|
819
|
+
query_params={"content_type": cls._meta.model._meta.label_lower},
|
|
820
|
+
label="Dynamic groups (name or ID)",
|
|
821
|
+
)
|
|
822
|
+
|
|
744
823
|
# django-filters has no concept of "abstract" filtersets, so we have to fake it
|
|
745
824
|
if cls._meta.model is not None:
|
|
825
|
+
if "tags" in filters and isinstance(filters["tags"], TagFilter):
|
|
826
|
+
filters["tags"].extra["query_params"] = {"content_types": [cls._meta.model._meta.label_lower]}
|
|
827
|
+
|
|
746
828
|
new_filters = {}
|
|
747
829
|
for existing_filter_name, existing_filter in filters.items():
|
|
748
830
|
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
|
@@ -59,6 +59,13 @@ class AddressFieldMixin(forms.ModelForm):
|
|
|
59
59
|
class BootstrapMixin(forms.BaseForm):
|
|
60
60
|
"""
|
|
61
61
|
Add the base Bootstrap CSS classes to form elements.
|
|
62
|
+
|
|
63
|
+
Note that this only applies to form fields that are:
|
|
64
|
+
|
|
65
|
+
1. statically defined on the form class at declaration time, or
|
|
66
|
+
2. dynamically added to the form at init time by a class **later in the MRO than this mixin**.
|
|
67
|
+
|
|
68
|
+
If a class earlier in the MRO adds its own fields, it will have to ensure that the widgets are correctly configured.
|
|
62
69
|
"""
|
|
63
70
|
|
|
64
71
|
def __init__(self, *args, **kwargs):
|
|
@@ -73,8 +80,9 @@ class BootstrapMixin(forms.BaseForm):
|
|
|
73
80
|
|
|
74
81
|
for field in self.fields.values():
|
|
75
82
|
if field.widget.__class__ not in exempt_widgets:
|
|
76
|
-
|
|
77
|
-
|
|
83
|
+
css_classes = field.widget.attrs.get("class", "")
|
|
84
|
+
if "form-control" not in css_classes:
|
|
85
|
+
field.widget.attrs["class"] = " ".join([css_classes, "form-control"]).strip()
|
|
78
86
|
if field.required and not isinstance(field.widget, forms.FileInput):
|
|
79
87
|
field.widget.attrs["required"] = "required"
|
|
80
88
|
if "placeholder" not in field.widget.attrs:
|
|
@@ -121,7 +129,7 @@ class BulkRenameForm(forms.Form):
|
|
|
121
129
|
"""
|
|
122
130
|
|
|
123
131
|
find = forms.CharField()
|
|
124
|
-
replace = forms.CharField()
|
|
132
|
+
replace = forms.CharField(required=False, strip=False)
|
|
125
133
|
use_regex = forms.BooleanField(required=False, initial=True, label="Use regular expressions")
|
|
126
134
|
|
|
127
135
|
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)
|
nautobot/core/graphql/schema.py
CHANGED
|
@@ -4,6 +4,7 @@ from collections import OrderedDict
|
|
|
4
4
|
import logging
|
|
5
5
|
|
|
6
6
|
from django.conf import settings
|
|
7
|
+
from django.contrib.contenttypes.fields import GenericRelation
|
|
7
8
|
from django.contrib.contenttypes.models import ContentType
|
|
8
9
|
from django.core.validators import ValidationError
|
|
9
10
|
from django.db.models import ManyToManyField
|
|
@@ -42,7 +43,7 @@ from nautobot.dcim.graphql.types import (
|
|
|
42
43
|
RearPortType,
|
|
43
44
|
)
|
|
44
45
|
from nautobot.extras.choices import CustomFieldTypeChoices, RelationshipSideChoices
|
|
45
|
-
from nautobot.extras.graphql.types import DynamicGroupType, TagType
|
|
46
|
+
from nautobot.extras.graphql.types import ContactAssociationType, DynamicGroupType, TagType
|
|
46
47
|
from nautobot.extras.models import ComputedField, CustomField, Relationship
|
|
47
48
|
from nautobot.extras.registry import registry
|
|
48
49
|
from nautobot.extras.utils import check_if_key_is_graphql_safe
|
|
@@ -68,8 +69,9 @@ registry["graphql_types"]["dcim.powerport"] = PowerPortType
|
|
|
68
69
|
registry["graphql_types"]["dcim.rack"] = RackType
|
|
69
70
|
registry["graphql_types"]["dcim.rearport"] = RearPortType
|
|
70
71
|
registry["graphql_types"]["dcim.location"] = LocationType
|
|
71
|
-
registry["graphql_types"]["extras.
|
|
72
|
+
registry["graphql_types"]["extras.contactassociation"] = ContactAssociationType
|
|
72
73
|
registry["graphql_types"]["extras.dynamicgroup"] = DynamicGroupType
|
|
74
|
+
registry["graphql_types"]["extras.tag"] = TagType
|
|
73
75
|
registry["graphql_types"]["ipam.ipaddress"] = IPAddressType
|
|
74
76
|
registry["graphql_types"]["ipam.prefix"] = PrefixType
|
|
75
77
|
registry["graphql_types"]["ipam.vlan"] = VLANType
|
|
@@ -127,6 +129,11 @@ def extend_schema_type(schema_type):
|
|
|
127
129
|
#
|
|
128
130
|
schema_type = extend_schema_type_config_context(schema_type, model)
|
|
129
131
|
|
|
132
|
+
#
|
|
133
|
+
# Global features (contacts, teams, dynamic groups)
|
|
134
|
+
#
|
|
135
|
+
schema_type = extend_schema_type_global_features(schema_type, model)
|
|
136
|
+
|
|
130
137
|
#
|
|
131
138
|
# Relationships
|
|
132
139
|
#
|
|
@@ -199,8 +206,7 @@ def extend_schema_type_filter(schema_type, model):
|
|
|
199
206
|
(DjangoObjectType): The extended schema_type object
|
|
200
207
|
"""
|
|
201
208
|
for field in model._meta.get_fields():
|
|
202
|
-
|
|
203
|
-
if not isinstance(field, (ManyToManyField, ManyToManyRel, ManyToOneRel)):
|
|
209
|
+
if not isinstance(field, (ManyToManyField, ManyToManyRel, ManyToOneRel, GenericRelation)):
|
|
204
210
|
continue
|
|
205
211
|
# OneToOneRel is a subclass of ManyToOneRel, but we don't want to treat it as a list
|
|
206
212
|
if isinstance(field, OneToOneRel):
|
|
@@ -366,6 +372,22 @@ 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 (dynamic groups, etc.).
|
|
378
|
+
"""
|
|
379
|
+
# associated_contacts and associated_object_metadata are handled elsewhere by extend_schema_type_filter()
|
|
380
|
+
if getattr(model, "is_dynamic_group_associable_model", False):
|
|
381
|
+
|
|
382
|
+
def resolve_dynamic_groups(self, args):
|
|
383
|
+
return self.dynamic_groups
|
|
384
|
+
|
|
385
|
+
setattr(schema_type, "resolve_dynamic_groups", resolve_dynamic_groups)
|
|
386
|
+
schema_type._meta.fields["dynamic_groups"] = graphene.Field.mounted(graphene.List(DynamicGroupType))
|
|
387
|
+
|
|
388
|
+
return schema_type
|
|
389
|
+
|
|
390
|
+
|
|
369
391
|
def extend_schema_type_relationships(schema_type, model):
|
|
370
392
|
"""Extend the schema type with attributes and resolvers corresponding
|
|
371
393
|
to the relationships associated with this model."""
|
nautobot/core/jobs/__init__.py
CHANGED
|
@@ -15,6 +15,8 @@ from nautobot.core.api.renderers import NautobotCSVRenderer
|
|
|
15
15
|
from nautobot.core.api.utils import get_serializer_for_model
|
|
16
16
|
from nautobot.core.celery import app, register_jobs
|
|
17
17
|
from nautobot.core.exceptions import AbortTransaction
|
|
18
|
+
from nautobot.core.jobs.cleanup import LogsCleanup
|
|
19
|
+
from nautobot.core.jobs.groups import RefreshDynamicGroupCaches
|
|
18
20
|
from nautobot.core.utils.lookup import get_filterset_for_model
|
|
19
21
|
from nautobot.core.utils.requests import get_filterable_params_from_filter_params
|
|
20
22
|
from nautobot.extras.datasources import ensure_git_repository, git_repository_dry_run, refresh_datasource_content
|
|
@@ -37,6 +39,7 @@ class GitRepositorySync(Job):
|
|
|
37
39
|
|
|
38
40
|
class Meta:
|
|
39
41
|
name = "Git Repository: Sync"
|
|
42
|
+
description = "Clone and/or pull a Git repository, then refresh data sourced from this repository."
|
|
40
43
|
has_sensitive_variables = False
|
|
41
44
|
|
|
42
45
|
def run(self, repository):
|
|
@@ -66,6 +69,7 @@ class GitRepositoryDryRun(Job):
|
|
|
66
69
|
|
|
67
70
|
class Meta:
|
|
68
71
|
name = "Git Repository: Dry-Run"
|
|
72
|
+
description = "Dry run of Git repository sync - will not update data sourced from this repository."
|
|
69
73
|
has_sensitive_variables = False
|
|
70
74
|
|
|
71
75
|
def run(self, repository):
|
|
@@ -112,6 +116,7 @@ class ExportObjectList(Job):
|
|
|
112
116
|
|
|
113
117
|
class Meta:
|
|
114
118
|
name = "Export Object List"
|
|
119
|
+
description = "Export a list of objects to CSV or YAML, or render a specified Export Template."
|
|
115
120
|
has_sensitive_variables = False
|
|
116
121
|
# Exporting large querysets may take substantial processing time
|
|
117
122
|
soft_time_limit = 1800
|
|
@@ -136,7 +141,15 @@ class ExportObjectList(Job):
|
|
|
136
141
|
# such that they never are even seen here.
|
|
137
142
|
query_params = QueryDict(query_string)
|
|
138
143
|
self.logger.debug("Parsed query_params: `%s`", query_params.dict())
|
|
139
|
-
default_non_filter_params = (
|
|
144
|
+
default_non_filter_params = (
|
|
145
|
+
"all_filters_removed",
|
|
146
|
+
"export",
|
|
147
|
+
"page",
|
|
148
|
+
"per_page",
|
|
149
|
+
"saved_view",
|
|
150
|
+
"sort",
|
|
151
|
+
"table_changes_pending",
|
|
152
|
+
)
|
|
140
153
|
filter_params = get_filterable_params_from_filter_params(
|
|
141
154
|
query_params, default_non_filter_params, filterset_class()
|
|
142
155
|
)
|
|
@@ -213,6 +226,7 @@ class ImportObjects(Job):
|
|
|
213
226
|
|
|
214
227
|
class Meta:
|
|
215
228
|
name = "Import Objects"
|
|
229
|
+
description = "Import objects from CSV-formatted data."
|
|
216
230
|
has_sensitive_variables = False
|
|
217
231
|
# Importing large files may take substantial processing time
|
|
218
232
|
soft_time_limit = 1800
|
|
@@ -317,5 +331,5 @@ class ImportObjects(Job):
|
|
|
317
331
|
raise RunJobTaskFailed("CSV import not fully successful, see logs")
|
|
318
332
|
|
|
319
333
|
|
|
320
|
-
jobs = [ExportObjectList, GitRepositorySync, GitRepositoryDryRun, ImportObjects]
|
|
334
|
+
jobs = [ExportObjectList, GitRepositorySync, GitRepositoryDryRun, ImportObjects, LogsCleanup, RefreshDynamicGroupCaches]
|
|
321
335
|
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")
|