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
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
|
|
1
3
|
from django.contrib.auth import get_user_model
|
|
2
4
|
from django.contrib.contenttypes.models import ContentType
|
|
3
5
|
from django.db.models import Q
|
|
@@ -20,6 +22,7 @@ from nautobot.dcim.choices import (
|
|
|
20
22
|
RackWidthChoices,
|
|
21
23
|
SubdeviceRoleChoices,
|
|
22
24
|
)
|
|
25
|
+
from nautobot.dcim.constants import NONCONNECTABLE_IFACE_TYPES, VIRTUAL_IFACE_TYPES
|
|
23
26
|
from nautobot.dcim.filters import (
|
|
24
27
|
CableFilterSet,
|
|
25
28
|
ConsolePortFilterSet,
|
|
@@ -45,6 +48,10 @@ from nautobot.dcim.filters import (
|
|
|
45
48
|
LocationFilterSet,
|
|
46
49
|
LocationTypeFilterSet,
|
|
47
50
|
ManufacturerFilterSet,
|
|
51
|
+
ModuleBayFilterSet,
|
|
52
|
+
ModuleBayTemplateFilterSet,
|
|
53
|
+
ModuleFilterSet,
|
|
54
|
+
ModuleTypeFilterSet,
|
|
48
55
|
PlatformFilterSet,
|
|
49
56
|
PowerFeedFilterSet,
|
|
50
57
|
PowerOutletFilterSet,
|
|
@@ -86,6 +93,10 @@ from nautobot.dcim.models import (
|
|
|
86
93
|
Location,
|
|
87
94
|
LocationType,
|
|
88
95
|
Manufacturer,
|
|
96
|
+
Module,
|
|
97
|
+
ModuleBay,
|
|
98
|
+
ModuleBayTemplate,
|
|
99
|
+
ModuleType,
|
|
89
100
|
Platform,
|
|
90
101
|
PowerFeed,
|
|
91
102
|
PowerOutlet,
|
|
@@ -457,7 +468,7 @@ def common_test_data(cls):
|
|
|
457
468
|
)
|
|
458
469
|
|
|
459
470
|
InterfaceTemplate.objects.create(
|
|
460
|
-
name="Interface 1",
|
|
471
|
+
name="Test Interface 1",
|
|
461
472
|
description="Interface Description 1",
|
|
462
473
|
device_type=device_types[0],
|
|
463
474
|
label="interface1",
|
|
@@ -465,7 +476,7 @@ def common_test_data(cls):
|
|
|
465
476
|
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
466
477
|
)
|
|
467
478
|
InterfaceTemplate.objects.create(
|
|
468
|
-
name="Interface 2",
|
|
479
|
+
name="Test Interface 2",
|
|
469
480
|
description="Interface Description 2",
|
|
470
481
|
device_type=device_types[1],
|
|
471
482
|
label="interface2",
|
|
@@ -473,7 +484,7 @@ def common_test_data(cls):
|
|
|
473
484
|
type=InterfaceTypeChoices.TYPE_1GE_GBIC,
|
|
474
485
|
)
|
|
475
486
|
InterfaceTemplate.objects.create(
|
|
476
|
-
name="Interface 3",
|
|
487
|
+
name="Test Interface 3",
|
|
477
488
|
description="Interface Description 3",
|
|
478
489
|
device_type=device_types[2],
|
|
479
490
|
label="interface3",
|
|
@@ -554,7 +565,27 @@ def common_test_data(cls):
|
|
|
554
565
|
label="devicebay3",
|
|
555
566
|
description="Device Bay Description 3",
|
|
556
567
|
)
|
|
557
|
-
|
|
568
|
+
ModuleBayTemplate.objects.create(
|
|
569
|
+
device_type=device_types[0],
|
|
570
|
+
name="device test module bay 1",
|
|
571
|
+
position=1,
|
|
572
|
+
label="devicemodulebay1",
|
|
573
|
+
description="device test module bay 1 description",
|
|
574
|
+
)
|
|
575
|
+
ModuleBayTemplate.objects.create(
|
|
576
|
+
device_type=device_types[1],
|
|
577
|
+
name="device test module bay 2",
|
|
578
|
+
position=2,
|
|
579
|
+
label="devicemodulebay2",
|
|
580
|
+
description="device test module bay 2 description",
|
|
581
|
+
)
|
|
582
|
+
ModuleBayTemplate.objects.create(
|
|
583
|
+
device_type=device_types[2],
|
|
584
|
+
name="device test module bay 3",
|
|
585
|
+
position=3,
|
|
586
|
+
label="devicemodulebay3",
|
|
587
|
+
description="device test module bay 3 description",
|
|
588
|
+
)
|
|
558
589
|
secrets_groups = (
|
|
559
590
|
SecretsGroup.objects.create(name="Secrets group 1"),
|
|
560
591
|
SecretsGroup.objects.create(name="Secrets group 2"),
|
|
@@ -624,6 +655,115 @@ def common_test_data(cls):
|
|
|
624
655
|
external_integrations = iter(ExternalIntegration.objects.all())
|
|
625
656
|
device_redundancy_groups = iter(DeviceRedundancyGroup.objects.all())
|
|
626
657
|
|
|
658
|
+
module_types = (
|
|
659
|
+
ModuleType.objects.create(manufacturer=cls.manufacturers[0], model="Filter Test Module Type 1"),
|
|
660
|
+
ModuleType.objects.create(manufacturer=cls.manufacturers[1], model="Filter Test Module Type 2"),
|
|
661
|
+
ModuleType.objects.create(manufacturer=cls.manufacturers[2], model="Filter Test Module Type 3"),
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
# Create 3 of each component template on the first two module types
|
|
665
|
+
for i in range(6):
|
|
666
|
+
ConsolePortTemplate.objects.create(
|
|
667
|
+
name=f"Test Filters Module Console Port {i+1}",
|
|
668
|
+
module_type=module_types[i % 2],
|
|
669
|
+
)
|
|
670
|
+
ConsoleServerPortTemplate.objects.create(
|
|
671
|
+
name=f"Test Filters Module Console Server Port {i+1}",
|
|
672
|
+
module_type=module_types[i % 2],
|
|
673
|
+
)
|
|
674
|
+
ppt = PowerPortTemplate.objects.create(
|
|
675
|
+
name=f"Test Filters Module Power Port {i+1}",
|
|
676
|
+
module_type=module_types[i % 2],
|
|
677
|
+
)
|
|
678
|
+
PowerOutletTemplate.objects.create(
|
|
679
|
+
name=f"Test Filters Module Power Outlet {i+1}",
|
|
680
|
+
power_port_template=ppt,
|
|
681
|
+
module_type=module_types[i % 2],
|
|
682
|
+
)
|
|
683
|
+
InterfaceTemplate.objects.create(
|
|
684
|
+
name=f"Test Filters Module Interface {i+1}",
|
|
685
|
+
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
686
|
+
module_type=module_types[i % 2],
|
|
687
|
+
)
|
|
688
|
+
rpt = RearPortTemplate.objects.create(
|
|
689
|
+
name=f"Test Filters Module Rear Port {i+1}",
|
|
690
|
+
module_type=module_types[i % 2],
|
|
691
|
+
type=PortTypeChoices.TYPE_8P8C,
|
|
692
|
+
positions=10,
|
|
693
|
+
)
|
|
694
|
+
FrontPortTemplate.objects.create(
|
|
695
|
+
name=f"Test Filters Module Front Port {i+1}",
|
|
696
|
+
module_type=module_types[i % 2],
|
|
697
|
+
rear_port_template=rpt,
|
|
698
|
+
rear_port_position=i + 1,
|
|
699
|
+
type=PortTypeChoices.TYPE_8P8C,
|
|
700
|
+
)
|
|
701
|
+
ModuleBayTemplate.objects.create(
|
|
702
|
+
name=f"Test Filters Module Module Bay {i+1}",
|
|
703
|
+
position=i + 1,
|
|
704
|
+
module_type=module_types[i % 2],
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
module_roles = Role.objects.get_for_model(Module)
|
|
708
|
+
cls.module_statuses = Status.objects.get_for_model(Module)
|
|
709
|
+
cls.modules = (
|
|
710
|
+
Module.objects.create(
|
|
711
|
+
module_type=module_types[0],
|
|
712
|
+
status=cls.module_statuses[0],
|
|
713
|
+
asset_tag="Test Filter Asset Tag Module1",
|
|
714
|
+
serial="Test Filter Serial Module1",
|
|
715
|
+
role=module_roles[0],
|
|
716
|
+
tenant=tenants[0],
|
|
717
|
+
parent_module_bay=cls.devices[0].module_bays.first(),
|
|
718
|
+
),
|
|
719
|
+
Module.objects.create(
|
|
720
|
+
module_type=module_types[1],
|
|
721
|
+
status=cls.module_statuses[0],
|
|
722
|
+
asset_tag="Test Filter Asset Tag Module2",
|
|
723
|
+
serial="Test Filter Serial Module2",
|
|
724
|
+
role=module_roles[0],
|
|
725
|
+
tenant=tenants[1],
|
|
726
|
+
parent_module_bay=cls.devices[1].module_bays.first(),
|
|
727
|
+
),
|
|
728
|
+
Module.objects.create(
|
|
729
|
+
module_type=module_types[2],
|
|
730
|
+
status=cls.module_statuses[0],
|
|
731
|
+
asset_tag="Test Filter Asset Tag Module3",
|
|
732
|
+
serial="Test Filter Serial Module3",
|
|
733
|
+
role=module_roles[1],
|
|
734
|
+
tenant=tenants[2],
|
|
735
|
+
parent_module_bay=cls.devices[2].module_bays.first(),
|
|
736
|
+
),
|
|
737
|
+
)
|
|
738
|
+
cls.modules[0].tags.set(Tag.objects.get_for_model(Module))
|
|
739
|
+
cls.modules[1].tags.set(Tag.objects.get_for_model(Module)[:3])
|
|
740
|
+
|
|
741
|
+
Module.objects.create(
|
|
742
|
+
module_type=module_types[0],
|
|
743
|
+
status=cls.module_statuses[1],
|
|
744
|
+
asset_tag="Test Filter Asset Tag Module4",
|
|
745
|
+
serial="Test Filter Serial Module4",
|
|
746
|
+
role=module_roles[1],
|
|
747
|
+
tenant=tenants[0],
|
|
748
|
+
parent_module_bay=cls.modules[0].module_bays.first(),
|
|
749
|
+
)
|
|
750
|
+
Module.objects.create(
|
|
751
|
+
module_type=module_types[1],
|
|
752
|
+
status=cls.module_statuses[1],
|
|
753
|
+
asset_tag="Test Filter Asset Tag Module5",
|
|
754
|
+
serial="Test Filter Serial Module5",
|
|
755
|
+
tenant=tenants[1],
|
|
756
|
+
parent_module_bay=cls.modules[1].module_bays.first(),
|
|
757
|
+
)
|
|
758
|
+
Module.objects.create(
|
|
759
|
+
module_type=module_types[2],
|
|
760
|
+
status=cls.module_statuses[1],
|
|
761
|
+
asset_tag="Test Filter Asset Tag Module6",
|
|
762
|
+
serial="Test Filter Serial Module6",
|
|
763
|
+
tenant=tenants[2],
|
|
764
|
+
parent_module_bay=cls.modules[1].module_bays.last(),
|
|
765
|
+
)
|
|
766
|
+
|
|
627
767
|
cls.controllers = (
|
|
628
768
|
Controller.objects.create(
|
|
629
769
|
name="Controller 1",
|
|
@@ -697,6 +837,157 @@ def common_test_data(cls):
|
|
|
697
837
|
cls.controller_managed_device_groups[1].tags.set(Tag.objects.get_for_model(ControllerManagedDeviceGroup)[:3])
|
|
698
838
|
|
|
699
839
|
|
|
840
|
+
class ComponentTemplateTestMixin:
|
|
841
|
+
generic_filter_tests = [
|
|
842
|
+
("description",),
|
|
843
|
+
("device_type", "device_type__id"),
|
|
844
|
+
("device_type", "device_type__model"),
|
|
845
|
+
("label",),
|
|
846
|
+
("name",),
|
|
847
|
+
]
|
|
848
|
+
|
|
849
|
+
@classmethod
|
|
850
|
+
def setUpTestData(cls):
|
|
851
|
+
common_test_data(cls)
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
class ModularComponentTemplateTestMixin(ComponentTemplateTestMixin):
|
|
855
|
+
generic_filter_tests = [
|
|
856
|
+
*ComponentTemplateTestMixin.generic_filter_tests,
|
|
857
|
+
("module_type", "module_type__id"),
|
|
858
|
+
("module_type", "module_type__model"),
|
|
859
|
+
]
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
class DeviceComponentTestMixin:
|
|
863
|
+
generic_filter_tests = [
|
|
864
|
+
("description",),
|
|
865
|
+
("device", "device__id"),
|
|
866
|
+
("device", "device__name"),
|
|
867
|
+
("label",),
|
|
868
|
+
("name",),
|
|
869
|
+
]
|
|
870
|
+
|
|
871
|
+
@classmethod
|
|
872
|
+
def setUpTestData(cls):
|
|
873
|
+
common_test_data(cls)
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
class ModularDeviceComponentTestMixin(DeviceComponentTestMixin):
|
|
877
|
+
generic_filter_tests = [
|
|
878
|
+
("description",),
|
|
879
|
+
("label",),
|
|
880
|
+
("name",),
|
|
881
|
+
("module", "module__id"),
|
|
882
|
+
("module", "module__module_type__model"),
|
|
883
|
+
]
|
|
884
|
+
|
|
885
|
+
def test_device(self):
|
|
886
|
+
"""Test that the device filter returns all components for a device and its modules."""
|
|
887
|
+
model = self.queryset.model._meta.model_name
|
|
888
|
+
manufacturer = Manufacturer.objects.first()
|
|
889
|
+
device_type = DeviceType.objects.create(
|
|
890
|
+
manufacturer=manufacturer, model=f"Test Device Filter for {model} Device Type"
|
|
891
|
+
)
|
|
892
|
+
device = Device.objects.create(
|
|
893
|
+
device_type=device_type,
|
|
894
|
+
name=f"Test Device Filter for {model} Device",
|
|
895
|
+
location=self.loc0,
|
|
896
|
+
role=self.device_roles[0],
|
|
897
|
+
status=Status.objects.get_for_model(Device).first(),
|
|
898
|
+
)
|
|
899
|
+
parent_module_bay = ModuleBay.objects.create(name="Parent module bay", position="1", parent_device=device)
|
|
900
|
+
module_type = ModuleType.objects.create(
|
|
901
|
+
manufacturer=manufacturer, model=f"Test Device Filter for {model} Module Type"
|
|
902
|
+
)
|
|
903
|
+
module = Module.objects.create(
|
|
904
|
+
module_type=module_type, parent_module_bay=parent_module_bay, status=self.module_statuses[0]
|
|
905
|
+
)
|
|
906
|
+
child_module_bay = ModuleBay.objects.create(name="Child module bay", position="1", parent_module=module)
|
|
907
|
+
child_module = Module.objects.create(
|
|
908
|
+
module_type=module_type, parent_module_bay=child_module_bay, status=self.module_statuses[0]
|
|
909
|
+
)
|
|
910
|
+
top_level_component = self.queryset.create(device=device, name=f"Top level {model}")
|
|
911
|
+
second_level_component = self.queryset.create(module=module, name=f"Second level {model}")
|
|
912
|
+
third_level_component = self.queryset.create(module=child_module, name=f"Third level {model}")
|
|
913
|
+
with self.subTest("device filter (pk)"):
|
|
914
|
+
self.assertQuerySetEqual(
|
|
915
|
+
self.filterset({"device": [device.pk]}, self.queryset).qs,
|
|
916
|
+
[top_level_component, second_level_component, third_level_component],
|
|
917
|
+
ordered=False,
|
|
918
|
+
)
|
|
919
|
+
with self.subTest("device filter (name)"):
|
|
920
|
+
self.assertQuerySetEqual(
|
|
921
|
+
self.filterset({"device": [device.name]}, self.queryset).qs,
|
|
922
|
+
[top_level_component, second_level_component, third_level_component],
|
|
923
|
+
ordered=False,
|
|
924
|
+
)
|
|
925
|
+
|
|
926
|
+
with self.subTest("device filter (pk) with an invalid uuid"):
|
|
927
|
+
self.assertFalse(self.filterset({"device": [uuid.uuid4()]}, self.queryset).is_valid())
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
class ModuleDeviceCommonTestsMixin:
|
|
931
|
+
def test_has_empty_module_bays(self):
|
|
932
|
+
test_instances = self.queryset.all()[:2]
|
|
933
|
+
ModuleBay.objects.create(
|
|
934
|
+
**{
|
|
935
|
+
f"parent_{self.queryset.model._meta.model_name}": test_instances[0],
|
|
936
|
+
"name": "test filters position 1",
|
|
937
|
+
"position": 1,
|
|
938
|
+
}
|
|
939
|
+
)
|
|
940
|
+
ModuleBay.objects.create(
|
|
941
|
+
**{
|
|
942
|
+
f"parent_{self.queryset.model._meta.model_name}": test_instances[1],
|
|
943
|
+
"name": "test filters position 1",
|
|
944
|
+
"position": 1,
|
|
945
|
+
}
|
|
946
|
+
)
|
|
947
|
+
with self.subTest():
|
|
948
|
+
params = {"has_empty_module_bays": True}
|
|
949
|
+
qs = self.filterset(params, self.queryset).qs
|
|
950
|
+
self.assertGreater(qs.count(), 0)
|
|
951
|
+
for instance in qs:
|
|
952
|
+
self.assertTrue(instance.module_bays.filter(installed_module__isnull=True).exists())
|
|
953
|
+
with self.subTest():
|
|
954
|
+
params = {"has_empty_module_bays": False}
|
|
955
|
+
qs = self.filterset(params, self.queryset).qs
|
|
956
|
+
self.assertGreater(qs.count(), 0)
|
|
957
|
+
for instance in qs:
|
|
958
|
+
self.assertFalse(instance.module_bays.filter(installed_module__isnull=True).exists())
|
|
959
|
+
|
|
960
|
+
def test_has_modules(self):
|
|
961
|
+
with self.subTest():
|
|
962
|
+
params = {"has_modules": True}
|
|
963
|
+
qs = self.filterset(params, self.queryset).qs
|
|
964
|
+
self.assertGreater(qs.count(), 0)
|
|
965
|
+
for instance in qs:
|
|
966
|
+
self.assertTrue(instance.module_bays.filter(installed_module__isnull=False).exists())
|
|
967
|
+
with self.subTest():
|
|
968
|
+
params = {"has_modules": False}
|
|
969
|
+
qs = self.filterset(params, self.queryset).qs
|
|
970
|
+
self.assertGreater(qs.count(), 0)
|
|
971
|
+
for instance in qs:
|
|
972
|
+
self.assertFalse(instance.module_bays.filter(installed_module__isnull=False).exists())
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
class PathEndpointModelTestMixin:
|
|
976
|
+
def test_connected(self):
|
|
977
|
+
with self.subTest():
|
|
978
|
+
params = {"connected": True}
|
|
979
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
980
|
+
self.filterset(params, self.queryset).qs,
|
|
981
|
+
self.queryset.filter(_path__is_active=True),
|
|
982
|
+
)
|
|
983
|
+
with self.subTest():
|
|
984
|
+
params = {"connected": False}
|
|
985
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
986
|
+
self.filterset(params, self.queryset).qs,
|
|
987
|
+
self.queryset.filter(Q(_path__isnull=True) | Q(_path__is_active=False)),
|
|
988
|
+
)
|
|
989
|
+
|
|
990
|
+
|
|
700
991
|
class LocationTypeFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
701
992
|
queryset = LocationType.objects.all()
|
|
702
993
|
filterset = LocationTypeFilterSet
|
|
@@ -1008,16 +1299,17 @@ class DeviceTypeTestCase(FilterTestCases.FilterTestCase):
|
|
|
1008
1299
|
("console_server_port_templates", "console_server_port_templates__name"),
|
|
1009
1300
|
("device_bay_templates", "device_bay_templates__id"),
|
|
1010
1301
|
("device_bay_templates", "device_bay_templates__name"),
|
|
1302
|
+
("device_family", "device_family__id"),
|
|
1303
|
+
("device_family", "device_family__name"),
|
|
1011
1304
|
("devices", "devices__id"),
|
|
1012
1305
|
("front_port_templates", "front_port_templates__id"),
|
|
1013
1306
|
("front_port_templates", "front_port_templates__name"),
|
|
1014
|
-
("device_family", "device_family__id"),
|
|
1015
|
-
("device_family", "device_family__name"),
|
|
1016
1307
|
("interface_templates", "interface_templates__id"),
|
|
1017
1308
|
("interface_templates", "interface_templates__name"),
|
|
1018
1309
|
("manufacturer", "manufacturer__id"),
|
|
1019
1310
|
("manufacturer", "manufacturer__name"),
|
|
1020
1311
|
("model",),
|
|
1312
|
+
("module_bay_templates", "module_bay_templates__id"),
|
|
1021
1313
|
("part_number",),
|
|
1022
1314
|
("power_outlet_templates", "power_outlet_templates__id"),
|
|
1023
1315
|
("power_outlet_templates", "power_outlet_templates__name"),
|
|
@@ -1158,13 +1450,13 @@ class DeviceTypeTestCase(FilterTestCases.FilterTestCase):
|
|
|
1158
1450
|
params = {"pass_through_ports": True}
|
|
1159
1451
|
self.assertQuerysetEqual(
|
|
1160
1452
|
self.filterset(params, self.queryset).qs,
|
|
1161
|
-
self.queryset.filter(query),
|
|
1453
|
+
self.queryset.filter(query).distinct(),
|
|
1162
1454
|
)
|
|
1163
1455
|
with self.subTest():
|
|
1164
1456
|
params = {"pass_through_ports": False}
|
|
1165
1457
|
self.assertQuerysetEqual(
|
|
1166
1458
|
self.filterset(params, self.queryset).qs,
|
|
1167
|
-
self.queryset.filter(~query),
|
|
1459
|
+
self.queryset.filter(~query).distinct(),
|
|
1168
1460
|
)
|
|
1169
1461
|
|
|
1170
1462
|
def test_device_bays(self):
|
|
@@ -1188,36 +1480,21 @@ class DeviceTypeTestCase(FilterTestCases.FilterTestCase):
|
|
|
1188
1480
|
self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
|
|
1189
1481
|
|
|
1190
1482
|
|
|
1191
|
-
class
|
|
1192
|
-
class ComponentTemplateMixin(FilterTestCases.FilterTestCase):
|
|
1193
|
-
generic_filter_tests = [
|
|
1194
|
-
("description",),
|
|
1195
|
-
("device_type", "device_type__id"),
|
|
1196
|
-
("device_type", "device_type__model"),
|
|
1197
|
-
("label",),
|
|
1198
|
-
("name",),
|
|
1199
|
-
]
|
|
1200
|
-
|
|
1201
|
-
@classmethod
|
|
1202
|
-
def setUpTestData(cls):
|
|
1203
|
-
common_test_data(cls)
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
class ConsolePortTemplateTestCase(Mixins.ComponentTemplateMixin):
|
|
1483
|
+
class ConsolePortTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1207
1484
|
queryset = ConsolePortTemplate.objects.all()
|
|
1208
1485
|
filterset = ConsolePortTemplateFilterSet
|
|
1209
1486
|
|
|
1210
1487
|
|
|
1211
|
-
class ConsoleServerPortTemplateTestCase(
|
|
1488
|
+
class ConsoleServerPortTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1212
1489
|
queryset = ConsoleServerPortTemplate.objects.all()
|
|
1213
1490
|
filterset = ConsoleServerPortTemplateFilterSet
|
|
1214
1491
|
|
|
1215
1492
|
|
|
1216
|
-
class PowerPortTemplateTestCase(
|
|
1493
|
+
class PowerPortTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1217
1494
|
queryset = PowerPortTemplate.objects.all()
|
|
1218
1495
|
filterset = PowerPortTemplateFilterSet
|
|
1219
1496
|
generic_filter_tests = [
|
|
1220
|
-
*
|
|
1497
|
+
*ModularComponentTemplateTestMixin.generic_filter_tests,
|
|
1221
1498
|
("allocated_draw",),
|
|
1222
1499
|
("maximum_draw",),
|
|
1223
1500
|
("power_outlet_templates", "power_outlet_templates__id"),
|
|
@@ -1239,11 +1516,12 @@ class PowerPortTemplateTestCase(Mixins.ComponentTemplateMixin):
|
|
|
1239
1516
|
)
|
|
1240
1517
|
|
|
1241
1518
|
|
|
1242
|
-
class PowerOutletTemplateTestCase(
|
|
1519
|
+
class PowerOutletTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1243
1520
|
queryset = PowerOutletTemplate.objects.all()
|
|
1244
1521
|
filterset = PowerOutletTemplateFilterSet
|
|
1245
1522
|
generic_filter_tests = [
|
|
1246
|
-
*
|
|
1523
|
+
*ModularComponentTemplateTestMixin.generic_filter_tests,
|
|
1524
|
+
("feed_leg",),
|
|
1247
1525
|
("power_port_template", "power_port_template__id"),
|
|
1248
1526
|
("power_port_template", "power_port_template__name"),
|
|
1249
1527
|
]
|
|
@@ -1261,26 +1539,14 @@ class PowerOutletTemplateTestCase(Mixins.ComponentTemplateMixin):
|
|
|
1261
1539
|
description="Power Outlet Description 4",
|
|
1262
1540
|
)
|
|
1263
1541
|
|
|
1264
|
-
def test_feed_leg(self):
|
|
1265
|
-
# TODO: Not a generic_filter_test because this is a single-value filter
|
|
1266
|
-
params = {"feed_leg": [PowerOutletFeedLegChoices.FEED_LEG_A]}
|
|
1267
|
-
self.assertQuerysetEqual(
|
|
1268
|
-
self.filterset(params, self.queryset).qs,
|
|
1269
|
-
self.queryset.filter(feed_leg=PowerOutletFeedLegChoices.FEED_LEG_A),
|
|
1270
|
-
)
|
|
1271
|
-
|
|
1272
1542
|
|
|
1273
|
-
class InterfaceTemplateTestCase(
|
|
1543
|
+
class InterfaceTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1274
1544
|
queryset = InterfaceTemplate.objects.all()
|
|
1275
1545
|
filterset = InterfaceTemplateFilterSet
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
self.assertQuerysetEqual(
|
|
1281
|
-
self.filterset(params, self.queryset).qs,
|
|
1282
|
-
self.queryset.filter(type=InterfaceTypeChoices.TYPE_1GE_FIXED),
|
|
1283
|
-
)
|
|
1546
|
+
generic_filter_tests = [
|
|
1547
|
+
*ModularComponentTemplateTestMixin.generic_filter_tests,
|
|
1548
|
+
("type",),
|
|
1549
|
+
]
|
|
1284
1550
|
|
|
1285
1551
|
def test_mgmt_only(self):
|
|
1286
1552
|
# TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
|
|
@@ -1298,11 +1564,11 @@ class InterfaceTemplateTestCase(Mixins.ComponentTemplateMixin):
|
|
|
1298
1564
|
)
|
|
1299
1565
|
|
|
1300
1566
|
|
|
1301
|
-
class FrontPortTemplateTestCase(
|
|
1567
|
+
class FrontPortTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1302
1568
|
queryset = FrontPortTemplate.objects.all()
|
|
1303
1569
|
filterset = FrontPortTemplateFilterSet
|
|
1304
1570
|
generic_filter_tests = [
|
|
1305
|
-
*
|
|
1571
|
+
*ModularComponentTemplateTestMixin.generic_filter_tests,
|
|
1306
1572
|
("rear_port_position",),
|
|
1307
1573
|
("rear_port_template", "rear_port_template__id"),
|
|
1308
1574
|
]
|
|
@@ -1316,11 +1582,11 @@ class FrontPortTemplateTestCase(Mixins.ComponentTemplateMixin):
|
|
|
1316
1582
|
)
|
|
1317
1583
|
|
|
1318
1584
|
|
|
1319
|
-
class RearPortTemplateTestCase(
|
|
1585
|
+
class RearPortTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1320
1586
|
queryset = RearPortTemplate.objects.all()
|
|
1321
1587
|
filterset = RearPortTemplateFilterSet
|
|
1322
1588
|
generic_filter_tests = [
|
|
1323
|
-
*
|
|
1589
|
+
*ModularComponentTemplateTestMixin.generic_filter_tests,
|
|
1324
1590
|
("front_port_templates", "front_port_templates__id"),
|
|
1325
1591
|
]
|
|
1326
1592
|
|
|
@@ -1355,7 +1621,7 @@ class RearPortTemplateTestCase(Mixins.ComponentTemplateMixin):
|
|
|
1355
1621
|
)
|
|
1356
1622
|
|
|
1357
1623
|
|
|
1358
|
-
class DeviceBayTemplateTestCase(
|
|
1624
|
+
class DeviceBayTemplateTestCase(ComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1359
1625
|
queryset = DeviceBayTemplate.objects.all()
|
|
1360
1626
|
filterset = DeviceBayTemplateFilterSet
|
|
1361
1627
|
|
|
@@ -1402,7 +1668,11 @@ class PlatformTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
1402
1668
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), len(virtual_machines))
|
|
1403
1669
|
|
|
1404
1670
|
|
|
1405
|
-
class DeviceTestCase(
|
|
1671
|
+
class DeviceTestCase(
|
|
1672
|
+
ModuleDeviceCommonTestsMixin,
|
|
1673
|
+
FilterTestCases.FilterTestCase,
|
|
1674
|
+
FilterTestCases.TenancyFilterTestCaseMixin,
|
|
1675
|
+
):
|
|
1406
1676
|
queryset = Device.objects.all()
|
|
1407
1677
|
filterset = DeviceFilterSet
|
|
1408
1678
|
tenancy_related_name = "devices"
|
|
@@ -1424,9 +1694,11 @@ class DeviceTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilt
|
|
|
1424
1694
|
("device_type", "device_type__model"),
|
|
1425
1695
|
("front_ports", "front_ports__id"),
|
|
1426
1696
|
("interfaces", "interfaces__id"),
|
|
1697
|
+
("interfaces", "interfaces__name"),
|
|
1427
1698
|
("mac_address", "interfaces__mac_address"),
|
|
1428
1699
|
("manufacturer", "device_type__manufacturer__id"),
|
|
1429
1700
|
("manufacturer", "device_type__manufacturer__name"),
|
|
1701
|
+
("module_bays", "module_bays__id"),
|
|
1430
1702
|
("name",),
|
|
1431
1703
|
("platform", "platform__id"),
|
|
1432
1704
|
("platform", "platform__name"),
|
|
@@ -1510,7 +1782,7 @@ class DeviceTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilt
|
|
|
1510
1782
|
)
|
|
1511
1783
|
|
|
1512
1784
|
# Assign primary IPs for filtering
|
|
1513
|
-
interfaces = Interface.objects.
|
|
1785
|
+
interfaces = Interface.objects.filter(device__isnull=False)
|
|
1514
1786
|
ipaddr_status = Status.objects.get_for_model(IPAddress).first()
|
|
1515
1787
|
prefix_status = Status.objects.get_for_model(Prefix).first()
|
|
1516
1788
|
namespace = Namespace.objects.first()
|
|
@@ -1681,21 +1953,17 @@ class DeviceTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilt
|
|
|
1681
1953
|
)
|
|
1682
1954
|
|
|
1683
1955
|
|
|
1684
|
-
class ConsolePortTestCase(FilterTestCases.FilterTestCase):
|
|
1956
|
+
class ConsolePortTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
1685
1957
|
queryset = ConsolePort.objects.all()
|
|
1686
1958
|
filterset = ConsolePortFilterSet
|
|
1687
1959
|
generic_filter_tests = [
|
|
1960
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
1688
1961
|
("cable", "cable__id"),
|
|
1689
|
-
("description",),
|
|
1690
|
-
("device", "device__id"),
|
|
1691
|
-
("device", "device__name"),
|
|
1692
|
-
("label",),
|
|
1693
|
-
("name",),
|
|
1694
1962
|
]
|
|
1695
1963
|
|
|
1696
1964
|
@classmethod
|
|
1697
1965
|
def setUpTestData(cls):
|
|
1698
|
-
|
|
1966
|
+
super().setUpTestData()
|
|
1699
1967
|
|
|
1700
1968
|
devices = (
|
|
1701
1969
|
Device.objects.get(name="Device 1"),
|
|
@@ -1730,31 +1998,20 @@ class ConsolePortTestCase(FilterTestCases.FilterTestCase):
|
|
|
1730
1998
|
)
|
|
1731
1999
|
# Third port is not connected
|
|
1732
2000
|
|
|
1733
|
-
def test_connected(self):
|
|
1734
|
-
# TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
|
|
1735
|
-
with self.subTest():
|
|
1736
|
-
params = {"connected": True}
|
|
1737
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1738
|
-
with self.subTest():
|
|
1739
|
-
params = {"connected": False}
|
|
1740
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
1741
|
-
|
|
1742
2001
|
|
|
1743
|
-
class ConsoleServerPortTestCase(
|
|
2002
|
+
class ConsoleServerPortTestCase(
|
|
2003
|
+
PathEndpointModelTestMixin, ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase
|
|
2004
|
+
):
|
|
1744
2005
|
queryset = ConsoleServerPort.objects.all()
|
|
1745
2006
|
filterset = ConsoleServerPortFilterSet
|
|
1746
2007
|
generic_filter_tests = [
|
|
2008
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
1747
2009
|
("cable", "cable__id"),
|
|
1748
|
-
("description",),
|
|
1749
|
-
("device", "device__id"),
|
|
1750
|
-
("device", "device__name"),
|
|
1751
|
-
("label",),
|
|
1752
|
-
("name",),
|
|
1753
2010
|
]
|
|
1754
2011
|
|
|
1755
2012
|
@classmethod
|
|
1756
2013
|
def setUpTestData(cls):
|
|
1757
|
-
|
|
2014
|
+
super().setUpTestData()
|
|
1758
2015
|
|
|
1759
2016
|
devices = (
|
|
1760
2017
|
Device.objects.get(name="Device 1"),
|
|
@@ -1789,28 +2046,15 @@ class ConsoleServerPortTestCase(FilterTestCases.FilterTestCase):
|
|
|
1789
2046
|
)
|
|
1790
2047
|
# Third port is not connected
|
|
1791
2048
|
|
|
1792
|
-
def test_connected(self):
|
|
1793
|
-
# TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
|
|
1794
|
-
with self.subTest():
|
|
1795
|
-
params = {"connected": True}
|
|
1796
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1797
|
-
with self.subTest():
|
|
1798
|
-
params = {"connected": False}
|
|
1799
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
1800
|
-
|
|
1801
2049
|
|
|
1802
|
-
class PowerPortTestCase(FilterTestCases.FilterTestCase):
|
|
2050
|
+
class PowerPortTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
1803
2051
|
queryset = PowerPort.objects.all()
|
|
1804
2052
|
filterset = PowerPortFilterSet
|
|
1805
2053
|
generic_filter_tests = [
|
|
2054
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
1806
2055
|
("allocated_draw",),
|
|
1807
2056
|
("cable", "cable__id"),
|
|
1808
|
-
("description",),
|
|
1809
|
-
("device", "device__id"),
|
|
1810
|
-
("device", "device__name"),
|
|
1811
|
-
("label",),
|
|
1812
2057
|
("maximum_draw",),
|
|
1813
|
-
("name",),
|
|
1814
2058
|
("power_outlets", "power_outlets__id"),
|
|
1815
2059
|
("power_outlets", "power_outlets__name"),
|
|
1816
2060
|
]
|
|
@@ -1854,32 +2098,20 @@ class PowerPortTestCase(FilterTestCases.FilterTestCase):
|
|
|
1854
2098
|
)
|
|
1855
2099
|
# Third port is not connected
|
|
1856
2100
|
|
|
1857
|
-
def test_connected(self):
|
|
1858
|
-
# TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
|
|
1859
|
-
with self.subTest():
|
|
1860
|
-
params = {"connected": True}
|
|
1861
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1862
|
-
with self.subTest():
|
|
1863
|
-
params = {"connected": False}
|
|
1864
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1865
|
-
|
|
1866
2101
|
|
|
1867
|
-
class PowerOutletTestCase(FilterTestCases.FilterTestCase):
|
|
2102
|
+
class PowerOutletTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
1868
2103
|
queryset = PowerOutlet.objects.all()
|
|
1869
2104
|
filterset = PowerOutletFilterSet
|
|
1870
2105
|
generic_filter_tests = [
|
|
2106
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
1871
2107
|
("cable", "cable__id"),
|
|
1872
|
-
("
|
|
1873
|
-
("device", "device__id"),
|
|
1874
|
-
("device", "device__name"),
|
|
1875
|
-
("label",),
|
|
1876
|
-
("name",),
|
|
2108
|
+
("feed_leg",),
|
|
1877
2109
|
("power_port", "power_port__id"),
|
|
1878
2110
|
]
|
|
1879
2111
|
|
|
1880
2112
|
@classmethod
|
|
1881
2113
|
def setUpTestData(cls):
|
|
1882
|
-
|
|
2114
|
+
super().setUpTestData()
|
|
1883
2115
|
|
|
1884
2116
|
devices = (
|
|
1885
2117
|
Device.objects.get(name="Device 1"),
|
|
@@ -1915,26 +2147,12 @@ class PowerOutletTestCase(FilterTestCases.FilterTestCase):
|
|
|
1915
2147
|
)
|
|
1916
2148
|
# Third port is not connected
|
|
1917
2149
|
|
|
1918
|
-
def test_feed_leg(self):
|
|
1919
|
-
# TODO: Not a generic_filter_test because this is a single-value filter
|
|
1920
|
-
# 2.0 TODO: Support filtering for multiple values
|
|
1921
|
-
params = {"feed_leg": [PowerOutletFeedLegChoices.FEED_LEG_A]}
|
|
1922
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
1923
|
-
|
|
1924
|
-
def test_connected(self):
|
|
1925
|
-
# TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
|
|
1926
|
-
with self.subTest():
|
|
1927
|
-
params = {"connected": True}
|
|
1928
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1929
|
-
with self.subTest():
|
|
1930
|
-
params = {"connected": False}
|
|
1931
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
1932
|
-
|
|
1933
2150
|
|
|
1934
|
-
class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
2151
|
+
class InterfaceTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
1935
2152
|
queryset = Interface.objects.all()
|
|
1936
2153
|
filterset = InterfaceFilterSet
|
|
1937
2154
|
generic_filter_tests = [
|
|
2155
|
+
# parent class generic_filter_tests intentionally excluded
|
|
1938
2156
|
("bridge", "bridge__id"),
|
|
1939
2157
|
("bridge", "bridge__name"),
|
|
1940
2158
|
("bridged_interfaces", "bridged_interfaces__id"),
|
|
@@ -1944,17 +2162,20 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
1944
2162
|
("child_interfaces", "child_interfaces__name"),
|
|
1945
2163
|
("description",),
|
|
1946
2164
|
# ("device", "device__id"), # TODO - InterfaceFilterSet overrides device as a MultiValueCharFilter on name only
|
|
1947
|
-
("device", "device__name"),
|
|
1948
2165
|
("label",),
|
|
1949
2166
|
("lag", "lag__id"),
|
|
1950
2167
|
("lag", "lag__name"),
|
|
1951
2168
|
("mac_address",),
|
|
1952
2169
|
("member_interfaces", "member_interfaces__id"),
|
|
1953
2170
|
("member_interfaces", "member_interfaces__name"),
|
|
2171
|
+
("module", "module__id"),
|
|
2172
|
+
("module", "module__module_type__model"),
|
|
1954
2173
|
("mtu",),
|
|
1955
2174
|
("name",),
|
|
1956
2175
|
("parent_interface", "parent_interface__id"),
|
|
1957
2176
|
("parent_interface", "parent_interface__name"),
|
|
2177
|
+
("role", "role__id"),
|
|
2178
|
+
("role", "role__name"),
|
|
1958
2179
|
("status", "status__id"),
|
|
1959
2180
|
("status", "status__name"),
|
|
1960
2181
|
("type",),
|
|
@@ -1966,7 +2187,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
1966
2187
|
|
|
1967
2188
|
@classmethod
|
|
1968
2189
|
def setUpTestData(cls):
|
|
1969
|
-
|
|
2190
|
+
super().setUpTestData()
|
|
1970
2191
|
|
|
1971
2192
|
devices = (
|
|
1972
2193
|
Device.objects.get(name="Device 1"),
|
|
@@ -1976,15 +2197,17 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
1976
2197
|
vlans = VLAN.objects.all()[:3]
|
|
1977
2198
|
|
|
1978
2199
|
interface_statuses = Status.objects.get_for_model(Interface)
|
|
2200
|
+
interface_roles = Role.objects.get_for_model(Interface)
|
|
1979
2201
|
|
|
1980
2202
|
# Cabled interfaces
|
|
1981
2203
|
cabled_interfaces = (
|
|
1982
|
-
Interface.objects.get(name="Interface 1"),
|
|
1983
|
-
Interface.objects.get(name="Interface 2"),
|
|
1984
|
-
Interface.objects.get(name="Interface 3"),
|
|
2204
|
+
Interface.objects.get(name="Test Interface 1"),
|
|
2205
|
+
Interface.objects.get(name="Test Interface 2"),
|
|
2206
|
+
Interface.objects.get(name="Test Interface 3"),
|
|
1985
2207
|
Interface.objects.create(
|
|
1986
2208
|
device=devices[2],
|
|
1987
2209
|
name="Parent Interface 1",
|
|
2210
|
+
role=interface_roles[0],
|
|
1988
2211
|
type=InterfaceTypeChoices.TYPE_OTHER,
|
|
1989
2212
|
mode=InterfaceModeChoices.MODE_TAGGED,
|
|
1990
2213
|
enabled=True,
|
|
@@ -2004,6 +2227,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2004
2227
|
Interface.objects.create(
|
|
2005
2228
|
device=devices[2],
|
|
2006
2229
|
name="Parent Interface 3",
|
|
2230
|
+
role=interface_roles[1],
|
|
2007
2231
|
type=InterfaceTypeChoices.TYPE_OTHER,
|
|
2008
2232
|
mode=InterfaceModeChoices.MODE_TAGGED,
|
|
2009
2233
|
enabled=False,
|
|
@@ -2069,6 +2293,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2069
2293
|
Interface.objects.create(
|
|
2070
2294
|
device=cabled_interfaces[3].device,
|
|
2071
2295
|
name="Child 1",
|
|
2296
|
+
role=interface_roles[2],
|
|
2072
2297
|
parent_interface=cabled_interfaces[3],
|
|
2073
2298
|
status=interface_statuses[3],
|
|
2074
2299
|
type=InterfaceTypeChoices.TYPE_VIRTUAL,
|
|
@@ -2083,6 +2308,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2083
2308
|
Interface.objects.create(
|
|
2084
2309
|
device=cabled_interfaces[5].device,
|
|
2085
2310
|
name="Child 3",
|
|
2311
|
+
role=interface_roles[0],
|
|
2086
2312
|
parent_interface=cabled_interfaces[5],
|
|
2087
2313
|
status=interface_statuses[3],
|
|
2088
2314
|
type=InterfaceTypeChoices.TYPE_VIRTUAL,
|
|
@@ -2099,12 +2325,14 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2099
2325
|
Interface.objects.create(
|
|
2100
2326
|
device=devices[2],
|
|
2101
2327
|
name="Bridge 2",
|
|
2328
|
+
role=interface_roles[1],
|
|
2102
2329
|
status=interface_statuses[3],
|
|
2103
2330
|
type=InterfaceTypeChoices.TYPE_BRIDGE,
|
|
2104
2331
|
),
|
|
2105
2332
|
Interface.objects.create(
|
|
2106
2333
|
device=devices[2],
|
|
2107
2334
|
name="Bridge 3",
|
|
2335
|
+
role=interface_roles[2],
|
|
2108
2336
|
status=interface_statuses[3],
|
|
2109
2337
|
type=InterfaceTypeChoices.TYPE_BRIDGE,
|
|
2110
2338
|
),
|
|
@@ -2112,6 +2340,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2112
2340
|
Interface.objects.create(
|
|
2113
2341
|
device=bridge_interfaces[0].device,
|
|
2114
2342
|
name="Bridged 1",
|
|
2343
|
+
role=interface_roles[0],
|
|
2115
2344
|
bridge=bridge_interfaces[0],
|
|
2116
2345
|
status=interface_statuses[3],
|
|
2117
2346
|
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
@@ -2126,6 +2355,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2126
2355
|
Interface.objects.create(
|
|
2127
2356
|
device=bridge_interfaces[2].device,
|
|
2128
2357
|
name="Bridged 3",
|
|
2358
|
+
role=interface_roles[1],
|
|
2129
2359
|
bridge=bridge_interfaces[2],
|
|
2130
2360
|
status=interface_statuses[3],
|
|
2131
2361
|
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
@@ -2136,6 +2366,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2136
2366
|
Interface.objects.create(
|
|
2137
2367
|
device=devices[2],
|
|
2138
2368
|
name="LAG 1",
|
|
2369
|
+
role=interface_roles[0],
|
|
2139
2370
|
type=InterfaceTypeChoices.TYPE_LAG,
|
|
2140
2371
|
status=interface_statuses[3],
|
|
2141
2372
|
),
|
|
@@ -2148,6 +2379,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2148
2379
|
Interface.objects.create(
|
|
2149
2380
|
device=devices[2],
|
|
2150
2381
|
name="LAG 3",
|
|
2382
|
+
role=interface_roles[1],
|
|
2151
2383
|
type=InterfaceTypeChoices.TYPE_LAG,
|
|
2152
2384
|
status=interface_statuses[3],
|
|
2153
2385
|
),
|
|
@@ -2163,6 +2395,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2163
2395
|
device=devices[2],
|
|
2164
2396
|
name="Member 2",
|
|
2165
2397
|
lag=lag_interfaces[1],
|
|
2398
|
+
role=interface_roles[2],
|
|
2166
2399
|
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2167
2400
|
status=interface_statuses[3],
|
|
2168
2401
|
)
|
|
@@ -2174,32 +2407,35 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2174
2407
|
status=interface_statuses[3],
|
|
2175
2408
|
)
|
|
2176
2409
|
|
|
2177
|
-
def test_connected(self):
|
|
2178
|
-
# TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
|
|
2179
|
-
with self.subTest():
|
|
2180
|
-
params = {"connected": True}
|
|
2181
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
|
2182
|
-
with self.subTest():
|
|
2183
|
-
params = {"connected": False}
|
|
2184
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 17)
|
|
2185
|
-
|
|
2186
2410
|
def test_enabled(self):
|
|
2187
2411
|
# TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
|
|
2188
2412
|
with self.subTest():
|
|
2189
2413
|
params = {"enabled": True}
|
|
2190
|
-
self.
|
|
2414
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2415
|
+
self.filterset(params, self.queryset).qs,
|
|
2416
|
+
self.queryset.filter(**params),
|
|
2417
|
+
)
|
|
2191
2418
|
with self.subTest():
|
|
2192
2419
|
params = {"enabled": False}
|
|
2193
|
-
self.
|
|
2420
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2421
|
+
self.filterset(params, self.queryset).qs,
|
|
2422
|
+
self.queryset.filter(**params),
|
|
2423
|
+
)
|
|
2194
2424
|
|
|
2195
2425
|
def test_mgmt_only(self):
|
|
2196
2426
|
# TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
|
|
2197
2427
|
with self.subTest():
|
|
2198
2428
|
params = {"mgmt_only": True}
|
|
2199
|
-
self.
|
|
2429
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2430
|
+
self.filterset(params, self.queryset).qs,
|
|
2431
|
+
self.queryset.filter(**params),
|
|
2432
|
+
)
|
|
2200
2433
|
with self.subTest():
|
|
2201
2434
|
params = {"mgmt_only": False}
|
|
2202
|
-
self.
|
|
2435
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2436
|
+
self.filterset(params, self.queryset).qs,
|
|
2437
|
+
self.queryset.filter(**params),
|
|
2438
|
+
)
|
|
2203
2439
|
|
|
2204
2440
|
def test_mode(self):
|
|
2205
2441
|
# TODO: Not a generic_filter_test because this is a single-value filter
|
|
@@ -2264,15 +2500,161 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2264
2500
|
with self.subTest():
|
|
2265
2501
|
self.assertFalse(queryset.filter(name="int4").exists())
|
|
2266
2502
|
|
|
2503
|
+
def test_device(self):
|
|
2504
|
+
"""
|
|
2505
|
+
Test that the device filter returns all components for a device and its
|
|
2506
|
+
modules, including virtual chassis member devices and their modules.
|
|
2507
|
+
"""
|
|
2508
|
+
status = Status.objects.get_for_model(Interface).first()
|
|
2509
|
+
manufacturer = Manufacturer.objects.first()
|
|
2510
|
+
device_type = DeviceType.objects.create(
|
|
2511
|
+
manufacturer=manufacturer, model="Test Device Filter for Interface Device Type"
|
|
2512
|
+
)
|
|
2513
|
+
device_vc_master = Device.objects.create(
|
|
2514
|
+
device_type=device_type,
|
|
2515
|
+
name="Test Device Filter for Interface Device VC Master",
|
|
2516
|
+
location=self.loc0,
|
|
2517
|
+
role=self.device_roles[0],
|
|
2518
|
+
status=Status.objects.get_for_model(Device).first(),
|
|
2519
|
+
)
|
|
2520
|
+
vc = VirtualChassis.objects.create(
|
|
2521
|
+
name="Test Device Filter for Interface Virtual Chassis", master=device_vc_master
|
|
2522
|
+
)
|
|
2523
|
+
device_vc_master.virtual_chassis = vc
|
|
2524
|
+
device_vc_master.save()
|
|
2525
|
+
parent_module_bay = ModuleBay.objects.create(
|
|
2526
|
+
name="Parent module bay", position="1", parent_device=device_vc_master
|
|
2527
|
+
)
|
|
2528
|
+
module_type = ModuleType.objects.create(
|
|
2529
|
+
manufacturer=manufacturer, model="Test Device Filter for Interface Module Type"
|
|
2530
|
+
)
|
|
2531
|
+
module = Module.objects.create(
|
|
2532
|
+
module_type=module_type, parent_module_bay=parent_module_bay, status=self.module_statuses[0]
|
|
2533
|
+
)
|
|
2534
|
+
child_module_bay = ModuleBay.objects.create(name="Child module bay", position="1", parent_module=module)
|
|
2535
|
+
child_module = Module.objects.create(
|
|
2536
|
+
module_type=module_type, parent_module_bay=child_module_bay, status=self.module_statuses[0]
|
|
2537
|
+
)
|
|
2538
|
+
top_level_interface = self.queryset.create(
|
|
2539
|
+
device=device_vc_master,
|
|
2540
|
+
name="Top level Interface VC Master",
|
|
2541
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2542
|
+
status=status,
|
|
2543
|
+
)
|
|
2544
|
+
second_level_interface = self.queryset.create(
|
|
2545
|
+
module=module,
|
|
2546
|
+
name="Second level Interface VC Master",
|
|
2547
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2548
|
+
status=status,
|
|
2549
|
+
)
|
|
2550
|
+
third_level_interface = self.queryset.create(
|
|
2551
|
+
module=child_module,
|
|
2552
|
+
name="Third level Interface VC Master",
|
|
2553
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2554
|
+
status=status,
|
|
2555
|
+
)
|
|
2556
|
+
device_vc_member = Device.objects.create(
|
|
2557
|
+
device_type=device_type,
|
|
2558
|
+
name="Test Device Filter for Interface Device VC Member",
|
|
2559
|
+
location=self.loc0,
|
|
2560
|
+
role=self.device_roles[0],
|
|
2561
|
+
status=Status.objects.get_for_model(Device).first(),
|
|
2562
|
+
virtual_chassis=vc,
|
|
2563
|
+
)
|
|
2564
|
+
parent_module_bay_vc_member = ModuleBay.objects.create(
|
|
2565
|
+
name="Parent module bay", position="1", parent_device=device_vc_member
|
|
2566
|
+
)
|
|
2567
|
+
module_vc_member = Module.objects.create(
|
|
2568
|
+
module_type=module_type, parent_module_bay=parent_module_bay_vc_member, status=self.module_statuses[0]
|
|
2569
|
+
)
|
|
2570
|
+
child_module_bay_vc_member = ModuleBay.objects.create(
|
|
2571
|
+
name="Child module bay", position="1", parent_module=module_vc_member
|
|
2572
|
+
)
|
|
2573
|
+
child_module_vc_member = Module.objects.create(
|
|
2574
|
+
module_type=module_type, parent_module_bay=child_module_bay_vc_member, status=self.module_statuses[0]
|
|
2575
|
+
)
|
|
2576
|
+
top_level_interface_vc_member = self.queryset.create(
|
|
2577
|
+
device=device_vc_member,
|
|
2578
|
+
name="Top level Interface VC Member",
|
|
2579
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2580
|
+
status=status,
|
|
2581
|
+
)
|
|
2582
|
+
second_level_interface_vc_member = self.queryset.create(
|
|
2583
|
+
module=module_vc_member,
|
|
2584
|
+
name="Second level Interface VC Member",
|
|
2585
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2586
|
+
status=status,
|
|
2587
|
+
)
|
|
2588
|
+
third_level_interface_vc_member = self.queryset.create(
|
|
2589
|
+
module=child_module_vc_member,
|
|
2590
|
+
name="Third level Interface VC Member",
|
|
2591
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2592
|
+
status=status,
|
|
2593
|
+
)
|
|
2594
|
+
|
|
2595
|
+
with self.subTest("device filter on pk"):
|
|
2596
|
+
self.assertQuerySetEqual(
|
|
2597
|
+
self.filterset({"device": [device_vc_master.pk]}, self.queryset).qs,
|
|
2598
|
+
[
|
|
2599
|
+
top_level_interface,
|
|
2600
|
+
second_level_interface,
|
|
2601
|
+
third_level_interface,
|
|
2602
|
+
top_level_interface_vc_member,
|
|
2603
|
+
second_level_interface_vc_member,
|
|
2604
|
+
third_level_interface_vc_member,
|
|
2605
|
+
],
|
|
2606
|
+
ordered=False,
|
|
2607
|
+
)
|
|
2608
|
+
|
|
2609
|
+
with self.subTest("device filter on name"):
|
|
2610
|
+
self.assertQuerySetEqual(
|
|
2611
|
+
self.filterset({"device": [device_vc_master.name]}, self.queryset).qs,
|
|
2612
|
+
[
|
|
2613
|
+
top_level_interface,
|
|
2614
|
+
second_level_interface,
|
|
2615
|
+
third_level_interface,
|
|
2616
|
+
top_level_interface_vc_member,
|
|
2617
|
+
second_level_interface_vc_member,
|
|
2618
|
+
third_level_interface_vc_member,
|
|
2619
|
+
],
|
|
2620
|
+
ordered=False,
|
|
2621
|
+
)
|
|
2622
|
+
|
|
2623
|
+
with self.subTest("device_id filter"):
|
|
2624
|
+
self.assertQuerySetEqual(
|
|
2625
|
+
self.filterset({"device_id": [device_vc_master.pk]}, self.queryset).qs,
|
|
2626
|
+
[
|
|
2627
|
+
top_level_interface,
|
|
2628
|
+
second_level_interface,
|
|
2629
|
+
third_level_interface,
|
|
2630
|
+
top_level_interface_vc_member,
|
|
2631
|
+
second_level_interface_vc_member,
|
|
2632
|
+
third_level_interface_vc_member,
|
|
2633
|
+
],
|
|
2634
|
+
ordered=False,
|
|
2635
|
+
)
|
|
2636
|
+
|
|
2637
|
+
with self.subTest("device_id filter with an invalid uuid"):
|
|
2638
|
+
self.assertFalse(self.filterset({"device_id": [uuid.uuid4()]}, self.queryset).is_valid())
|
|
2639
|
+
|
|
2640
|
+
with self.subTest("device (pk) filter with an invalid uuid"):
|
|
2641
|
+
self.assertFalse(self.filterset({"device": [uuid.uuid4()]}, self.queryset).is_valid())
|
|
2642
|
+
|
|
2267
2643
|
def test_kind(self):
|
|
2268
2644
|
# TODO: Not a generic_filter_test because this is a single-value filter
|
|
2269
2645
|
# 2.0 TODO: Support filtering for multiple values
|
|
2270
2646
|
with self.subTest():
|
|
2271
2647
|
params = {"kind": "physical"}
|
|
2272
|
-
self.
|
|
2648
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2649
|
+
self.filterset(params, self.queryset).qs,
|
|
2650
|
+
self.queryset.exclude(type__in=NONCONNECTABLE_IFACE_TYPES),
|
|
2651
|
+
)
|
|
2273
2652
|
with self.subTest():
|
|
2274
2653
|
params = {"kind": "virtual"}
|
|
2275
|
-
self.
|
|
2654
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2655
|
+
self.filterset(params, self.queryset).qs,
|
|
2656
|
+
self.queryset.filter(type__in=VIRTUAL_IFACE_TYPES),
|
|
2657
|
+
)
|
|
2276
2658
|
|
|
2277
2659
|
def test_vlan(self):
|
|
2278
2660
|
# TODO: Not a generic_filter_test because this is a single-value filter
|
|
@@ -2297,24 +2679,21 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2297
2679
|
)
|
|
2298
2680
|
|
|
2299
2681
|
|
|
2300
|
-
class FrontPortTestCase(FilterTestCases.FilterTestCase):
|
|
2682
|
+
class FrontPortTestCase(ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
2301
2683
|
queryset = FrontPort.objects.all()
|
|
2302
2684
|
filterset = FrontPortFilterSet
|
|
2303
2685
|
generic_filter_tests = [
|
|
2304
|
-
|
|
2686
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
2305
2687
|
("cable", "cable__id"),
|
|
2306
|
-
("device", "device__id"),
|
|
2307
|
-
("device", "device__name"),
|
|
2308
|
-
("label",),
|
|
2309
|
-
("name",),
|
|
2310
2688
|
("rear_port", "rear_port__id"),
|
|
2311
2689
|
("rear_port", "rear_port__name"),
|
|
2312
2690
|
("rear_port_position",),
|
|
2691
|
+
("type",),
|
|
2313
2692
|
]
|
|
2314
2693
|
|
|
2315
2694
|
@classmethod
|
|
2316
2695
|
def setUpTestData(cls):
|
|
2317
|
-
|
|
2696
|
+
super().setUpTestData()
|
|
2318
2697
|
|
|
2319
2698
|
devices = (
|
|
2320
2699
|
Device.objects.get(name="Device 1"),
|
|
@@ -2378,30 +2757,93 @@ class FrontPortTestCase(FilterTestCases.FilterTestCase):
|
|
|
2378
2757
|
)
|
|
2379
2758
|
# Third port is not connected
|
|
2380
2759
|
|
|
2381
|
-
def
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2760
|
+
def test_device(self):
|
|
2761
|
+
"""Test that the device filter returns all components for a device and its modules."""
|
|
2762
|
+
manufacturer = Manufacturer.objects.first()
|
|
2763
|
+
device_type = DeviceType.objects.create(
|
|
2764
|
+
manufacturer=manufacturer, model="Test Device Filter for FrontPort Device Type"
|
|
2765
|
+
)
|
|
2766
|
+
device = Device.objects.create(
|
|
2767
|
+
device_type=device_type,
|
|
2768
|
+
name="Test Device Filter for FrontPort Device",
|
|
2769
|
+
location=self.loc0,
|
|
2770
|
+
role=self.device_roles[0],
|
|
2771
|
+
status=Status.objects.get_for_model(Device).first(),
|
|
2772
|
+
)
|
|
2773
|
+
parent_module_bay = ModuleBay.objects.create(name="Parent module bay", position="1", parent_device=device)
|
|
2774
|
+
module_type = ModuleType.objects.create(
|
|
2775
|
+
manufacturer=manufacturer, model="Test Device Filter for FrontPort Module Type"
|
|
2776
|
+
)
|
|
2777
|
+
module = Module.objects.create(
|
|
2778
|
+
module_type=module_type, parent_module_bay=parent_module_bay, status=self.module_statuses[0]
|
|
2779
|
+
)
|
|
2780
|
+
child_module_bay = ModuleBay.objects.create(name="Child module bay", position="1", parent_module=module)
|
|
2781
|
+
child_module = Module.objects.create(
|
|
2782
|
+
module_type=module_type, parent_module_bay=child_module_bay, status=self.module_statuses[0]
|
|
2783
|
+
)
|
|
2784
|
+
top_level_rearport = RearPort.objects.create(
|
|
2785
|
+
device=device,
|
|
2786
|
+
name="Top level Rear Port",
|
|
2787
|
+
type=PortTypeChoices.TYPE_8P8C,
|
|
2788
|
+
positions=6,
|
|
2789
|
+
)
|
|
2790
|
+
second_level_rearport = RearPort.objects.create(
|
|
2791
|
+
module=module,
|
|
2792
|
+
name="Second level Rear Port",
|
|
2793
|
+
type=PortTypeChoices.TYPE_8P8C,
|
|
2794
|
+
positions=6,
|
|
2795
|
+
)
|
|
2796
|
+
third_level_rearport = RearPort.objects.create(
|
|
2797
|
+
module=child_module,
|
|
2798
|
+
name="Third level Rear Port",
|
|
2799
|
+
type=PortTypeChoices.TYPE_8P8C,
|
|
2800
|
+
positions=6,
|
|
2801
|
+
)
|
|
2802
|
+
top_level_frontport = self.queryset.create(
|
|
2803
|
+
device=device,
|
|
2804
|
+
name="Top level Front Port",
|
|
2805
|
+
rear_port=top_level_rearport,
|
|
2806
|
+
rear_port_position=1,
|
|
2807
|
+
)
|
|
2808
|
+
second_level_frontport = self.queryset.create(
|
|
2809
|
+
module=module,
|
|
2810
|
+
name="Second level Front Port",
|
|
2811
|
+
rear_port=second_level_rearport,
|
|
2812
|
+
rear_port_position=1,
|
|
2813
|
+
)
|
|
2814
|
+
third_level_frontport = self.queryset.create(
|
|
2815
|
+
module=child_module,
|
|
2816
|
+
name="Third level Front Port",
|
|
2817
|
+
rear_port=third_level_rearport,
|
|
2818
|
+
rear_port_position=1,
|
|
2819
|
+
)
|
|
2820
|
+
self.assertQuerySetEqual(
|
|
2821
|
+
self.filterset({"device": [device.pk]}, self.queryset).qs,
|
|
2822
|
+
[top_level_frontport, second_level_frontport, third_level_frontport],
|
|
2823
|
+
ordered=False,
|
|
2824
|
+
)
|
|
2825
|
+
self.assertQuerySetEqual(
|
|
2826
|
+
self.filterset({"device": [device.name]}, self.queryset).qs,
|
|
2827
|
+
[top_level_frontport, second_level_frontport, third_level_frontport],
|
|
2828
|
+
ordered=False,
|
|
2829
|
+
)
|
|
2385
2830
|
|
|
2386
2831
|
|
|
2387
|
-
class RearPortTestCase(FilterTestCases.FilterTestCase):
|
|
2832
|
+
class RearPortTestCase(ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
2388
2833
|
queryset = RearPort.objects.all()
|
|
2389
2834
|
filterset = RearPortFilterSet
|
|
2390
2835
|
generic_filter_tests = [
|
|
2836
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
2391
2837
|
("cable", "cable__id"),
|
|
2392
|
-
("description",),
|
|
2393
|
-
("device", "device__id"),
|
|
2394
|
-
("device", "device__name"),
|
|
2395
2838
|
("front_ports", "front_ports__id"),
|
|
2396
2839
|
("front_ports", "front_ports__name"),
|
|
2397
|
-
("label",),
|
|
2398
|
-
("name",),
|
|
2399
2840
|
("positions",),
|
|
2841
|
+
("type",),
|
|
2400
2842
|
]
|
|
2401
2843
|
|
|
2402
2844
|
@classmethod
|
|
2403
2845
|
def setUpTestData(cls):
|
|
2404
|
-
|
|
2846
|
+
super().setUpTestData()
|
|
2405
2847
|
|
|
2406
2848
|
devices = (
|
|
2407
2849
|
Device.objects.get(name="Device 1"),
|
|
@@ -2445,28 +2887,19 @@ class RearPortTestCase(FilterTestCases.FilterTestCase):
|
|
|
2445
2887
|
)
|
|
2446
2888
|
# Third port is not connected
|
|
2447
2889
|
|
|
2448
|
-
def test_type(self):
|
|
2449
|
-
# TODO: Not a generic_filter_test because this is a single-value filter
|
|
2450
|
-
params = {"type": [PortTypeChoices.TYPE_8P8C]}
|
|
2451
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
2452
|
-
|
|
2453
2890
|
|
|
2454
|
-
class DeviceBayTestCase(FilterTestCases.FilterTestCase):
|
|
2891
|
+
class DeviceBayTestCase(DeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
2455
2892
|
queryset = DeviceBay.objects.all()
|
|
2456
2893
|
filterset = DeviceBayFilterSet
|
|
2457
2894
|
generic_filter_tests = [
|
|
2458
|
-
|
|
2459
|
-
("device", "device__id"),
|
|
2460
|
-
("device", "device__name"),
|
|
2895
|
+
*DeviceComponentTestMixin.generic_filter_tests,
|
|
2461
2896
|
("installed_device", "installed_device__id"),
|
|
2462
2897
|
("installed_device", "installed_device__name"),
|
|
2463
|
-
("label",),
|
|
2464
|
-
("name",),
|
|
2465
2898
|
]
|
|
2466
2899
|
|
|
2467
2900
|
@classmethod
|
|
2468
2901
|
def setUpTestData(cls):
|
|
2469
|
-
|
|
2902
|
+
super().setUpTestData()
|
|
2470
2903
|
|
|
2471
2904
|
device_role = Role.objects.get_for_model(Device).first()
|
|
2472
2905
|
parent_device_type = DeviceType.objects.get(model="Model 2")
|
|
@@ -2519,19 +2952,15 @@ class DeviceBayTestCase(FilterTestCases.FilterTestCase):
|
|
|
2519
2952
|
device_bays[1].save()
|
|
2520
2953
|
|
|
2521
2954
|
|
|
2522
|
-
class InventoryItemTestCase(FilterTestCases.FilterTestCase):
|
|
2955
|
+
class InventoryItemTestCase(DeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
2523
2956
|
queryset = InventoryItem.objects.all()
|
|
2524
2957
|
filterset = InventoryItemFilterSet
|
|
2525
2958
|
generic_filter_tests = [
|
|
2959
|
+
*DeviceComponentTestMixin.generic_filter_tests,
|
|
2526
2960
|
("asset_tag",),
|
|
2527
2961
|
("children", "children__id"),
|
|
2528
|
-
("description",),
|
|
2529
|
-
("device", "device__id"),
|
|
2530
|
-
("device", "device__name"),
|
|
2531
|
-
("label",),
|
|
2532
2962
|
("manufacturer", "manufacturer__id"),
|
|
2533
2963
|
("manufacturer", "manufacturer__name"),
|
|
2534
|
-
("name",),
|
|
2535
2964
|
("parent", "parent__id"),
|
|
2536
2965
|
("parent", "parent__name"),
|
|
2537
2966
|
("part_id",),
|
|
@@ -2543,7 +2972,7 @@ class InventoryItemTestCase(FilterTestCases.FilterTestCase):
|
|
|
2543
2972
|
|
|
2544
2973
|
@classmethod
|
|
2545
2974
|
def setUpTestData(cls):
|
|
2546
|
-
|
|
2975
|
+
super().setUpTestData()
|
|
2547
2976
|
|
|
2548
2977
|
devices = (
|
|
2549
2978
|
Device.objects.get(name="Device 1"),
|
|
@@ -2551,7 +2980,7 @@ class InventoryItemTestCase(FilterTestCases.FilterTestCase):
|
|
|
2551
2980
|
Device.objects.get(name="Device 3"),
|
|
2552
2981
|
)
|
|
2553
2982
|
|
|
2554
|
-
software_versions = SoftwareVersion.objects.filter(software_image_files__isnull=False)[:3]
|
|
2983
|
+
software_versions = SoftwareVersion.objects.filter(software_image_files__isnull=False).distinct()[:3]
|
|
2555
2984
|
|
|
2556
2985
|
inventory_items = (
|
|
2557
2986
|
InventoryItem.objects.create(
|
|
@@ -2797,37 +3226,37 @@ class CableTestCase(FilterTestCases.FilterTestCase):
|
|
|
2797
3226
|
Interface.objects.get(device__name="Device 6"),
|
|
2798
3227
|
Interface.objects.create(
|
|
2799
3228
|
device=devices[0],
|
|
2800
|
-
name="Interface 7",
|
|
3229
|
+
name="Test Interface 7",
|
|
2801
3230
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2802
3231
|
status=interface_status,
|
|
2803
3232
|
),
|
|
2804
3233
|
Interface.objects.create(
|
|
2805
3234
|
device=devices[1],
|
|
2806
|
-
name="Interface 8",
|
|
3235
|
+
name="Test Interface 8",
|
|
2807
3236
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2808
3237
|
status=interface_status,
|
|
2809
3238
|
),
|
|
2810
3239
|
Interface.objects.create(
|
|
2811
3240
|
device=devices[2],
|
|
2812
|
-
name="Interface 9",
|
|
3241
|
+
name="Test Interface 9",
|
|
2813
3242
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2814
3243
|
status=interface_status,
|
|
2815
3244
|
),
|
|
2816
3245
|
Interface.objects.create(
|
|
2817
3246
|
device=devices[3],
|
|
2818
|
-
name="Interface 10",
|
|
3247
|
+
name="Test Interface 10",
|
|
2819
3248
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2820
3249
|
status=interface_status,
|
|
2821
3250
|
),
|
|
2822
3251
|
Interface.objects.create(
|
|
2823
3252
|
device=devices[4],
|
|
2824
|
-
name="Interface 11",
|
|
3253
|
+
name="Test Interface 11",
|
|
2825
3254
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2826
3255
|
status=interface_status,
|
|
2827
3256
|
),
|
|
2828
3257
|
Interface.objects.create(
|
|
2829
3258
|
device=devices[5],
|
|
2830
|
-
name="Interface 12",
|
|
3259
|
+
name="Test Interface 12",
|
|
2831
3260
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2832
3261
|
status=interface_status,
|
|
2833
3262
|
),
|
|
@@ -2913,17 +3342,87 @@ class CableTestCase(FilterTestCases.FilterTestCase):
|
|
|
2913
3342
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
|
2914
3343
|
|
|
2915
3344
|
def test_device(self):
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
self.
|
|
3345
|
+
"""Test that the device filter returns all cables for a device and its modules."""
|
|
3346
|
+
interfaces = Interface.objects.filter(cable__isnull=True)[:3]
|
|
3347
|
+
manufacturer = Manufacturer.objects.first()
|
|
3348
|
+
device_type = DeviceType.objects.create(
|
|
3349
|
+
manufacturer=manufacturer, model="Test Device Filter for Cable Device Type"
|
|
3350
|
+
)
|
|
3351
|
+
device = Device.objects.create(
|
|
3352
|
+
device_type=device_type,
|
|
3353
|
+
name="Test Device Filter for Cable Device",
|
|
3354
|
+
location=self.loc0,
|
|
3355
|
+
role=self.device_roles[0],
|
|
3356
|
+
status=Status.objects.get_for_model(Device).first(),
|
|
3357
|
+
)
|
|
3358
|
+
parent_module_bay = ModuleBay.objects.create(name="Parent module bay", position="1", parent_device=device)
|
|
3359
|
+
module_type = ModuleType.objects.create(
|
|
3360
|
+
manufacturer=manufacturer, model="Test Device Filter for Cable Module Type"
|
|
3361
|
+
)
|
|
3362
|
+
module = Module.objects.create(
|
|
3363
|
+
module_type=module_type, parent_module_bay=parent_module_bay, status=self.module_statuses[0]
|
|
3364
|
+
)
|
|
3365
|
+
child_module_bay = ModuleBay.objects.create(name="Child module bay", position="1", parent_module=module)
|
|
3366
|
+
child_module = Module.objects.create(
|
|
3367
|
+
module_type=module_type, parent_module_bay=child_module_bay, status=self.module_statuses[0]
|
|
3368
|
+
)
|
|
3369
|
+
interface_status = Status.objects.get_for_model(Interface).first()
|
|
3370
|
+
top_level_interface = Interface.objects.create(
|
|
3371
|
+
device=device,
|
|
3372
|
+
name="Top level Interface",
|
|
3373
|
+
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
3374
|
+
status=interface_status,
|
|
3375
|
+
)
|
|
3376
|
+
Interface.objects.create(
|
|
3377
|
+
module=module,
|
|
3378
|
+
name="Second level Interface",
|
|
3379
|
+
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
3380
|
+
status=interface_status,
|
|
3381
|
+
)
|
|
3382
|
+
third_level_interface = Interface.objects.create(
|
|
3383
|
+
module=child_module,
|
|
3384
|
+
name="Third level Interface",
|
|
3385
|
+
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
3386
|
+
status=interface_status,
|
|
3387
|
+
)
|
|
3388
|
+
|
|
3389
|
+
top_level_cable = Cable.objects.create(
|
|
3390
|
+
termination_a=top_level_interface,
|
|
3391
|
+
termination_b=interfaces[0],
|
|
3392
|
+
label="Test Device Filter Cable 1",
|
|
3393
|
+
type=CableTypeChoices.TYPE_CAT5E,
|
|
3394
|
+
status=self.status_connected,
|
|
3395
|
+
color="f44336",
|
|
3396
|
+
length=30,
|
|
3397
|
+
length_unit=CableLengthUnitChoices.UNIT_FOOT,
|
|
3398
|
+
)
|
|
3399
|
+
third_level_cable = Cable.objects.create(
|
|
3400
|
+
termination_a=interfaces[1],
|
|
3401
|
+
termination_b=third_level_interface,
|
|
3402
|
+
label="Test Device Filter Cable 2",
|
|
3403
|
+
type=CableTypeChoices.TYPE_CAT5E,
|
|
3404
|
+
status=self.status_connected,
|
|
3405
|
+
color="f44336",
|
|
3406
|
+
length=30,
|
|
3407
|
+
length_unit=CableLengthUnitChoices.UNIT_FOOT,
|
|
3408
|
+
)
|
|
3409
|
+
|
|
3410
|
+
with self.subTest("device_id filter"):
|
|
3411
|
+
self.assertQuerySetEqual(
|
|
3412
|
+
self.filterset({"device_id": [device.pk]}, self.queryset).qs,
|
|
3413
|
+
[top_level_cable, third_level_cable],
|
|
3414
|
+
ordered=False,
|
|
3415
|
+
)
|
|
3416
|
+
|
|
3417
|
+
with self.subTest("device filter"):
|
|
3418
|
+
self.assertQuerySetEqual(
|
|
3419
|
+
self.filterset({"device": [device.name]}, self.queryset).qs,
|
|
3420
|
+
[top_level_cable, third_level_cable],
|
|
3421
|
+
ordered=False,
|
|
3422
|
+
)
|
|
3423
|
+
|
|
3424
|
+
with self.subTest("device_id filter with an invalid uuid"):
|
|
3425
|
+
self.assertFalse(self.filterset({"device_id": [uuid.uuid4()]}, self.queryset).is_valid())
|
|
2927
3426
|
|
|
2928
3427
|
def test_rack(self):
|
|
2929
3428
|
# TODO: Not a generic_filter_test because this is a method filter.
|
|
@@ -2999,7 +3498,7 @@ class PowerPanelTestCase(FilterTestCases.FilterTestCase):
|
|
|
2999
3498
|
PowerPanel.objects.create(name="Power Panel 4", location=cls.loc1)
|
|
3000
3499
|
|
|
3001
3500
|
|
|
3002
|
-
class PowerFeedTestCase(FilterTestCases.FilterTestCase):
|
|
3501
|
+
class PowerFeedTestCase(PathEndpointModelTestMixin, FilterTestCases.FilterTestCase):
|
|
3003
3502
|
queryset = PowerFeed.objects.all()
|
|
3004
3503
|
filterset = PowerFeedFilterSet
|
|
3005
3504
|
generic_filter_tests = [
|
|
@@ -3088,28 +3587,28 @@ class PowerFeedTestCase(FilterTestCases.FilterTestCase):
|
|
|
3088
3587
|
)
|
|
3089
3588
|
|
|
3090
3589
|
def test_type(self):
|
|
3091
|
-
# TODO: Not a generic_filter_test because this
|
|
3590
|
+
# TODO: Not a generic_filter_test because this field only has 2 valid choices
|
|
3092
3591
|
params = {"type": [PowerFeedTypeChoices.TYPE_PRIMARY]}
|
|
3093
|
-
self.
|
|
3592
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
3593
|
+
self.filterset(params, self.queryset).qs,
|
|
3594
|
+
self.queryset.filter(type=PowerFeedTypeChoices.TYPE_PRIMARY),
|
|
3595
|
+
)
|
|
3094
3596
|
|
|
3095
3597
|
def test_supply(self):
|
|
3096
|
-
# TODO: Not a generic_filter_test because this
|
|
3598
|
+
# TODO: Not a generic_filter_test because this field only has 2 valid choices
|
|
3097
3599
|
params = {"supply": [PowerFeedSupplyChoices.SUPPLY_AC]}
|
|
3098
|
-
self.
|
|
3600
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
3601
|
+
self.filterset(params, self.queryset).qs,
|
|
3602
|
+
self.queryset.filter(supply=PowerFeedSupplyChoices.SUPPLY_AC),
|
|
3603
|
+
)
|
|
3099
3604
|
|
|
3100
3605
|
def test_phase(self):
|
|
3101
|
-
# TODO: Not a generic_filter_test because this
|
|
3606
|
+
# TODO: Not a generic_filter_test because this field only has 2 valid choices
|
|
3102
3607
|
params = {"phase": [PowerFeedPhaseChoices.PHASE_3PHASE]}
|
|
3103
|
-
self.
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
with self.subTest():
|
|
3108
|
-
params = {"connected": True}
|
|
3109
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
3110
|
-
with self.subTest():
|
|
3111
|
-
params = {"connected": False}
|
|
3112
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
3608
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
3609
|
+
self.filterset(params, self.queryset).qs,
|
|
3610
|
+
self.queryset.filter(phase=PowerFeedPhaseChoices.PHASE_3PHASE),
|
|
3611
|
+
)
|
|
3113
3612
|
|
|
3114
3613
|
|
|
3115
3614
|
class DeviceRedundancyGroupTestCase(FilterTestCases.FilterTestCase):
|
|
@@ -3249,7 +3748,7 @@ class InterfaceRedundancyGroupAssociationTestCase(FilterTestCases.FilterTestCase
|
|
|
3249
3748
|
|
|
3250
3749
|
statuses = Status.objects.get_for_model(InterfaceRedundancyGroup)
|
|
3251
3750
|
cls.ips = IPAddress.objects.all()
|
|
3252
|
-
cls.interfaces = Interface.objects.all()[:
|
|
3751
|
+
cls.interfaces = Interface.objects.all()[:8]
|
|
3253
3752
|
|
|
3254
3753
|
interface_redundancy_groups = (
|
|
3255
3754
|
InterfaceRedundancyGroup(
|
|
@@ -3297,8 +3796,9 @@ class InterfaceRedundancyGroupAssociationTestCase(FilterTestCases.FilterTestCase
|
|
|
3297
3796
|
interface_redundancy_groups[1].secrets_group = secrets_groups[1]
|
|
3298
3797
|
interface_redundancy_groups[1].validated_save()
|
|
3299
3798
|
|
|
3300
|
-
for i,
|
|
3301
|
-
|
|
3799
|
+
for i, group in enumerate(interface_redundancy_groups):
|
|
3800
|
+
group.add_interface(cls.interfaces[i], 100 * i)
|
|
3801
|
+
group.add_interface(cls.interfaces[i + 4], 100 * (i + 4))
|
|
3302
3802
|
|
|
3303
3803
|
|
|
3304
3804
|
class SoftwareImageFileFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
@@ -3458,3 +3958,122 @@ class ControllerManagedDeviceGroupFilterSetTestCase(FilterTestCases.FilterTestCa
|
|
|
3458
3958
|
@classmethod
|
|
3459
3959
|
def setUpTestData(cls):
|
|
3460
3960
|
common_test_data(cls)
|
|
3961
|
+
|
|
3962
|
+
|
|
3963
|
+
class ModuleTestCase(
|
|
3964
|
+
ModuleDeviceCommonTestsMixin,
|
|
3965
|
+
FilterTestCases.TenancyFilterTestCaseMixin,
|
|
3966
|
+
FilterTestCases.FilterTestCase,
|
|
3967
|
+
):
|
|
3968
|
+
queryset = Module.objects.all()
|
|
3969
|
+
filterset = ModuleFilterSet
|
|
3970
|
+
tenancy_related_name = "modules"
|
|
3971
|
+
generic_filter_tests = [
|
|
3972
|
+
("asset_tag",),
|
|
3973
|
+
("console_ports", "console_ports__id"),
|
|
3974
|
+
("console_ports", "console_ports__name"),
|
|
3975
|
+
("console_server_ports", "console_server_ports__id"),
|
|
3976
|
+
("console_server_ports", "console_server_ports__name"),
|
|
3977
|
+
("front_ports", "front_ports__id"),
|
|
3978
|
+
("front_ports", "front_ports__name"),
|
|
3979
|
+
("interfaces", "interfaces__id"),
|
|
3980
|
+
("interfaces", "interfaces__name"),
|
|
3981
|
+
("mac_address", "interfaces__mac_address"),
|
|
3982
|
+
("manufacturer", "module_type__manufacturer__id"),
|
|
3983
|
+
("manufacturer", "module_type__manufacturer__name"),
|
|
3984
|
+
("module_bays", "module_bays__id"),
|
|
3985
|
+
("module_type", "module_type__id"),
|
|
3986
|
+
("module_type", "module_type__model"),
|
|
3987
|
+
("parent_module_bay", "parent_module_bay__id"),
|
|
3988
|
+
("power_outlets", "power_outlets__id"),
|
|
3989
|
+
("power_outlets", "power_outlets__name"),
|
|
3990
|
+
("power_ports", "power_ports__id"),
|
|
3991
|
+
("power_ports", "power_ports__name"),
|
|
3992
|
+
("rear_ports", "rear_ports__id"),
|
|
3993
|
+
("rear_ports", "rear_ports__name"),
|
|
3994
|
+
("role", "role__id"),
|
|
3995
|
+
("role", "role__name"),
|
|
3996
|
+
("serial",),
|
|
3997
|
+
("status", "status__id"),
|
|
3998
|
+
("status", "status__name"),
|
|
3999
|
+
]
|
|
4000
|
+
|
|
4001
|
+
@classmethod
|
|
4002
|
+
def setUpTestData(cls):
|
|
4003
|
+
common_test_data(cls)
|
|
4004
|
+
|
|
4005
|
+
# Update existing interface objects with mac addresses for filtering
|
|
4006
|
+
interfaces = Interface.objects.filter(module__isnull=False)[:3]
|
|
4007
|
+
Interface.objects.filter(pk=interfaces[0].pk).update(mac_address="00-00-00-00-00-01")
|
|
4008
|
+
Interface.objects.filter(pk=interfaces[1].pk).update(mac_address="00-00-00-00-00-02")
|
|
4009
|
+
|
|
4010
|
+
|
|
4011
|
+
class ModuleTypeTestCase(FilterTestCases.FilterTestCase):
|
|
4012
|
+
queryset = ModuleType.objects.all()
|
|
4013
|
+
filterset = ModuleTypeFilterSet
|
|
4014
|
+
generic_filter_tests = [
|
|
4015
|
+
("manufacturer", "manufacturer__id"),
|
|
4016
|
+
("manufacturer", "manufacturer__name"),
|
|
4017
|
+
("model",),
|
|
4018
|
+
("part_number",),
|
|
4019
|
+
("console_port_templates", "console_port_templates__id"),
|
|
4020
|
+
("console_port_templates", "console_port_templates__name"),
|
|
4021
|
+
("console_server_port_templates", "console_server_port_templates__id"),
|
|
4022
|
+
("console_server_port_templates", "console_server_port_templates__name"),
|
|
4023
|
+
("power_port_templates", "power_port_templates__id"),
|
|
4024
|
+
("power_port_templates", "power_port_templates__name"),
|
|
4025
|
+
("power_outlet_templates", "power_outlet_templates__id"),
|
|
4026
|
+
("power_outlet_templates", "power_outlet_templates__name"),
|
|
4027
|
+
("interface_templates", "interface_templates__id"),
|
|
4028
|
+
("interface_templates", "interface_templates__name"),
|
|
4029
|
+
("front_port_templates", "front_port_templates__id"),
|
|
4030
|
+
("front_port_templates", "front_port_templates__name"),
|
|
4031
|
+
("rear_port_templates", "rear_port_templates__id"),
|
|
4032
|
+
("rear_port_templates", "rear_port_templates__name"),
|
|
4033
|
+
("module_bay_templates", "module_bay_templates__id"),
|
|
4034
|
+
]
|
|
4035
|
+
|
|
4036
|
+
@classmethod
|
|
4037
|
+
def setUpTestData(cls):
|
|
4038
|
+
common_test_data(cls)
|
|
4039
|
+
|
|
4040
|
+
|
|
4041
|
+
class ModuleBayTemplateTestCase(FilterTestCases.FilterTestCase):
|
|
4042
|
+
queryset = ModuleBayTemplate.objects.all()
|
|
4043
|
+
filterset = ModuleBayTemplateFilterSet
|
|
4044
|
+
generic_filter_tests = [
|
|
4045
|
+
("description",),
|
|
4046
|
+
("device_type", "device_type__id"),
|
|
4047
|
+
("device_type", "device_type__model"),
|
|
4048
|
+
("label",),
|
|
4049
|
+
("module_type", "module_type__id"),
|
|
4050
|
+
("module_type", "module_type__model"),
|
|
4051
|
+
("name",),
|
|
4052
|
+
("position",),
|
|
4053
|
+
]
|
|
4054
|
+
|
|
4055
|
+
@classmethod
|
|
4056
|
+
def setUpTestData(cls):
|
|
4057
|
+
common_test_data(cls)
|
|
4058
|
+
|
|
4059
|
+
|
|
4060
|
+
class ModuleBayTestCase(FilterTestCases.FilterTestCase):
|
|
4061
|
+
queryset = ModuleBay.objects.all()
|
|
4062
|
+
filterset = ModuleBayFilterSet
|
|
4063
|
+
generic_filter_tests = [
|
|
4064
|
+
("description",),
|
|
4065
|
+
("label",),
|
|
4066
|
+
("parent_device", "parent_device__id"),
|
|
4067
|
+
("parent_device", "parent_device__name"),
|
|
4068
|
+
("parent_module", "parent_module__id"),
|
|
4069
|
+
("installed_module", "installed_module__id"),
|
|
4070
|
+
("name",),
|
|
4071
|
+
("position",),
|
|
4072
|
+
]
|
|
4073
|
+
|
|
4074
|
+
@classmethod
|
|
4075
|
+
def setUpTestData(cls):
|
|
4076
|
+
common_test_data(cls)
|
|
4077
|
+
module_bays = ModuleBay.objects.all()[:2]
|
|
4078
|
+
module_bays[0].tags.set(Tag.objects.get_for_model(ModuleBay))
|
|
4079
|
+
module_bays[1].tags.set(Tag.objects.get_for_model(ModuleBay)[:3])
|