nautobot 2.2.9__py3-none-any.whl → 2.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/apps/forms.py +4 -0
- nautobot/apps/models.py +10 -1
- nautobot/circuits/__init__.py +0 -1
- nautobot/circuits/apps.py +1 -0
- nautobot/circuits/factory.py +15 -3
- nautobot/circuits/filters.py +13 -0
- nautobot/circuits/forms.py +13 -0
- nautobot/circuits/migrations/0021_alter_circuit_status_alter_circuittermination__path.py +32 -0
- nautobot/circuits/migrations/0022_circuittermination_cloud_network.py +25 -0
- nautobot/circuits/models.py +16 -3
- nautobot/circuits/tables.py +16 -2
- nautobot/circuits/templates/circuits/circuittermination_create.html +10 -2
- nautobot/circuits/templates/circuits/circuittermination_retrieve.html +6 -0
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -1
- nautobot/circuits/tests/test_api.py +7 -5
- nautobot/circuits/tests/test_filters.py +12 -5
- nautobot/circuits/tests/test_models.py +33 -2
- nautobot/circuits/views.py +2 -3
- nautobot/cloud/__init__.py +0 -0
- nautobot/cloud/api/__init__.py +0 -0
- nautobot/cloud/api/serializers.py +54 -0
- nautobot/cloud/api/urls.py +16 -0
- nautobot/cloud/api/views.py +48 -0
- nautobot/cloud/apps.py +13 -0
- nautobot/cloud/factory.py +113 -0
- nautobot/cloud/filters.py +187 -0
- nautobot/cloud/forms.py +339 -0
- nautobot/cloud/homepage.py +43 -0
- nautobot/cloud/migrations/0001_initial.py +304 -0
- nautobot/cloud/migrations/__init__.py +0 -0
- nautobot/cloud/models.py +246 -0
- nautobot/cloud/navigation.py +85 -0
- nautobot/cloud/tables.py +157 -0
- nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +43 -0
- nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +122 -0
- nautobot/cloud/templates/cloud/cloudnetwork_update.html +33 -0
- nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +111 -0
- nautobot/cloud/templates/cloud/cloudservice_retrieve.html +69 -0
- nautobot/cloud/templates/cloud/cloudservice_update.html +25 -0
- nautobot/cloud/tests/__init__.py +0 -0
- nautobot/cloud/tests/test_api.py +248 -0
- nautobot/cloud/tests/test_filters.py +125 -0
- nautobot/cloud/tests/test_models.py +43 -0
- nautobot/cloud/tests/test_views.py +153 -0
- nautobot/cloud/urls.py +14 -0
- nautobot/cloud/views.py +181 -0
- nautobot/core/__init__.py +0 -3
- nautobot/core/api/metadata.py +1 -0
- nautobot/core/api/parsers.py +7 -1
- nautobot/core/api/urls.py +1 -0
- nautobot/core/api/utils.py +1 -0
- nautobot/core/api/views.py +4 -0
- nautobot/core/apps/__init__.py +6 -3
- nautobot/core/constants.py +8 -0
- nautobot/core/factory.py +32 -1
- nautobot/core/filters.py +95 -13
- nautobot/core/forms/fields.py +10 -4
- nautobot/core/forms/forms.py +11 -3
- nautobot/core/forms/widgets.py +18 -1
- nautobot/core/graphql/schema.py +26 -4
- nautobot/core/jobs/__init__.py +16 -2
- nautobot/core/jobs/cleanup.py +100 -0
- nautobot/core/jobs/groups.py +38 -0
- nautobot/core/management/commands/generate_test_data.py +116 -3
- nautobot/core/models/__init__.py +34 -9
- nautobot/core/models/generics.py +19 -3
- nautobot/core/models/name_color_content_types.py +7 -28
- nautobot/core/models/querysets.py +4 -3
- nautobot/core/models/tree_queries.py +1 -1
- nautobot/core/models/utils.py +21 -5
- nautobot/core/settings.py +2 -17
- nautobot/core/settings.yaml +34 -13
- nautobot/core/settings_funcs.py +103 -0
- nautobot/core/tables.py +130 -56
- nautobot/core/templates/admin/search_form.html +1 -1
- nautobot/core/templates/buttons/add.html +11 -3
- nautobot/core/templates/buttons/consolidated_bulk_action_buttons.html +13 -0
- nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +13 -0
- nautobot/core/templates/buttons/export.html +101 -53
- nautobot/core/templates/buttons/job_import.html +11 -3
- nautobot/core/templates/generic/object_bulk_destroy.html +3 -1
- nautobot/core/templates/generic/object_bulk_update.html +3 -1
- nautobot/core/templates/generic/object_changelog.html +0 -9
- nautobot/core/templates/generic/object_list.html +156 -17
- nautobot/core/templates/generic/object_retrieve.html +80 -16
- nautobot/core/templates/inc/extras_features_edit_form_fields.html +8 -0
- nautobot/core/templates/inc/javascript.html +2 -0
- nautobot/core/templates/inc/media.html +2 -2
- nautobot/core/templates/inc/nav_menu.html +1 -0
- nautobot/core/templates/inc/paginator.html +7 -7
- nautobot/core/templates/inc/search_panel.html +2 -2
- nautobot/core/templates/inc/table.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +13 -8
- nautobot/core/templates/utilities/templatetags/dynamic_group_assignment_modal.html +37 -0
- nautobot/core/templates/utilities/templatetags/filter_form_modal.html +2 -2
- nautobot/core/templates/utilities/templatetags/saved_view_modal.html +38 -0
- nautobot/core/templates/utilities/theme_preview.html +25 -8
- nautobot/core/templates/utilities/worker_status.html +152 -0
- nautobot/core/templatetags/buttons.py +335 -38
- nautobot/core/templatetags/form_helpers.py +1 -1
- nautobot/core/templatetags/helpers.py +181 -11
- nautobot/core/testing/api.py +5 -4
- nautobot/core/testing/filters.py +63 -14
- nautobot/core/testing/mixins.py +46 -0
- nautobot/core/testing/models.py +22 -0
- nautobot/core/testing/schema.py +4 -8
- nautobot/core/testing/views.py +31 -14
- nautobot/core/tests/integration/test_import_objects_ui.py +1 -0
- nautobot/core/tests/integration/test_swagger.py +1 -1
- nautobot/core/tests/nautobot_config.py +0 -1
- nautobot/core/tests/runner.py +2 -2
- nautobot/core/tests/test_api.py +1 -0
- nautobot/core/tests/test_authentication.py +7 -2
- nautobot/core/tests/test_filters.py +11 -9
- nautobot/core/tests/test_forms.py +9 -0
- nautobot/core/tests/test_graphql.py +27 -16
- nautobot/core/tests/test_jobs.py +122 -0
- nautobot/core/tests/test_tables.py +3 -1
- nautobot/core/tests/test_templatetags_helpers.py +12 -5
- nautobot/core/tests/test_utils.py +31 -20
- nautobot/core/tests/test_views.py +6 -6
- nautobot/core/urls.py +8 -3
- nautobot/core/utils/deprecation.py +29 -0
- nautobot/core/utils/filtering.py +12 -9
- nautobot/core/utils/lookup.py +37 -2
- nautobot/core/utils/requests.py +4 -1
- nautobot/core/views/__init__.py +137 -24
- nautobot/core/views/generic.py +119 -67
- nautobot/core/views/mixins.py +105 -36
- nautobot/core/views/paginator.py +9 -3
- nautobot/core/views/renderers.py +121 -56
- nautobot/core/views/utils.py +81 -1
- nautobot/dcim/__init__.py +0 -1
- nautobot/dcim/api/serializers.py +180 -44
- nautobot/dcim/api/urls.py +7 -3
- nautobot/dcim/api/views.py +53 -7
- nautobot/dcim/apps.py +3 -0
- nautobot/dcim/choices.py +25 -0
- nautobot/dcim/constants.py +7 -0
- nautobot/dcim/factory.py +252 -18
- nautobot/dcim/filters/__init__.py +373 -193
- nautobot/dcim/filters/mixins.py +274 -1
- nautobot/dcim/forms.py +834 -121
- nautobot/dcim/graphql/types.py +2 -2
- nautobot/dcim/homepage.py +1 -1
- nautobot/dcim/migrations/0059_add_role_field_to_interface_models.py +27 -0
- nautobot/dcim/migrations/0060_alter_cable_status_alter_consoleport__path_and_more.py +303 -0
- nautobot/dcim/migrations/0061_module_models.py +862 -0
- nautobot/dcim/migrations/0062_module_data_migration.py +25 -0
- nautobot/dcim/models/__init__.py +8 -0
- nautobot/dcim/models/cables.py +15 -0
- nautobot/dcim/models/device_component_templates.py +207 -53
- nautobot/dcim/models/device_components.py +275 -99
- nautobot/dcim/models/devices.py +468 -13
- nautobot/dcim/models/racks.py +0 -1
- nautobot/dcim/navigation.py +47 -0
- nautobot/dcim/signals.py +3 -3
- nautobot/dcim/tables/__init__.py +35 -23
- nautobot/dcim/tables/devices.py +229 -43
- nautobot/dcim/tables/devicetypes.py +65 -9
- nautobot/dcim/tables/racks.py +5 -1
- nautobot/dcim/tables/template_code.py +46 -26
- nautobot/dcim/templates/dcim/cable_connect.html +76 -3
- nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -5
- nautobot/dcim/templates/dcim/device/base.html +14 -6
- nautobot/dcim/templates/dcim/device/consoleports.html +2 -3
- nautobot/dcim/templates/dcim/device/consoleserverports.html +2 -3
- nautobot/dcim/templates/dcim/device/devicebays.html +6 -7
- nautobot/dcim/templates/dcim/device/frontports.html +2 -3
- nautobot/dcim/templates/dcim/device/interfaces.html +2 -3
- nautobot/dcim/templates/dcim/device/inventory.html +2 -3
- nautobot/dcim/templates/dcim/device/modulebays.html +49 -0
- nautobot/dcim/templates/dcim/device/poweroutlets.html +2 -3
- nautobot/dcim/templates/dcim/device/powerports.html +2 -3
- nautobot/dcim/templates/dcim/device/rearports.html +2 -3
- nautobot/dcim/templates/dcim/device.html +45 -1
- nautobot/dcim/templates/dcim/device_component.html +13 -5
- nautobot/dcim/templates/dcim/device_list.html +2 -1
- nautobot/dcim/templates/dcim/devicetype.html +99 -98
- nautobot/dcim/templates/dcim/devicetype_list.html +8 -16
- nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
- nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +39 -0
- nautobot/dcim/templates/dcim/interface.html +17 -2
- nautobot/dcim/templates/dcim/interface_connection_list.html +7 -5
- nautobot/dcim/templates/dcim/interface_edit.html +1 -0
- nautobot/dcim/templates/dcim/manufacturer.html +24 -0
- nautobot/dcim/templates/dcim/module/base.html +97 -0
- nautobot/dcim/templates/dcim/module_bulk_destroy.html +5 -0
- nautobot/dcim/templates/dcim/module_consoleports.html +53 -0
- nautobot/dcim/templates/dcim/module_consoleserverports.html +53 -0
- nautobot/dcim/templates/dcim/module_destroy.html +5 -0
- nautobot/dcim/templates/dcim/module_frontports.html +53 -0
- nautobot/dcim/templates/dcim/module_interfaces.html +57 -0
- nautobot/dcim/templates/dcim/module_list.html +20 -0
- nautobot/dcim/templates/dcim/module_modulebays.html +49 -0
- nautobot/dcim/templates/dcim/module_poweroutlets.html +53 -0
- nautobot/dcim/templates/dcim/module_powerports.html +53 -0
- nautobot/dcim/templates/dcim/module_rearports.html +53 -0
- nautobot/dcim/templates/dcim/module_retrieve.html +63 -0
- nautobot/dcim/templates/dcim/module_update.html +71 -0
- nautobot/dcim/templates/dcim/modulebay_bulk_destroy.html +5 -0
- nautobot/dcim/templates/dcim/modulebay_destroy.html +8 -0
- nautobot/dcim/templates/dcim/modulebay_retrieve.html +101 -0
- nautobot/dcim/templates/dcim/moduletype_list.html +11 -0
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +159 -0
- nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -5
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +65 -19
- nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
- nautobot/dcim/tests/test_api.py +693 -208
- nautobot/dcim/tests/test_filters.py +843 -217
- nautobot/dcim/tests/test_models.py +1072 -8
- nautobot/dcim/tests/test_views.py +1510 -341
- nautobot/dcim/urls.py +17 -2
- nautobot/dcim/utils.py +2 -3
- nautobot/dcim/views.py +1106 -116
- nautobot/extras/__init__.py +0 -1
- nautobot/extras/api/serializers.py +115 -3
- nautobot/extras/api/urls.py +12 -0
- nautobot/extras/api/views.py +66 -0
- nautobot/extras/apps.py +2 -2
- nautobot/extras/choices.py +43 -0
- nautobot/extras/context_managers.py +13 -8
- nautobot/extras/datasources/git.py +2 -0
- nautobot/extras/factory.py +460 -9
- nautobot/extras/filters/__init__.py +174 -3
- nautobot/extras/filters/mixins.py +46 -43
- nautobot/extras/forms/base.py +24 -5
- nautobot/extras/forms/forms.py +227 -8
- nautobot/extras/forms/mixins.py +93 -0
- nautobot/extras/graphql/types.py +23 -10
- nautobot/extras/homepage.py +14 -1
- nautobot/extras/management/__init__.py +1 -0
- nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +1 -16
- nautobot/extras/migrations/0021_customfield_changelog_data.py +1 -0
- nautobot/extras/migrations/0109_dynamicgroup_group_type_dynamicgroup_tags_and_more.py +108 -0
- nautobot/extras/migrations/0110_alter_configcontext_cluster_groups_and_more.py +111 -0
- nautobot/extras/migrations/0111_metadata.py +162 -0
- nautobot/extras/migrations/0112_dynamic_group_group_type_data_migration.py +28 -0
- nautobot/extras/migrations/0113_saved_views.py +77 -0
- nautobot/extras/models/__init__.py +15 -1
- nautobot/extras/models/change_logging.py +3 -3
- nautobot/extras/models/contacts.py +4 -0
- nautobot/extras/models/customfields.py +18 -3
- nautobot/extras/models/groups.py +389 -225
- nautobot/extras/models/jobs.py +6 -3
- nautobot/extras/models/metadata.py +441 -0
- nautobot/extras/models/mixins.py +72 -62
- nautobot/extras/models/models.py +118 -9
- nautobot/extras/models/relationships.py +9 -2
- nautobot/extras/models/tags.py +13 -2
- nautobot/extras/navigation.py +57 -0
- nautobot/extras/plugins/__init__.py +3 -1
- nautobot/extras/querysets.py +30 -66
- nautobot/extras/signals.py +95 -100
- nautobot/extras/tables.py +165 -12
- nautobot/extras/templates/extras/dynamicgroup.html +44 -15
- nautobot/extras/templates/extras/dynamicgroup_edit.html +2 -0
- nautobot/extras/templates/extras/job.html +1 -1
- nautobot/extras/templates/extras/jobresult.html +61 -74
- nautobot/extras/templates/extras/metadatatype_create.html +89 -0
- nautobot/extras/templates/extras/metadatatype_retrieve.html +67 -0
- nautobot/extras/templates/extras/object_dynamicgroups.html +7 -0
- nautobot/extras/templates/extras/objectchange_list.html +0 -12
- nautobot/extras/templates/extras/plugins_list.html +1 -3
- nautobot/extras/templates/extras/role_retrieve.html +48 -0
- nautobot/extras/templates/extras/staticgroupassociation_retrieve.html +20 -0
- nautobot/extras/tests/integration/test_customfields.py +1 -0
- nautobot/extras/tests/test_api.py +509 -23
- nautobot/extras/tests/test_changelog.py +20 -9
- nautobot/extras/tests/test_context_managers.py +22 -15
- nautobot/extras/tests/test_datasources.py +13 -1
- nautobot/extras/tests/test_dynamicgroups.py +201 -171
- nautobot/extras/tests/test_filters.py +211 -12
- nautobot/extras/tests/test_jobs.py +6 -6
- nautobot/extras/tests/test_models.py +501 -4
- nautobot/extras/tests/test_relationships.py +1 -0
- nautobot/extras/tests/test_views.py +565 -8
- nautobot/extras/tests/test_webhooks.py +1 -1
- nautobot/extras/urls.py +5 -0
- nautobot/extras/utils.py +51 -11
- nautobot/extras/views.py +542 -76
- nautobot/ipam/__init__.py +0 -1
- nautobot/ipam/apps.py +1 -0
- nautobot/ipam/factory.py +17 -19
- nautobot/ipam/filters.py +13 -0
- nautobot/ipam/forms.py +8 -4
- nautobot/ipam/graphql/types.py +2 -2
- nautobot/ipam/migrations/0047_alter_ipaddress_role_alter_ipaddress_status_and_more.py +59 -0
- nautobot/ipam/models.py +11 -8
- nautobot/ipam/querysets.py +1 -1
- nautobot/ipam/signals.py +4 -2
- nautobot/ipam/tables.py +5 -0
- nautobot/ipam/templates/ipam/ipaddress_interfaces.html +1 -1
- nautobot/ipam/templates/ipam/ipaddress_vm_interfaces.html +1 -1
- nautobot/ipam/templates/ipam/prefix.html +1 -0
- nautobot/ipam/tests/test_api.py +37 -18
- nautobot/ipam/tests/test_filters.py +26 -2
- nautobot/ipam/tests/test_models.py +6 -0
- nautobot/ipam/tests/test_querysets.py +1 -1
- nautobot/ipam/tests/test_views.py +3 -2
- nautobot/ipam/urls.py +2 -2
- nautobot/ipam/views.py +18 -26
- nautobot/project-static/css/base.css +20 -0
- nautobot/project-static/css/dark.css +11 -0
- nautobot/project-static/docs/404.html +892 -88
- nautobot/project-static/docs/apps/index.html +892 -88
- nautobot/project-static/docs/apps/nautobot-apps.html +892 -88
- nautobot/project-static/docs/assets/_mkdocstrings.css +5 -0
- nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +919 -120
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +904 -101
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1618 -903
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +935 -144
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +977 -188
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +901 -99
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +897 -93
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +991 -193
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +974 -131
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +1078 -272
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1242 -334
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1727 -875
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +1164 -381
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2088 -1374
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2246 -1422
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +912 -111
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +963 -163
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1010 -223
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +1913 -1277
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1846 -1102
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +904 -101
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +2331 -1699
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +1802 -1024
- nautobot/project-static/docs/development/apps/api/configuration-view.html +892 -88
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +892 -88
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +892 -88
- nautobot/project-static/docs/development/apps/api/models/global-search.html +892 -88
- nautobot/project-static/docs/development/apps/api/models/graphql.html +892 -88
- nautobot/project-static/docs/development/apps/api/models/index.html +942 -90
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +892 -88
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +892 -88
- nautobot/project-static/docs/development/apps/api/prometheus.html +892 -88
- nautobot/project-static/docs/development/apps/api/setup.html +892 -88
- nautobot/project-static/docs/development/apps/api/testing.html +892 -88
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +892 -88
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +892 -88
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +892 -88
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +892 -88
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/base-template.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/index.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/notes.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +892 -88
- nautobot/project-static/docs/development/apps/api/views/urls.html +892 -88
- nautobot/project-static/docs/development/apps/index.html +892 -88
- nautobot/project-static/docs/development/apps/migration/code-updates.html +892 -88
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +892 -88
- nautobot/project-static/docs/development/apps/migration/from-v1.html +892 -88
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +892 -88
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +892 -88
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +892 -88
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +892 -88
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +892 -88
- nautobot/project-static/docs/development/core/application-registry.html +892 -88
- nautobot/project-static/docs/development/core/best-practices.html +893 -88
- nautobot/project-static/docs/development/core/bootstrap-ui.html +892 -88
- nautobot/project-static/docs/development/core/caching.html +892 -88
- nautobot/project-static/docs/development/core/controllers.html +892 -88
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +892 -88
- nautobot/project-static/docs/development/core/generic-views.html +892 -88
- nautobot/project-static/docs/development/core/getting-started.html +892 -88
- nautobot/project-static/docs/development/core/homepage.html +892 -88
- nautobot/project-static/docs/development/core/index.html +892 -88
- nautobot/project-static/docs/development/core/model-checklist.html +901 -89
- nautobot/project-static/docs/development/core/model-features.html +892 -88
- nautobot/project-static/docs/development/core/natural-keys.html +892 -88
- nautobot/project-static/docs/development/core/navigation-menu.html +892 -88
- nautobot/project-static/docs/development/core/release-checklist.html +895 -91
- nautobot/project-static/docs/development/core/role-internals.html +892 -88
- nautobot/project-static/docs/development/core/settings.html +892 -88
- nautobot/project-static/docs/development/core/style-guide.html +893 -89
- nautobot/project-static/docs/development/core/templates.html +904 -89
- nautobot/project-static/docs/development/core/testing.html +892 -88
- nautobot/project-static/docs/development/core/user-preferences.html +892 -88
- nautobot/project-static/docs/development/index.html +892 -88
- nautobot/project-static/docs/development/jobs/index.html +893 -89
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +892 -88
- nautobot/project-static/docs/index.html +892 -88
- nautobot/project-static/docs/media/models/cloud_aws_direct_connect_dark.png +0 -0
- nautobot/project-static/docs/media/models/cloud_aws_direct_connect_light.png +0 -0
- nautobot/project-static/docs/models/cloud/cloudaccount.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudnetwork.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudnetworkprefixassignment.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudresourcetype.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudservice.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudservicenetworkassignment.html +15 -0
- nautobot/project-static/docs/models/dcim/module.html +15 -0
- nautobot/project-static/docs/models/dcim/modulebay.html +15 -0
- nautobot/project-static/docs/models/dcim/modulebaytemplate.html +15 -0
- nautobot/project-static/docs/models/dcim/moduletype.html +15 -0
- nautobot/project-static/docs/models/extras/metadatachoice.html +15 -0
- nautobot/project-static/docs/models/extras/metadatatype.html +15 -0
- nautobot/project-static/docs/models/extras/objectmetadata.html +15 -0
- nautobot/project-static/docs/models/extras/role.html +15 -0
- nautobot/project-static/docs/models/extras/savedview.html +15 -0
- nautobot/project-static/docs/models/extras/staticgroupassociation.html +15 -0
- nautobot/project-static/docs/models/extras/status.html +15 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +900 -89
- nautobot/project-static/docs/overview/design_philosophy.html +892 -88
- nautobot/project-static/docs/release-notes/index.html +1129 -92
- nautobot/project-static/docs/release-notes/version-1.0.html +892 -88
- nautobot/project-static/docs/release-notes/version-1.1.html +892 -88
- nautobot/project-static/docs/release-notes/version-1.2.html +892 -88
- nautobot/project-static/docs/release-notes/version-1.3.html +892 -88
- nautobot/project-static/docs/release-notes/version-1.4.html +892 -88
- nautobot/project-static/docs/release-notes/version-1.5.html +893 -89
- nautobot/project-static/docs/release-notes/version-1.6.html +893 -89
- nautobot/project-static/docs/release-notes/version-2.0.html +892 -88
- nautobot/project-static/docs/release-notes/version-2.1.html +892 -88
- nautobot/project-static/docs/release-notes/version-2.2.html +895 -91
- nautobot/project-static/docs/release-notes/version-2.3.html +9954 -0
- nautobot/project-static/docs/requirements.txt +5 -5
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +331 -256
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +892 -88
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +892 -88
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +892 -88
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +892 -88
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +992 -174
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +892 -88
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +896 -88
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +892 -88
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +892 -88
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +892 -88
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +892 -88
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +944 -153
- nautobot/project-static/docs/user-guide/administration/installation/index.html +901 -93
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +934 -122
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +954 -157
- nautobot/project-static/docs/user-guide/administration/installation/services.html +913 -112
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +908 -99
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +892 -88
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +892 -88
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +892 -88
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +892 -88
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +893 -89
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +892 -88
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +893 -89
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +896 -88
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +895 -91
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +8984 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +8829 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +8829 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +8833 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +923 -105
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +923 -105
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +918 -100
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +923 -105
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +913 -105
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +920 -116
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +921 -117
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +918 -114
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +914 -105
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +926 -108
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +936 -118
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +928 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +937 -119
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +928 -110
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +918 -114
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +921 -117
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +923 -115
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +8846 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +8843 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +8823 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +916 -112
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +940 -83
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +924 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +943 -86
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +921 -103
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +929 -125
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +918 -114
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +922 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +924 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +906 -102
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +936 -88
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +897 -89
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +897 -89
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +901 -96
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +892 -88
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +897 -89
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/clear-view-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/cleared-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/config-table-columns-to-locations.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/configure-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/create-saved-view-success.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/current-saved-view-drop-down-menu.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/default-location-list-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/dropdown-button-after-new-saved-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-application-to-locations.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/global-default-location-list-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/location-list-view-with-saved-views.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/navigation-menu.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-as-new-view-drop-down.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-view-modal.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-buttons.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-success.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view-unchecked.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-different-user.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-modal-unchecked.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-success.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/unsaved-saved-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/updated-saved-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +892 -88
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +892 -88
- nautobot/project-static/docs/user-guide/index.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +1258 -785
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +895 -91
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +896 -88
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +895 -91
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +9061 -0
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +895 -91
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +895 -91
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +9137 -0
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +895 -91
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +8933 -0
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +950 -121
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +892 -88
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +892 -88
- nautobot/project-static/js/forms.js +71 -0
- nautobot/project-static/js/table_sorting_indicator.js +46 -0
- nautobot/project-static/js/tableconfig.js +6 -1
- nautobot/project-static/materialdesignicons-7.4.47/css/materialdesignicons.min.css +3 -0
- nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.eot +0 -0
- nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.ttf +0 -0
- nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff +0 -0
- nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff2 +0 -0
- nautobot/tenancy/__init__.py +0 -1
- nautobot/tenancy/apps.py +1 -0
- nautobot/tenancy/factory.py +3 -2
- nautobot/tenancy/filters/__init__.py +1 -0
- nautobot/tenancy/forms.py +1 -1
- nautobot/tenancy/templates/tenancy/tenant.html +24 -20
- nautobot/tenancy/views.py +11 -10
- nautobot/users/__init__.py +0 -1
- nautobot/users/api/serializers.py +1 -1
- nautobot/users/api/views.py +4 -2
- nautobot/users/apps.py +3 -2
- nautobot/users/factory.py +3 -3
- nautobot/users/migrations/0010_user_default_saved_views.py +20 -0
- nautobot/users/models.py +12 -0
- nautobot/users/tests/test_filters.py +6 -3
- nautobot/users/urls.py +8 -0
- nautobot/virtualization/__init__.py +0 -1
- nautobot/virtualization/apps.py +1 -0
- nautobot/virtualization/filters.py +6 -1
- nautobot/virtualization/forms.py +11 -3
- nautobot/virtualization/graphql/types.py +2 -2
- nautobot/virtualization/migrations/0029_add_role_field_to_interface_models.py +27 -0
- nautobot/virtualization/migrations/0030_alter_virtualmachine_local_config_context_data_owner_content_type_and_more.py +67 -0
- nautobot/virtualization/models.py +0 -2
- nautobot/virtualization/tables.py +10 -3
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
- nautobot/virtualization/templates/virtualization/vminterface.html +7 -1
- nautobot/virtualization/templates/virtualization/vminterface_edit.html +1 -0
- nautobot/virtualization/tests/test_api.py +9 -4
- nautobot/virtualization/tests/test_filters.py +22 -0
- nautobot/virtualization/tests/test_models.py +7 -3
- nautobot/virtualization/tests/test_views.py +19 -3
- nautobot/virtualization/urls.py +2 -2
- nautobot/virtualization/views.py +10 -32
- {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/METADATA +20 -18
- {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/RECORD +677 -557
- nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css.map +0 -1
- nautobot/project-static/materialdesignicons-6.5.95/.github/ISSUE_TEMPLATE.md +0 -3
- nautobot/project-static/materialdesignicons-6.5.95/README.md +0 -25
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css +0 -26654
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css.map +0 -16
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css +0 -3
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css.map +0 -16
- nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff +0 -0
- nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff2 +0 -0
- nautobot/project-static/materialdesignicons-6.5.95/package.json +0 -28
- nautobot/project-static/materialdesignicons-6.5.95/preview.html +0 -717
- nautobot/project-static/materialdesignicons-6.5.95/scss/_animated.scss +0 -27
- nautobot/project-static/materialdesignicons-6.5.95/scss/_core.scss +0 -10
- nautobot/project-static/materialdesignicons-6.5.95/scss/_extras.scss +0 -65
- nautobot/project-static/materialdesignicons-6.5.95/scss/_functions.scss +0 -20
- nautobot/project-static/materialdesignicons-6.5.95/scss/_icons.scss +0 -10
- nautobot/project-static/materialdesignicons-6.5.95/scss/_path.scss +0 -10
- nautobot/project-static/materialdesignicons-6.5.95/scss/_variables.scss +0 -6606
- nautobot/project-static/materialdesignicons-6.5.95/scss/materialdesignicons.scss +0 -8
- /nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/LICENSE +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/NOTICE +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/WHEEL +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/entry_points.txt +0 -0
|
@@ -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,121 @@ 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(
|
|
660
|
+
manufacturer=cls.manufacturers[0], model="Filter Test Module Type 1", comments="Module Type 1"
|
|
661
|
+
),
|
|
662
|
+
ModuleType.objects.create(
|
|
663
|
+
manufacturer=cls.manufacturers[1], model="Filter Test Module Type 2", comments="Module Type 2"
|
|
664
|
+
),
|
|
665
|
+
ModuleType.objects.create(
|
|
666
|
+
manufacturer=cls.manufacturers[2], model="Filter Test Module Type 3", comments="Module Type 3"
|
|
667
|
+
),
|
|
668
|
+
)
|
|
669
|
+
|
|
670
|
+
# Create 3 of each component template on the first two module types
|
|
671
|
+
for i in range(6):
|
|
672
|
+
ConsolePortTemplate.objects.create(
|
|
673
|
+
name=f"Test Filters Module Console Port {i+1}",
|
|
674
|
+
module_type=module_types[i % 2],
|
|
675
|
+
)
|
|
676
|
+
ConsoleServerPortTemplate.objects.create(
|
|
677
|
+
name=f"Test Filters Module Console Server Port {i+1}",
|
|
678
|
+
module_type=module_types[i % 2],
|
|
679
|
+
)
|
|
680
|
+
ppt = PowerPortTemplate.objects.create(
|
|
681
|
+
name=f"Test Filters Module Power Port {i+1}",
|
|
682
|
+
module_type=module_types[i % 2],
|
|
683
|
+
)
|
|
684
|
+
PowerOutletTemplate.objects.create(
|
|
685
|
+
name=f"Test Filters Module Power Outlet {i+1}",
|
|
686
|
+
power_port_template=ppt,
|
|
687
|
+
module_type=module_types[i % 2],
|
|
688
|
+
)
|
|
689
|
+
InterfaceTemplate.objects.create(
|
|
690
|
+
name=f"Test Filters Module Interface {i+1}",
|
|
691
|
+
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
692
|
+
module_type=module_types[i % 2],
|
|
693
|
+
)
|
|
694
|
+
rpt = RearPortTemplate.objects.create(
|
|
695
|
+
name=f"Test Filters Module Rear Port {i+1}",
|
|
696
|
+
module_type=module_types[i % 2],
|
|
697
|
+
type=PortTypeChoices.TYPE_8P8C,
|
|
698
|
+
positions=10,
|
|
699
|
+
)
|
|
700
|
+
FrontPortTemplate.objects.create(
|
|
701
|
+
name=f"Test Filters Module Front Port {i+1}",
|
|
702
|
+
module_type=module_types[i % 2],
|
|
703
|
+
rear_port_template=rpt,
|
|
704
|
+
rear_port_position=i + 1,
|
|
705
|
+
type=PortTypeChoices.TYPE_8P8C,
|
|
706
|
+
)
|
|
707
|
+
ModuleBayTemplate.objects.create(
|
|
708
|
+
name=f"Test Filters Module Module Bay {i+1}",
|
|
709
|
+
position=i + 1,
|
|
710
|
+
module_type=module_types[i % 2],
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
module_roles = Role.objects.get_for_model(Module)
|
|
714
|
+
cls.module_statuses = Status.objects.get_for_model(Module)
|
|
715
|
+
cls.modules = (
|
|
716
|
+
Module.objects.create(
|
|
717
|
+
module_type=module_types[0],
|
|
718
|
+
status=cls.module_statuses[0],
|
|
719
|
+
asset_tag="Test Filter Asset Tag Module1",
|
|
720
|
+
serial="Test Filter Serial Module1",
|
|
721
|
+
role=module_roles[0],
|
|
722
|
+
tenant=tenants[0],
|
|
723
|
+
parent_module_bay=cls.devices[0].module_bays.first(),
|
|
724
|
+
),
|
|
725
|
+
Module.objects.create(
|
|
726
|
+
module_type=module_types[1],
|
|
727
|
+
status=cls.module_statuses[0],
|
|
728
|
+
asset_tag="Test Filter Asset Tag Module2",
|
|
729
|
+
serial="Test Filter Serial Module2",
|
|
730
|
+
role=module_roles[0],
|
|
731
|
+
tenant=tenants[1],
|
|
732
|
+
parent_module_bay=cls.devices[1].module_bays.first(),
|
|
733
|
+
),
|
|
734
|
+
Module.objects.create(
|
|
735
|
+
module_type=module_types[2],
|
|
736
|
+
status=cls.module_statuses[0],
|
|
737
|
+
asset_tag="Test Filter Asset Tag Module3",
|
|
738
|
+
serial="Test Filter Serial Module3",
|
|
739
|
+
role=module_roles[1],
|
|
740
|
+
tenant=tenants[2],
|
|
741
|
+
parent_module_bay=cls.devices[2].module_bays.first(),
|
|
742
|
+
),
|
|
743
|
+
)
|
|
744
|
+
cls.modules[0].tags.set(Tag.objects.get_for_model(Module))
|
|
745
|
+
cls.modules[1].tags.set(Tag.objects.get_for_model(Module)[:3])
|
|
746
|
+
|
|
747
|
+
Module.objects.create(
|
|
748
|
+
module_type=module_types[0],
|
|
749
|
+
status=cls.module_statuses[1],
|
|
750
|
+
asset_tag="Test Filter Asset Tag Module4",
|
|
751
|
+
serial="Test Filter Serial Module4",
|
|
752
|
+
role=module_roles[1],
|
|
753
|
+
tenant=tenants[0],
|
|
754
|
+
parent_module_bay=cls.modules[0].module_bays.first(),
|
|
755
|
+
)
|
|
756
|
+
Module.objects.create(
|
|
757
|
+
module_type=module_types[1],
|
|
758
|
+
status=cls.module_statuses[1],
|
|
759
|
+
asset_tag="Test Filter Asset Tag Module5",
|
|
760
|
+
serial="Test Filter Serial Module5",
|
|
761
|
+
tenant=tenants[1],
|
|
762
|
+
parent_module_bay=cls.modules[1].module_bays.first(),
|
|
763
|
+
)
|
|
764
|
+
Module.objects.create(
|
|
765
|
+
module_type=module_types[2],
|
|
766
|
+
status=cls.module_statuses[1],
|
|
767
|
+
asset_tag="Test Filter Asset Tag Module6",
|
|
768
|
+
serial="Test Filter Serial Module6",
|
|
769
|
+
tenant=tenants[2],
|
|
770
|
+
parent_module_bay=cls.modules[1].module_bays.last(),
|
|
771
|
+
)
|
|
772
|
+
|
|
627
773
|
cls.controllers = (
|
|
628
774
|
Controller.objects.create(
|
|
629
775
|
name="Controller 1",
|
|
@@ -697,6 +843,157 @@ def common_test_data(cls):
|
|
|
697
843
|
cls.controller_managed_device_groups[1].tags.set(Tag.objects.get_for_model(ControllerManagedDeviceGroup)[:3])
|
|
698
844
|
|
|
699
845
|
|
|
846
|
+
class ComponentTemplateTestMixin:
|
|
847
|
+
generic_filter_tests = [
|
|
848
|
+
("description",),
|
|
849
|
+
("device_type", "device_type__id"),
|
|
850
|
+
("device_type", "device_type__model"),
|
|
851
|
+
("label",),
|
|
852
|
+
("name",),
|
|
853
|
+
]
|
|
854
|
+
|
|
855
|
+
@classmethod
|
|
856
|
+
def setUpTestData(cls):
|
|
857
|
+
common_test_data(cls)
|
|
858
|
+
|
|
859
|
+
|
|
860
|
+
class ModularComponentTemplateTestMixin(ComponentTemplateTestMixin):
|
|
861
|
+
generic_filter_tests = [
|
|
862
|
+
*ComponentTemplateTestMixin.generic_filter_tests,
|
|
863
|
+
("module_type", "module_type__id"),
|
|
864
|
+
("module_type", "module_type__model"),
|
|
865
|
+
]
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
class DeviceComponentTestMixin:
|
|
869
|
+
generic_filter_tests = [
|
|
870
|
+
("description",),
|
|
871
|
+
("device", "device__id"),
|
|
872
|
+
("device", "device__name"),
|
|
873
|
+
("label",),
|
|
874
|
+
("name",),
|
|
875
|
+
]
|
|
876
|
+
|
|
877
|
+
@classmethod
|
|
878
|
+
def setUpTestData(cls):
|
|
879
|
+
common_test_data(cls)
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
class ModularDeviceComponentTestMixin(DeviceComponentTestMixin):
|
|
883
|
+
generic_filter_tests = [
|
|
884
|
+
("description",),
|
|
885
|
+
("label",),
|
|
886
|
+
("name",),
|
|
887
|
+
("module", "module__id"),
|
|
888
|
+
("module", "module__module_type__model"),
|
|
889
|
+
]
|
|
890
|
+
|
|
891
|
+
def test_device(self):
|
|
892
|
+
"""Test that the device filter returns all components for a device and its modules."""
|
|
893
|
+
model = self.queryset.model._meta.model_name
|
|
894
|
+
manufacturer = Manufacturer.objects.first()
|
|
895
|
+
device_type = DeviceType.objects.create(
|
|
896
|
+
manufacturer=manufacturer, model=f"Test Device Filter for {model} Device Type"
|
|
897
|
+
)
|
|
898
|
+
device = Device.objects.create(
|
|
899
|
+
device_type=device_type,
|
|
900
|
+
name=f"Test Device Filter for {model} Device",
|
|
901
|
+
location=self.loc0,
|
|
902
|
+
role=self.device_roles[0],
|
|
903
|
+
status=Status.objects.get_for_model(Device).first(),
|
|
904
|
+
)
|
|
905
|
+
parent_module_bay = ModuleBay.objects.create(name="Parent module bay", position="1", parent_device=device)
|
|
906
|
+
module_type = ModuleType.objects.create(
|
|
907
|
+
manufacturer=manufacturer, model=f"Test Device Filter for {model} Module Type", comments="Module Type test"
|
|
908
|
+
)
|
|
909
|
+
module = Module.objects.create(
|
|
910
|
+
module_type=module_type, parent_module_bay=parent_module_bay, status=self.module_statuses[0]
|
|
911
|
+
)
|
|
912
|
+
child_module_bay = ModuleBay.objects.create(name="Child module bay", position="1", parent_module=module)
|
|
913
|
+
child_module = Module.objects.create(
|
|
914
|
+
module_type=module_type, parent_module_bay=child_module_bay, status=self.module_statuses[0]
|
|
915
|
+
)
|
|
916
|
+
top_level_component = self.queryset.create(device=device, name=f"Top level {model}")
|
|
917
|
+
second_level_component = self.queryset.create(module=module, name=f"Second level {model}")
|
|
918
|
+
third_level_component = self.queryset.create(module=child_module, name=f"Third level {model}")
|
|
919
|
+
with self.subTest("device filter (pk)"):
|
|
920
|
+
self.assertQuerySetEqual(
|
|
921
|
+
self.filterset({"device": [device.pk]}, self.queryset).qs,
|
|
922
|
+
[top_level_component, second_level_component, third_level_component],
|
|
923
|
+
ordered=False,
|
|
924
|
+
)
|
|
925
|
+
with self.subTest("device filter (name)"):
|
|
926
|
+
self.assertQuerySetEqual(
|
|
927
|
+
self.filterset({"device": [device.name]}, self.queryset).qs,
|
|
928
|
+
[top_level_component, second_level_component, third_level_component],
|
|
929
|
+
ordered=False,
|
|
930
|
+
)
|
|
931
|
+
|
|
932
|
+
with self.subTest("device filter (pk) with an invalid uuid"):
|
|
933
|
+
self.assertFalse(self.filterset({"device": [uuid.uuid4()]}, self.queryset).is_valid())
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
class ModuleDeviceCommonTestsMixin:
|
|
937
|
+
def test_has_empty_module_bays(self):
|
|
938
|
+
test_instances = self.queryset.all()[:2]
|
|
939
|
+
ModuleBay.objects.create(
|
|
940
|
+
**{
|
|
941
|
+
f"parent_{self.queryset.model._meta.model_name}": test_instances[0],
|
|
942
|
+
"name": "test filters position 1",
|
|
943
|
+
"position": 1,
|
|
944
|
+
}
|
|
945
|
+
)
|
|
946
|
+
ModuleBay.objects.create(
|
|
947
|
+
**{
|
|
948
|
+
f"parent_{self.queryset.model._meta.model_name}": test_instances[1],
|
|
949
|
+
"name": "test filters position 1",
|
|
950
|
+
"position": 1,
|
|
951
|
+
}
|
|
952
|
+
)
|
|
953
|
+
with self.subTest():
|
|
954
|
+
params = {"has_empty_module_bays": True}
|
|
955
|
+
qs = self.filterset(params, self.queryset).qs
|
|
956
|
+
self.assertGreater(qs.count(), 0)
|
|
957
|
+
for instance in qs:
|
|
958
|
+
self.assertTrue(instance.module_bays.filter(installed_module__isnull=True).exists())
|
|
959
|
+
with self.subTest():
|
|
960
|
+
params = {"has_empty_module_bays": False}
|
|
961
|
+
qs = self.filterset(params, self.queryset).qs
|
|
962
|
+
self.assertGreater(qs.count(), 0)
|
|
963
|
+
for instance in qs:
|
|
964
|
+
self.assertFalse(instance.module_bays.filter(installed_module__isnull=True).exists())
|
|
965
|
+
|
|
966
|
+
def test_has_modules(self):
|
|
967
|
+
with self.subTest():
|
|
968
|
+
params = {"has_modules": True}
|
|
969
|
+
qs = self.filterset(params, self.queryset).qs
|
|
970
|
+
self.assertGreater(qs.count(), 0)
|
|
971
|
+
for instance in qs:
|
|
972
|
+
self.assertTrue(instance.module_bays.filter(installed_module__isnull=False).exists())
|
|
973
|
+
with self.subTest():
|
|
974
|
+
params = {"has_modules": False}
|
|
975
|
+
qs = self.filterset(params, self.queryset).qs
|
|
976
|
+
self.assertGreater(qs.count(), 0)
|
|
977
|
+
for instance in qs:
|
|
978
|
+
self.assertFalse(instance.module_bays.filter(installed_module__isnull=False).exists())
|
|
979
|
+
|
|
980
|
+
|
|
981
|
+
class PathEndpointModelTestMixin:
|
|
982
|
+
def test_connected(self):
|
|
983
|
+
with self.subTest():
|
|
984
|
+
params = {"connected": True}
|
|
985
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
986
|
+
self.filterset(params, self.queryset).qs,
|
|
987
|
+
self.queryset.filter(_path__is_active=True),
|
|
988
|
+
)
|
|
989
|
+
with self.subTest():
|
|
990
|
+
params = {"connected": False}
|
|
991
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
992
|
+
self.filterset(params, self.queryset).qs,
|
|
993
|
+
self.queryset.filter(Q(_path__isnull=True) | Q(_path__is_active=False)),
|
|
994
|
+
)
|
|
995
|
+
|
|
996
|
+
|
|
700
997
|
class LocationTypeFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
701
998
|
queryset = LocationType.objects.all()
|
|
702
999
|
filterset = LocationTypeFilterSet
|
|
@@ -1008,16 +1305,17 @@ class DeviceTypeTestCase(FilterTestCases.FilterTestCase):
|
|
|
1008
1305
|
("console_server_port_templates", "console_server_port_templates__name"),
|
|
1009
1306
|
("device_bay_templates", "device_bay_templates__id"),
|
|
1010
1307
|
("device_bay_templates", "device_bay_templates__name"),
|
|
1308
|
+
("device_family", "device_family__id"),
|
|
1309
|
+
("device_family", "device_family__name"),
|
|
1011
1310
|
("devices", "devices__id"),
|
|
1012
1311
|
("front_port_templates", "front_port_templates__id"),
|
|
1013
1312
|
("front_port_templates", "front_port_templates__name"),
|
|
1014
|
-
("device_family", "device_family__id"),
|
|
1015
|
-
("device_family", "device_family__name"),
|
|
1016
1313
|
("interface_templates", "interface_templates__id"),
|
|
1017
1314
|
("interface_templates", "interface_templates__name"),
|
|
1018
1315
|
("manufacturer", "manufacturer__id"),
|
|
1019
1316
|
("manufacturer", "manufacturer__name"),
|
|
1020
1317
|
("model",),
|
|
1318
|
+
("module_bay_templates", "module_bay_templates__id"),
|
|
1021
1319
|
("part_number",),
|
|
1022
1320
|
("power_outlet_templates", "power_outlet_templates__id"),
|
|
1023
1321
|
("power_outlet_templates", "power_outlet_templates__name"),
|
|
@@ -1158,13 +1456,13 @@ class DeviceTypeTestCase(FilterTestCases.FilterTestCase):
|
|
|
1158
1456
|
params = {"pass_through_ports": True}
|
|
1159
1457
|
self.assertQuerysetEqual(
|
|
1160
1458
|
self.filterset(params, self.queryset).qs,
|
|
1161
|
-
self.queryset.filter(query),
|
|
1459
|
+
self.queryset.filter(query).distinct(),
|
|
1162
1460
|
)
|
|
1163
1461
|
with self.subTest():
|
|
1164
1462
|
params = {"pass_through_ports": False}
|
|
1165
1463
|
self.assertQuerysetEqual(
|
|
1166
1464
|
self.filterset(params, self.queryset).qs,
|
|
1167
|
-
self.queryset.filter(~query),
|
|
1465
|
+
self.queryset.filter(~query).distinct(),
|
|
1168
1466
|
)
|
|
1169
1467
|
|
|
1170
1468
|
def test_device_bays(self):
|
|
@@ -1188,36 +1486,21 @@ class DeviceTypeTestCase(FilterTestCases.FilterTestCase):
|
|
|
1188
1486
|
self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
|
|
1189
1487
|
|
|
1190
1488
|
|
|
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):
|
|
1489
|
+
class ConsolePortTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1207
1490
|
queryset = ConsolePortTemplate.objects.all()
|
|
1208
1491
|
filterset = ConsolePortTemplateFilterSet
|
|
1209
1492
|
|
|
1210
1493
|
|
|
1211
|
-
class ConsoleServerPortTemplateTestCase(
|
|
1494
|
+
class ConsoleServerPortTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1212
1495
|
queryset = ConsoleServerPortTemplate.objects.all()
|
|
1213
1496
|
filterset = ConsoleServerPortTemplateFilterSet
|
|
1214
1497
|
|
|
1215
1498
|
|
|
1216
|
-
class PowerPortTemplateTestCase(
|
|
1499
|
+
class PowerPortTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1217
1500
|
queryset = PowerPortTemplate.objects.all()
|
|
1218
1501
|
filterset = PowerPortTemplateFilterSet
|
|
1219
1502
|
generic_filter_tests = [
|
|
1220
|
-
*
|
|
1503
|
+
*ModularComponentTemplateTestMixin.generic_filter_tests,
|
|
1221
1504
|
("allocated_draw",),
|
|
1222
1505
|
("maximum_draw",),
|
|
1223
1506
|
("power_outlet_templates", "power_outlet_templates__id"),
|
|
@@ -1239,11 +1522,12 @@ class PowerPortTemplateTestCase(Mixins.ComponentTemplateMixin):
|
|
|
1239
1522
|
)
|
|
1240
1523
|
|
|
1241
1524
|
|
|
1242
|
-
class PowerOutletTemplateTestCase(
|
|
1525
|
+
class PowerOutletTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1243
1526
|
queryset = PowerOutletTemplate.objects.all()
|
|
1244
1527
|
filterset = PowerOutletTemplateFilterSet
|
|
1245
1528
|
generic_filter_tests = [
|
|
1246
|
-
*
|
|
1529
|
+
*ModularComponentTemplateTestMixin.generic_filter_tests,
|
|
1530
|
+
("feed_leg",),
|
|
1247
1531
|
("power_port_template", "power_port_template__id"),
|
|
1248
1532
|
("power_port_template", "power_port_template__name"),
|
|
1249
1533
|
]
|
|
@@ -1261,26 +1545,14 @@ class PowerOutletTemplateTestCase(Mixins.ComponentTemplateMixin):
|
|
|
1261
1545
|
description="Power Outlet Description 4",
|
|
1262
1546
|
)
|
|
1263
1547
|
|
|
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
1548
|
|
|
1273
|
-
class InterfaceTemplateTestCase(
|
|
1549
|
+
class InterfaceTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1274
1550
|
queryset = InterfaceTemplate.objects.all()
|
|
1275
1551
|
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
|
-
)
|
|
1552
|
+
generic_filter_tests = [
|
|
1553
|
+
*ModularComponentTemplateTestMixin.generic_filter_tests,
|
|
1554
|
+
("type",),
|
|
1555
|
+
]
|
|
1284
1556
|
|
|
1285
1557
|
def test_mgmt_only(self):
|
|
1286
1558
|
# TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
|
|
@@ -1298,11 +1570,11 @@ class InterfaceTemplateTestCase(Mixins.ComponentTemplateMixin):
|
|
|
1298
1570
|
)
|
|
1299
1571
|
|
|
1300
1572
|
|
|
1301
|
-
class FrontPortTemplateTestCase(
|
|
1573
|
+
class FrontPortTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1302
1574
|
queryset = FrontPortTemplate.objects.all()
|
|
1303
1575
|
filterset = FrontPortTemplateFilterSet
|
|
1304
1576
|
generic_filter_tests = [
|
|
1305
|
-
*
|
|
1577
|
+
*ModularComponentTemplateTestMixin.generic_filter_tests,
|
|
1306
1578
|
("rear_port_position",),
|
|
1307
1579
|
("rear_port_template", "rear_port_template__id"),
|
|
1308
1580
|
]
|
|
@@ -1316,11 +1588,11 @@ class FrontPortTemplateTestCase(Mixins.ComponentTemplateMixin):
|
|
|
1316
1588
|
)
|
|
1317
1589
|
|
|
1318
1590
|
|
|
1319
|
-
class RearPortTemplateTestCase(
|
|
1591
|
+
class RearPortTemplateTestCase(ModularComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1320
1592
|
queryset = RearPortTemplate.objects.all()
|
|
1321
1593
|
filterset = RearPortTemplateFilterSet
|
|
1322
1594
|
generic_filter_tests = [
|
|
1323
|
-
*
|
|
1595
|
+
*ModularComponentTemplateTestMixin.generic_filter_tests,
|
|
1324
1596
|
("front_port_templates", "front_port_templates__id"),
|
|
1325
1597
|
]
|
|
1326
1598
|
|
|
@@ -1355,7 +1627,7 @@ class RearPortTemplateTestCase(Mixins.ComponentTemplateMixin):
|
|
|
1355
1627
|
)
|
|
1356
1628
|
|
|
1357
1629
|
|
|
1358
|
-
class DeviceBayTemplateTestCase(
|
|
1630
|
+
class DeviceBayTemplateTestCase(ComponentTemplateTestMixin, FilterTestCases.FilterTestCase):
|
|
1359
1631
|
queryset = DeviceBayTemplate.objects.all()
|
|
1360
1632
|
filterset = DeviceBayTemplateFilterSet
|
|
1361
1633
|
|
|
@@ -1402,7 +1674,11 @@ class PlatformTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
1402
1674
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), len(virtual_machines))
|
|
1403
1675
|
|
|
1404
1676
|
|
|
1405
|
-
class DeviceTestCase(
|
|
1677
|
+
class DeviceTestCase(
|
|
1678
|
+
ModuleDeviceCommonTestsMixin,
|
|
1679
|
+
FilterTestCases.FilterTestCase,
|
|
1680
|
+
FilterTestCases.TenancyFilterTestCaseMixin,
|
|
1681
|
+
):
|
|
1406
1682
|
queryset = Device.objects.all()
|
|
1407
1683
|
filterset = DeviceFilterSet
|
|
1408
1684
|
tenancy_related_name = "devices"
|
|
@@ -1424,9 +1700,11 @@ class DeviceTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilt
|
|
|
1424
1700
|
("device_type", "device_type__model"),
|
|
1425
1701
|
("front_ports", "front_ports__id"),
|
|
1426
1702
|
("interfaces", "interfaces__id"),
|
|
1703
|
+
("interfaces", "interfaces__name"),
|
|
1427
1704
|
("mac_address", "interfaces__mac_address"),
|
|
1428
1705
|
("manufacturer", "device_type__manufacturer__id"),
|
|
1429
1706
|
("manufacturer", "device_type__manufacturer__name"),
|
|
1707
|
+
("module_bays", "module_bays__id"),
|
|
1430
1708
|
("name",),
|
|
1431
1709
|
("platform", "platform__id"),
|
|
1432
1710
|
("platform", "platform__name"),
|
|
@@ -1510,7 +1788,7 @@ class DeviceTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilt
|
|
|
1510
1788
|
)
|
|
1511
1789
|
|
|
1512
1790
|
# Assign primary IPs for filtering
|
|
1513
|
-
interfaces = Interface.objects.
|
|
1791
|
+
interfaces = Interface.objects.filter(device__isnull=False)
|
|
1514
1792
|
ipaddr_status = Status.objects.get_for_model(IPAddress).first()
|
|
1515
1793
|
prefix_status = Status.objects.get_for_model(Prefix).first()
|
|
1516
1794
|
namespace = Namespace.objects.first()
|
|
@@ -1681,21 +1959,17 @@ class DeviceTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilt
|
|
|
1681
1959
|
)
|
|
1682
1960
|
|
|
1683
1961
|
|
|
1684
|
-
class ConsolePortTestCase(FilterTestCases.FilterTestCase):
|
|
1962
|
+
class ConsolePortTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
1685
1963
|
queryset = ConsolePort.objects.all()
|
|
1686
1964
|
filterset = ConsolePortFilterSet
|
|
1687
1965
|
generic_filter_tests = [
|
|
1966
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
1688
1967
|
("cable", "cable__id"),
|
|
1689
|
-
("description",),
|
|
1690
|
-
("device", "device__id"),
|
|
1691
|
-
("device", "device__name"),
|
|
1692
|
-
("label",),
|
|
1693
|
-
("name",),
|
|
1694
1968
|
]
|
|
1695
1969
|
|
|
1696
1970
|
@classmethod
|
|
1697
1971
|
def setUpTestData(cls):
|
|
1698
|
-
|
|
1972
|
+
super().setUpTestData()
|
|
1699
1973
|
|
|
1700
1974
|
devices = (
|
|
1701
1975
|
Device.objects.get(name="Device 1"),
|
|
@@ -1730,31 +2004,20 @@ class ConsolePortTestCase(FilterTestCases.FilterTestCase):
|
|
|
1730
2004
|
)
|
|
1731
2005
|
# Third port is not connected
|
|
1732
2006
|
|
|
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
2007
|
|
|
1743
|
-
class ConsoleServerPortTestCase(
|
|
2008
|
+
class ConsoleServerPortTestCase(
|
|
2009
|
+
PathEndpointModelTestMixin, ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase
|
|
2010
|
+
):
|
|
1744
2011
|
queryset = ConsoleServerPort.objects.all()
|
|
1745
2012
|
filterset = ConsoleServerPortFilterSet
|
|
1746
2013
|
generic_filter_tests = [
|
|
2014
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
1747
2015
|
("cable", "cable__id"),
|
|
1748
|
-
("description",),
|
|
1749
|
-
("device", "device__id"),
|
|
1750
|
-
("device", "device__name"),
|
|
1751
|
-
("label",),
|
|
1752
|
-
("name",),
|
|
1753
2016
|
]
|
|
1754
2017
|
|
|
1755
2018
|
@classmethod
|
|
1756
2019
|
def setUpTestData(cls):
|
|
1757
|
-
|
|
2020
|
+
super().setUpTestData()
|
|
1758
2021
|
|
|
1759
2022
|
devices = (
|
|
1760
2023
|
Device.objects.get(name="Device 1"),
|
|
@@ -1789,28 +2052,15 @@ class ConsoleServerPortTestCase(FilterTestCases.FilterTestCase):
|
|
|
1789
2052
|
)
|
|
1790
2053
|
# Third port is not connected
|
|
1791
2054
|
|
|
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
2055
|
|
|
1802
|
-
class PowerPortTestCase(FilterTestCases.FilterTestCase):
|
|
2056
|
+
class PowerPortTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
1803
2057
|
queryset = PowerPort.objects.all()
|
|
1804
2058
|
filterset = PowerPortFilterSet
|
|
1805
2059
|
generic_filter_tests = [
|
|
2060
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
1806
2061
|
("allocated_draw",),
|
|
1807
2062
|
("cable", "cable__id"),
|
|
1808
|
-
("description",),
|
|
1809
|
-
("device", "device__id"),
|
|
1810
|
-
("device", "device__name"),
|
|
1811
|
-
("label",),
|
|
1812
2063
|
("maximum_draw",),
|
|
1813
|
-
("name",),
|
|
1814
2064
|
("power_outlets", "power_outlets__id"),
|
|
1815
2065
|
("power_outlets", "power_outlets__name"),
|
|
1816
2066
|
]
|
|
@@ -1854,32 +2104,20 @@ class PowerPortTestCase(FilterTestCases.FilterTestCase):
|
|
|
1854
2104
|
)
|
|
1855
2105
|
# Third port is not connected
|
|
1856
2106
|
|
|
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
2107
|
|
|
1867
|
-
class PowerOutletTestCase(FilterTestCases.FilterTestCase):
|
|
2108
|
+
class PowerOutletTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
1868
2109
|
queryset = PowerOutlet.objects.all()
|
|
1869
2110
|
filterset = PowerOutletFilterSet
|
|
1870
2111
|
generic_filter_tests = [
|
|
2112
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
1871
2113
|
("cable", "cable__id"),
|
|
1872
|
-
("
|
|
1873
|
-
("device", "device__id"),
|
|
1874
|
-
("device", "device__name"),
|
|
1875
|
-
("label",),
|
|
1876
|
-
("name",),
|
|
2114
|
+
("feed_leg",),
|
|
1877
2115
|
("power_port", "power_port__id"),
|
|
1878
2116
|
]
|
|
1879
2117
|
|
|
1880
2118
|
@classmethod
|
|
1881
2119
|
def setUpTestData(cls):
|
|
1882
|
-
|
|
2120
|
+
super().setUpTestData()
|
|
1883
2121
|
|
|
1884
2122
|
devices = (
|
|
1885
2123
|
Device.objects.get(name="Device 1"),
|
|
@@ -1915,26 +2153,12 @@ class PowerOutletTestCase(FilterTestCases.FilterTestCase):
|
|
|
1915
2153
|
)
|
|
1916
2154
|
# Third port is not connected
|
|
1917
2155
|
|
|
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
2156
|
|
|
1934
|
-
class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
2157
|
+
class InterfaceTestCase(PathEndpointModelTestMixin, ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
1935
2158
|
queryset = Interface.objects.all()
|
|
1936
2159
|
filterset = InterfaceFilterSet
|
|
1937
2160
|
generic_filter_tests = [
|
|
2161
|
+
# parent class generic_filter_tests intentionally excluded
|
|
1938
2162
|
("bridge", "bridge__id"),
|
|
1939
2163
|
("bridge", "bridge__name"),
|
|
1940
2164
|
("bridged_interfaces", "bridged_interfaces__id"),
|
|
@@ -1944,17 +2168,20 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
1944
2168
|
("child_interfaces", "child_interfaces__name"),
|
|
1945
2169
|
("description",),
|
|
1946
2170
|
# ("device", "device__id"), # TODO - InterfaceFilterSet overrides device as a MultiValueCharFilter on name only
|
|
1947
|
-
("device", "device__name"),
|
|
1948
2171
|
("label",),
|
|
1949
2172
|
("lag", "lag__id"),
|
|
1950
2173
|
("lag", "lag__name"),
|
|
1951
2174
|
("mac_address",),
|
|
1952
2175
|
("member_interfaces", "member_interfaces__id"),
|
|
1953
2176
|
("member_interfaces", "member_interfaces__name"),
|
|
2177
|
+
("module", "module__id"),
|
|
2178
|
+
("module", "module__module_type__model"),
|
|
1954
2179
|
("mtu",),
|
|
1955
2180
|
("name",),
|
|
1956
2181
|
("parent_interface", "parent_interface__id"),
|
|
1957
2182
|
("parent_interface", "parent_interface__name"),
|
|
2183
|
+
("role", "role__id"),
|
|
2184
|
+
("role", "role__name"),
|
|
1958
2185
|
("status", "status__id"),
|
|
1959
2186
|
("status", "status__name"),
|
|
1960
2187
|
("type",),
|
|
@@ -1966,7 +2193,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
1966
2193
|
|
|
1967
2194
|
@classmethod
|
|
1968
2195
|
def setUpTestData(cls):
|
|
1969
|
-
|
|
2196
|
+
super().setUpTestData()
|
|
1970
2197
|
|
|
1971
2198
|
devices = (
|
|
1972
2199
|
Device.objects.get(name="Device 1"),
|
|
@@ -1976,15 +2203,17 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
1976
2203
|
vlans = VLAN.objects.all()[:3]
|
|
1977
2204
|
|
|
1978
2205
|
interface_statuses = Status.objects.get_for_model(Interface)
|
|
2206
|
+
interface_roles = Role.objects.get_for_model(Interface)
|
|
1979
2207
|
|
|
1980
2208
|
# Cabled interfaces
|
|
1981
2209
|
cabled_interfaces = (
|
|
1982
|
-
Interface.objects.get(name="Interface 1"),
|
|
1983
|
-
Interface.objects.get(name="Interface 2"),
|
|
1984
|
-
Interface.objects.get(name="Interface 3"),
|
|
2210
|
+
Interface.objects.get(name="Test Interface 1"),
|
|
2211
|
+
Interface.objects.get(name="Test Interface 2"),
|
|
2212
|
+
Interface.objects.get(name="Test Interface 3"),
|
|
1985
2213
|
Interface.objects.create(
|
|
1986
2214
|
device=devices[2],
|
|
1987
2215
|
name="Parent Interface 1",
|
|
2216
|
+
role=interface_roles[0],
|
|
1988
2217
|
type=InterfaceTypeChoices.TYPE_OTHER,
|
|
1989
2218
|
mode=InterfaceModeChoices.MODE_TAGGED,
|
|
1990
2219
|
enabled=True,
|
|
@@ -2004,6 +2233,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2004
2233
|
Interface.objects.create(
|
|
2005
2234
|
device=devices[2],
|
|
2006
2235
|
name="Parent Interface 3",
|
|
2236
|
+
role=interface_roles[1],
|
|
2007
2237
|
type=InterfaceTypeChoices.TYPE_OTHER,
|
|
2008
2238
|
mode=InterfaceModeChoices.MODE_TAGGED,
|
|
2009
2239
|
enabled=False,
|
|
@@ -2069,6 +2299,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2069
2299
|
Interface.objects.create(
|
|
2070
2300
|
device=cabled_interfaces[3].device,
|
|
2071
2301
|
name="Child 1",
|
|
2302
|
+
role=interface_roles[2],
|
|
2072
2303
|
parent_interface=cabled_interfaces[3],
|
|
2073
2304
|
status=interface_statuses[3],
|
|
2074
2305
|
type=InterfaceTypeChoices.TYPE_VIRTUAL,
|
|
@@ -2083,6 +2314,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2083
2314
|
Interface.objects.create(
|
|
2084
2315
|
device=cabled_interfaces[5].device,
|
|
2085
2316
|
name="Child 3",
|
|
2317
|
+
role=interface_roles[0],
|
|
2086
2318
|
parent_interface=cabled_interfaces[5],
|
|
2087
2319
|
status=interface_statuses[3],
|
|
2088
2320
|
type=InterfaceTypeChoices.TYPE_VIRTUAL,
|
|
@@ -2099,12 +2331,14 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2099
2331
|
Interface.objects.create(
|
|
2100
2332
|
device=devices[2],
|
|
2101
2333
|
name="Bridge 2",
|
|
2334
|
+
role=interface_roles[1],
|
|
2102
2335
|
status=interface_statuses[3],
|
|
2103
2336
|
type=InterfaceTypeChoices.TYPE_BRIDGE,
|
|
2104
2337
|
),
|
|
2105
2338
|
Interface.objects.create(
|
|
2106
2339
|
device=devices[2],
|
|
2107
2340
|
name="Bridge 3",
|
|
2341
|
+
role=interface_roles[2],
|
|
2108
2342
|
status=interface_statuses[3],
|
|
2109
2343
|
type=InterfaceTypeChoices.TYPE_BRIDGE,
|
|
2110
2344
|
),
|
|
@@ -2112,6 +2346,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2112
2346
|
Interface.objects.create(
|
|
2113
2347
|
device=bridge_interfaces[0].device,
|
|
2114
2348
|
name="Bridged 1",
|
|
2349
|
+
role=interface_roles[0],
|
|
2115
2350
|
bridge=bridge_interfaces[0],
|
|
2116
2351
|
status=interface_statuses[3],
|
|
2117
2352
|
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
@@ -2126,6 +2361,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2126
2361
|
Interface.objects.create(
|
|
2127
2362
|
device=bridge_interfaces[2].device,
|
|
2128
2363
|
name="Bridged 3",
|
|
2364
|
+
role=interface_roles[1],
|
|
2129
2365
|
bridge=bridge_interfaces[2],
|
|
2130
2366
|
status=interface_statuses[3],
|
|
2131
2367
|
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
@@ -2136,6 +2372,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2136
2372
|
Interface.objects.create(
|
|
2137
2373
|
device=devices[2],
|
|
2138
2374
|
name="LAG 1",
|
|
2375
|
+
role=interface_roles[0],
|
|
2139
2376
|
type=InterfaceTypeChoices.TYPE_LAG,
|
|
2140
2377
|
status=interface_statuses[3],
|
|
2141
2378
|
),
|
|
@@ -2148,6 +2385,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2148
2385
|
Interface.objects.create(
|
|
2149
2386
|
device=devices[2],
|
|
2150
2387
|
name="LAG 3",
|
|
2388
|
+
role=interface_roles[1],
|
|
2151
2389
|
type=InterfaceTypeChoices.TYPE_LAG,
|
|
2152
2390
|
status=interface_statuses[3],
|
|
2153
2391
|
),
|
|
@@ -2163,6 +2401,7 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2163
2401
|
device=devices[2],
|
|
2164
2402
|
name="Member 2",
|
|
2165
2403
|
lag=lag_interfaces[1],
|
|
2404
|
+
role=interface_roles[2],
|
|
2166
2405
|
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2167
2406
|
status=interface_statuses[3],
|
|
2168
2407
|
)
|
|
@@ -2174,32 +2413,35 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2174
2413
|
status=interface_statuses[3],
|
|
2175
2414
|
)
|
|
2176
2415
|
|
|
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
2416
|
def test_enabled(self):
|
|
2187
2417
|
# TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
|
|
2188
2418
|
with self.subTest():
|
|
2189
2419
|
params = {"enabled": True}
|
|
2190
|
-
self.
|
|
2420
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2421
|
+
self.filterset(params, self.queryset).qs,
|
|
2422
|
+
self.queryset.filter(**params),
|
|
2423
|
+
)
|
|
2191
2424
|
with self.subTest():
|
|
2192
2425
|
params = {"enabled": False}
|
|
2193
|
-
self.
|
|
2426
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2427
|
+
self.filterset(params, self.queryset).qs,
|
|
2428
|
+
self.queryset.filter(**params),
|
|
2429
|
+
)
|
|
2194
2430
|
|
|
2195
2431
|
def test_mgmt_only(self):
|
|
2196
2432
|
# TODO: Not a generic_filter_test because this is a boolean filter but not a RelatedMembershipBooleanFilter
|
|
2197
2433
|
with self.subTest():
|
|
2198
2434
|
params = {"mgmt_only": True}
|
|
2199
|
-
self.
|
|
2435
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2436
|
+
self.filterset(params, self.queryset).qs,
|
|
2437
|
+
self.queryset.filter(**params),
|
|
2438
|
+
)
|
|
2200
2439
|
with self.subTest():
|
|
2201
2440
|
params = {"mgmt_only": False}
|
|
2202
|
-
self.
|
|
2441
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2442
|
+
self.filterset(params, self.queryset).qs,
|
|
2443
|
+
self.queryset.filter(**params),
|
|
2444
|
+
)
|
|
2203
2445
|
|
|
2204
2446
|
def test_mode(self):
|
|
2205
2447
|
# TODO: Not a generic_filter_test because this is a single-value filter
|
|
@@ -2264,15 +2506,161 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2264
2506
|
with self.subTest():
|
|
2265
2507
|
self.assertFalse(queryset.filter(name="int4").exists())
|
|
2266
2508
|
|
|
2509
|
+
def test_device(self):
|
|
2510
|
+
"""
|
|
2511
|
+
Test that the device filter returns all components for a device and its
|
|
2512
|
+
modules, including virtual chassis member devices and their modules.
|
|
2513
|
+
"""
|
|
2514
|
+
status = Status.objects.get_for_model(Interface).first()
|
|
2515
|
+
manufacturer = Manufacturer.objects.first()
|
|
2516
|
+
device_type = DeviceType.objects.create(
|
|
2517
|
+
manufacturer=manufacturer, model="Test Device Filter for Interface Device Type"
|
|
2518
|
+
)
|
|
2519
|
+
device_vc_master = Device.objects.create(
|
|
2520
|
+
device_type=device_type,
|
|
2521
|
+
name="Test Device Filter for Interface Device VC Master",
|
|
2522
|
+
location=self.loc0,
|
|
2523
|
+
role=self.device_roles[0],
|
|
2524
|
+
status=Status.objects.get_for_model(Device).first(),
|
|
2525
|
+
)
|
|
2526
|
+
vc = VirtualChassis.objects.create(
|
|
2527
|
+
name="Test Device Filter for Interface Virtual Chassis", master=device_vc_master
|
|
2528
|
+
)
|
|
2529
|
+
device_vc_master.virtual_chassis = vc
|
|
2530
|
+
device_vc_master.save()
|
|
2531
|
+
parent_module_bay = ModuleBay.objects.create(
|
|
2532
|
+
name="Parent module bay", position="1", parent_device=device_vc_master
|
|
2533
|
+
)
|
|
2534
|
+
module_type = ModuleType.objects.create(
|
|
2535
|
+
manufacturer=manufacturer, model="Test Device Filter for Interface Module Type", comments="Module Type test"
|
|
2536
|
+
)
|
|
2537
|
+
module = Module.objects.create(
|
|
2538
|
+
module_type=module_type, parent_module_bay=parent_module_bay, status=self.module_statuses[0]
|
|
2539
|
+
)
|
|
2540
|
+
child_module_bay = ModuleBay.objects.create(name="Child module bay", position="1", parent_module=module)
|
|
2541
|
+
child_module = Module.objects.create(
|
|
2542
|
+
module_type=module_type, parent_module_bay=child_module_bay, status=self.module_statuses[0]
|
|
2543
|
+
)
|
|
2544
|
+
top_level_interface = self.queryset.create(
|
|
2545
|
+
device=device_vc_master,
|
|
2546
|
+
name="Top level Interface VC Master",
|
|
2547
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2548
|
+
status=status,
|
|
2549
|
+
)
|
|
2550
|
+
second_level_interface = self.queryset.create(
|
|
2551
|
+
module=module,
|
|
2552
|
+
name="Second level Interface VC Master",
|
|
2553
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2554
|
+
status=status,
|
|
2555
|
+
)
|
|
2556
|
+
third_level_interface = self.queryset.create(
|
|
2557
|
+
module=child_module,
|
|
2558
|
+
name="Third level Interface VC Master",
|
|
2559
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2560
|
+
status=status,
|
|
2561
|
+
)
|
|
2562
|
+
device_vc_member = Device.objects.create(
|
|
2563
|
+
device_type=device_type,
|
|
2564
|
+
name="Test Device Filter for Interface Device VC Member",
|
|
2565
|
+
location=self.loc0,
|
|
2566
|
+
role=self.device_roles[0],
|
|
2567
|
+
status=Status.objects.get_for_model(Device).first(),
|
|
2568
|
+
virtual_chassis=vc,
|
|
2569
|
+
)
|
|
2570
|
+
parent_module_bay_vc_member = ModuleBay.objects.create(
|
|
2571
|
+
name="Parent module bay", position="1", parent_device=device_vc_member
|
|
2572
|
+
)
|
|
2573
|
+
module_vc_member = Module.objects.create(
|
|
2574
|
+
module_type=module_type, parent_module_bay=parent_module_bay_vc_member, status=self.module_statuses[0]
|
|
2575
|
+
)
|
|
2576
|
+
child_module_bay_vc_member = ModuleBay.objects.create(
|
|
2577
|
+
name="Child module bay", position="1", parent_module=module_vc_member
|
|
2578
|
+
)
|
|
2579
|
+
child_module_vc_member = Module.objects.create(
|
|
2580
|
+
module_type=module_type, parent_module_bay=child_module_bay_vc_member, status=self.module_statuses[0]
|
|
2581
|
+
)
|
|
2582
|
+
top_level_interface_vc_member = self.queryset.create(
|
|
2583
|
+
device=device_vc_member,
|
|
2584
|
+
name="Top level Interface VC Member",
|
|
2585
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2586
|
+
status=status,
|
|
2587
|
+
)
|
|
2588
|
+
second_level_interface_vc_member = self.queryset.create(
|
|
2589
|
+
module=module_vc_member,
|
|
2590
|
+
name="Second level Interface VC Member",
|
|
2591
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2592
|
+
status=status,
|
|
2593
|
+
)
|
|
2594
|
+
third_level_interface_vc_member = self.queryset.create(
|
|
2595
|
+
module=child_module_vc_member,
|
|
2596
|
+
name="Third level Interface VC Member",
|
|
2597
|
+
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
|
2598
|
+
status=status,
|
|
2599
|
+
)
|
|
2600
|
+
|
|
2601
|
+
with self.subTest("device filter on pk"):
|
|
2602
|
+
self.assertQuerySetEqual(
|
|
2603
|
+
self.filterset({"device": [device_vc_master.pk]}, self.queryset).qs,
|
|
2604
|
+
[
|
|
2605
|
+
top_level_interface,
|
|
2606
|
+
second_level_interface,
|
|
2607
|
+
third_level_interface,
|
|
2608
|
+
top_level_interface_vc_member,
|
|
2609
|
+
second_level_interface_vc_member,
|
|
2610
|
+
third_level_interface_vc_member,
|
|
2611
|
+
],
|
|
2612
|
+
ordered=False,
|
|
2613
|
+
)
|
|
2614
|
+
|
|
2615
|
+
with self.subTest("device filter on name"):
|
|
2616
|
+
self.assertQuerySetEqual(
|
|
2617
|
+
self.filterset({"device": [device_vc_master.name]}, self.queryset).qs,
|
|
2618
|
+
[
|
|
2619
|
+
top_level_interface,
|
|
2620
|
+
second_level_interface,
|
|
2621
|
+
third_level_interface,
|
|
2622
|
+
top_level_interface_vc_member,
|
|
2623
|
+
second_level_interface_vc_member,
|
|
2624
|
+
third_level_interface_vc_member,
|
|
2625
|
+
],
|
|
2626
|
+
ordered=False,
|
|
2627
|
+
)
|
|
2628
|
+
|
|
2629
|
+
with self.subTest("device_id filter"):
|
|
2630
|
+
self.assertQuerySetEqual(
|
|
2631
|
+
self.filterset({"device_id": [device_vc_master.pk]}, self.queryset).qs,
|
|
2632
|
+
[
|
|
2633
|
+
top_level_interface,
|
|
2634
|
+
second_level_interface,
|
|
2635
|
+
third_level_interface,
|
|
2636
|
+
top_level_interface_vc_member,
|
|
2637
|
+
second_level_interface_vc_member,
|
|
2638
|
+
third_level_interface_vc_member,
|
|
2639
|
+
],
|
|
2640
|
+
ordered=False,
|
|
2641
|
+
)
|
|
2642
|
+
|
|
2643
|
+
with self.subTest("device_id filter with an invalid uuid"):
|
|
2644
|
+
self.assertFalse(self.filterset({"device_id": [uuid.uuid4()]}, self.queryset).is_valid())
|
|
2645
|
+
|
|
2646
|
+
with self.subTest("device (pk) filter with an invalid uuid"):
|
|
2647
|
+
self.assertFalse(self.filterset({"device": [uuid.uuid4()]}, self.queryset).is_valid())
|
|
2648
|
+
|
|
2267
2649
|
def test_kind(self):
|
|
2268
2650
|
# TODO: Not a generic_filter_test because this is a single-value filter
|
|
2269
2651
|
# 2.0 TODO: Support filtering for multiple values
|
|
2270
2652
|
with self.subTest():
|
|
2271
2653
|
params = {"kind": "physical"}
|
|
2272
|
-
self.
|
|
2654
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2655
|
+
self.filterset(params, self.queryset).qs,
|
|
2656
|
+
self.queryset.exclude(type__in=NONCONNECTABLE_IFACE_TYPES),
|
|
2657
|
+
)
|
|
2273
2658
|
with self.subTest():
|
|
2274
2659
|
params = {"kind": "virtual"}
|
|
2275
|
-
self.
|
|
2660
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
2661
|
+
self.filterset(params, self.queryset).qs,
|
|
2662
|
+
self.queryset.filter(type__in=VIRTUAL_IFACE_TYPES),
|
|
2663
|
+
)
|
|
2276
2664
|
|
|
2277
2665
|
def test_vlan(self):
|
|
2278
2666
|
# TODO: Not a generic_filter_test because this is a single-value filter
|
|
@@ -2297,24 +2685,21 @@ class InterfaceTestCase(FilterTestCases.FilterTestCase):
|
|
|
2297
2685
|
)
|
|
2298
2686
|
|
|
2299
2687
|
|
|
2300
|
-
class FrontPortTestCase(FilterTestCases.FilterTestCase):
|
|
2688
|
+
class FrontPortTestCase(ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
2301
2689
|
queryset = FrontPort.objects.all()
|
|
2302
2690
|
filterset = FrontPortFilterSet
|
|
2303
2691
|
generic_filter_tests = [
|
|
2304
|
-
|
|
2692
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
2305
2693
|
("cable", "cable__id"),
|
|
2306
|
-
("device", "device__id"),
|
|
2307
|
-
("device", "device__name"),
|
|
2308
|
-
("label",),
|
|
2309
|
-
("name",),
|
|
2310
2694
|
("rear_port", "rear_port__id"),
|
|
2311
2695
|
("rear_port", "rear_port__name"),
|
|
2312
2696
|
("rear_port_position",),
|
|
2697
|
+
("type",),
|
|
2313
2698
|
]
|
|
2314
2699
|
|
|
2315
2700
|
@classmethod
|
|
2316
2701
|
def setUpTestData(cls):
|
|
2317
|
-
|
|
2702
|
+
super().setUpTestData()
|
|
2318
2703
|
|
|
2319
2704
|
devices = (
|
|
2320
2705
|
Device.objects.get(name="Device 1"),
|
|
@@ -2378,30 +2763,93 @@ class FrontPortTestCase(FilterTestCases.FilterTestCase):
|
|
|
2378
2763
|
)
|
|
2379
2764
|
# Third port is not connected
|
|
2380
2765
|
|
|
2381
|
-
def
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2766
|
+
def test_device(self):
|
|
2767
|
+
"""Test that the device filter returns all components for a device and its modules."""
|
|
2768
|
+
manufacturer = Manufacturer.objects.first()
|
|
2769
|
+
device_type = DeviceType.objects.create(
|
|
2770
|
+
manufacturer=manufacturer, model="Test Device Filter for FrontPort Device Type"
|
|
2771
|
+
)
|
|
2772
|
+
device = Device.objects.create(
|
|
2773
|
+
device_type=device_type,
|
|
2774
|
+
name="Test Device Filter for FrontPort Device",
|
|
2775
|
+
location=self.loc0,
|
|
2776
|
+
role=self.device_roles[0],
|
|
2777
|
+
status=Status.objects.get_for_model(Device).first(),
|
|
2778
|
+
)
|
|
2779
|
+
parent_module_bay = ModuleBay.objects.create(name="Parent module bay", position="1", parent_device=device)
|
|
2780
|
+
module_type = ModuleType.objects.create(
|
|
2781
|
+
manufacturer=manufacturer, model="Test Device Filter for FrontPort Module Type", comments="Module Type test"
|
|
2782
|
+
)
|
|
2783
|
+
module = Module.objects.create(
|
|
2784
|
+
module_type=module_type, parent_module_bay=parent_module_bay, status=self.module_statuses[0]
|
|
2785
|
+
)
|
|
2786
|
+
child_module_bay = ModuleBay.objects.create(name="Child module bay", position="1", parent_module=module)
|
|
2787
|
+
child_module = Module.objects.create(
|
|
2788
|
+
module_type=module_type, parent_module_bay=child_module_bay, status=self.module_statuses[0]
|
|
2789
|
+
)
|
|
2790
|
+
top_level_rearport = RearPort.objects.create(
|
|
2791
|
+
device=device,
|
|
2792
|
+
name="Top level Rear Port",
|
|
2793
|
+
type=PortTypeChoices.TYPE_8P8C,
|
|
2794
|
+
positions=6,
|
|
2795
|
+
)
|
|
2796
|
+
second_level_rearport = RearPort.objects.create(
|
|
2797
|
+
module=module,
|
|
2798
|
+
name="Second level Rear Port",
|
|
2799
|
+
type=PortTypeChoices.TYPE_8P8C,
|
|
2800
|
+
positions=6,
|
|
2801
|
+
)
|
|
2802
|
+
third_level_rearport = RearPort.objects.create(
|
|
2803
|
+
module=child_module,
|
|
2804
|
+
name="Third level Rear Port",
|
|
2805
|
+
type=PortTypeChoices.TYPE_8P8C,
|
|
2806
|
+
positions=6,
|
|
2807
|
+
)
|
|
2808
|
+
top_level_frontport = self.queryset.create(
|
|
2809
|
+
device=device,
|
|
2810
|
+
name="Top level Front Port",
|
|
2811
|
+
rear_port=top_level_rearport,
|
|
2812
|
+
rear_port_position=1,
|
|
2813
|
+
)
|
|
2814
|
+
second_level_frontport = self.queryset.create(
|
|
2815
|
+
module=module,
|
|
2816
|
+
name="Second level Front Port",
|
|
2817
|
+
rear_port=second_level_rearport,
|
|
2818
|
+
rear_port_position=1,
|
|
2819
|
+
)
|
|
2820
|
+
third_level_frontport = self.queryset.create(
|
|
2821
|
+
module=child_module,
|
|
2822
|
+
name="Third level Front Port",
|
|
2823
|
+
rear_port=third_level_rearport,
|
|
2824
|
+
rear_port_position=1,
|
|
2825
|
+
)
|
|
2826
|
+
self.assertQuerySetEqual(
|
|
2827
|
+
self.filterset({"device": [device.pk]}, self.queryset).qs,
|
|
2828
|
+
[top_level_frontport, second_level_frontport, third_level_frontport],
|
|
2829
|
+
ordered=False,
|
|
2830
|
+
)
|
|
2831
|
+
self.assertQuerySetEqual(
|
|
2832
|
+
self.filterset({"device": [device.name]}, self.queryset).qs,
|
|
2833
|
+
[top_level_frontport, second_level_frontport, third_level_frontport],
|
|
2834
|
+
ordered=False,
|
|
2835
|
+
)
|
|
2385
2836
|
|
|
2386
2837
|
|
|
2387
|
-
class RearPortTestCase(FilterTestCases.FilterTestCase):
|
|
2838
|
+
class RearPortTestCase(ModularDeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
2388
2839
|
queryset = RearPort.objects.all()
|
|
2389
2840
|
filterset = RearPortFilterSet
|
|
2390
2841
|
generic_filter_tests = [
|
|
2842
|
+
*ModularDeviceComponentTestMixin.generic_filter_tests,
|
|
2391
2843
|
("cable", "cable__id"),
|
|
2392
|
-
("description",),
|
|
2393
|
-
("device", "device__id"),
|
|
2394
|
-
("device", "device__name"),
|
|
2395
2844
|
("front_ports", "front_ports__id"),
|
|
2396
2845
|
("front_ports", "front_ports__name"),
|
|
2397
|
-
("label",),
|
|
2398
|
-
("name",),
|
|
2399
2846
|
("positions",),
|
|
2847
|
+
("type",),
|
|
2400
2848
|
]
|
|
2401
2849
|
|
|
2402
2850
|
@classmethod
|
|
2403
2851
|
def setUpTestData(cls):
|
|
2404
|
-
|
|
2852
|
+
super().setUpTestData()
|
|
2405
2853
|
|
|
2406
2854
|
devices = (
|
|
2407
2855
|
Device.objects.get(name="Device 1"),
|
|
@@ -2445,28 +2893,19 @@ class RearPortTestCase(FilterTestCases.FilterTestCase):
|
|
|
2445
2893
|
)
|
|
2446
2894
|
# Third port is not connected
|
|
2447
2895
|
|
|
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
2896
|
|
|
2454
|
-
class DeviceBayTestCase(FilterTestCases.FilterTestCase):
|
|
2897
|
+
class DeviceBayTestCase(DeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
2455
2898
|
queryset = DeviceBay.objects.all()
|
|
2456
2899
|
filterset = DeviceBayFilterSet
|
|
2457
2900
|
generic_filter_tests = [
|
|
2458
|
-
|
|
2459
|
-
("device", "device__id"),
|
|
2460
|
-
("device", "device__name"),
|
|
2901
|
+
*DeviceComponentTestMixin.generic_filter_tests,
|
|
2461
2902
|
("installed_device", "installed_device__id"),
|
|
2462
2903
|
("installed_device", "installed_device__name"),
|
|
2463
|
-
("label",),
|
|
2464
|
-
("name",),
|
|
2465
2904
|
]
|
|
2466
2905
|
|
|
2467
2906
|
@classmethod
|
|
2468
2907
|
def setUpTestData(cls):
|
|
2469
|
-
|
|
2908
|
+
super().setUpTestData()
|
|
2470
2909
|
|
|
2471
2910
|
device_role = Role.objects.get_for_model(Device).first()
|
|
2472
2911
|
parent_device_type = DeviceType.objects.get(model="Model 2")
|
|
@@ -2519,19 +2958,15 @@ class DeviceBayTestCase(FilterTestCases.FilterTestCase):
|
|
|
2519
2958
|
device_bays[1].save()
|
|
2520
2959
|
|
|
2521
2960
|
|
|
2522
|
-
class InventoryItemTestCase(FilterTestCases.FilterTestCase):
|
|
2961
|
+
class InventoryItemTestCase(DeviceComponentTestMixin, FilterTestCases.FilterTestCase):
|
|
2523
2962
|
queryset = InventoryItem.objects.all()
|
|
2524
2963
|
filterset = InventoryItemFilterSet
|
|
2525
2964
|
generic_filter_tests = [
|
|
2965
|
+
*DeviceComponentTestMixin.generic_filter_tests,
|
|
2526
2966
|
("asset_tag",),
|
|
2527
2967
|
("children", "children__id"),
|
|
2528
|
-
("description",),
|
|
2529
|
-
("device", "device__id"),
|
|
2530
|
-
("device", "device__name"),
|
|
2531
|
-
("label",),
|
|
2532
2968
|
("manufacturer", "manufacturer__id"),
|
|
2533
2969
|
("manufacturer", "manufacturer__name"),
|
|
2534
|
-
("name",),
|
|
2535
2970
|
("parent", "parent__id"),
|
|
2536
2971
|
("parent", "parent__name"),
|
|
2537
2972
|
("part_id",),
|
|
@@ -2543,7 +2978,7 @@ class InventoryItemTestCase(FilterTestCases.FilterTestCase):
|
|
|
2543
2978
|
|
|
2544
2979
|
@classmethod
|
|
2545
2980
|
def setUpTestData(cls):
|
|
2546
|
-
|
|
2981
|
+
super().setUpTestData()
|
|
2547
2982
|
|
|
2548
2983
|
devices = (
|
|
2549
2984
|
Device.objects.get(name="Device 1"),
|
|
@@ -2551,7 +2986,7 @@ class InventoryItemTestCase(FilterTestCases.FilterTestCase):
|
|
|
2551
2986
|
Device.objects.get(name="Device 3"),
|
|
2552
2987
|
)
|
|
2553
2988
|
|
|
2554
|
-
software_versions = SoftwareVersion.objects.filter(software_image_files__isnull=False)[:3]
|
|
2989
|
+
software_versions = SoftwareVersion.objects.filter(software_image_files__isnull=False).distinct()[:3]
|
|
2555
2990
|
|
|
2556
2991
|
inventory_items = (
|
|
2557
2992
|
InventoryItem.objects.create(
|
|
@@ -2797,37 +3232,37 @@ class CableTestCase(FilterTestCases.FilterTestCase):
|
|
|
2797
3232
|
Interface.objects.get(device__name="Device 6"),
|
|
2798
3233
|
Interface.objects.create(
|
|
2799
3234
|
device=devices[0],
|
|
2800
|
-
name="Interface 7",
|
|
3235
|
+
name="Test Interface 7",
|
|
2801
3236
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2802
3237
|
status=interface_status,
|
|
2803
3238
|
),
|
|
2804
3239
|
Interface.objects.create(
|
|
2805
3240
|
device=devices[1],
|
|
2806
|
-
name="Interface 8",
|
|
3241
|
+
name="Test Interface 8",
|
|
2807
3242
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2808
3243
|
status=interface_status,
|
|
2809
3244
|
),
|
|
2810
3245
|
Interface.objects.create(
|
|
2811
3246
|
device=devices[2],
|
|
2812
|
-
name="Interface 9",
|
|
3247
|
+
name="Test Interface 9",
|
|
2813
3248
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2814
3249
|
status=interface_status,
|
|
2815
3250
|
),
|
|
2816
3251
|
Interface.objects.create(
|
|
2817
3252
|
device=devices[3],
|
|
2818
|
-
name="Interface 10",
|
|
3253
|
+
name="Test Interface 10",
|
|
2819
3254
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2820
3255
|
status=interface_status,
|
|
2821
3256
|
),
|
|
2822
3257
|
Interface.objects.create(
|
|
2823
3258
|
device=devices[4],
|
|
2824
|
-
name="Interface 11",
|
|
3259
|
+
name="Test Interface 11",
|
|
2825
3260
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2826
3261
|
status=interface_status,
|
|
2827
3262
|
),
|
|
2828
3263
|
Interface.objects.create(
|
|
2829
3264
|
device=devices[5],
|
|
2830
|
-
name="Interface 12",
|
|
3265
|
+
name="Test Interface 12",
|
|
2831
3266
|
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
2832
3267
|
status=interface_status,
|
|
2833
3268
|
),
|
|
@@ -2913,17 +3348,87 @@ class CableTestCase(FilterTestCases.FilterTestCase):
|
|
|
2913
3348
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
|
2914
3349
|
|
|
2915
3350
|
def test_device(self):
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
self.
|
|
3351
|
+
"""Test that the device filter returns all cables for a device and its modules."""
|
|
3352
|
+
interfaces = Interface.objects.filter(cable__isnull=True)[:3]
|
|
3353
|
+
manufacturer = Manufacturer.objects.first()
|
|
3354
|
+
device_type = DeviceType.objects.create(
|
|
3355
|
+
manufacturer=manufacturer, model="Test Device Filter for Cable Device Type"
|
|
3356
|
+
)
|
|
3357
|
+
device = Device.objects.create(
|
|
3358
|
+
device_type=device_type,
|
|
3359
|
+
name="Test Device Filter for Cable Device",
|
|
3360
|
+
location=self.loc0,
|
|
3361
|
+
role=self.device_roles[0],
|
|
3362
|
+
status=Status.objects.get_for_model(Device).first(),
|
|
3363
|
+
)
|
|
3364
|
+
parent_module_bay = ModuleBay.objects.create(name="Parent module bay", position="1", parent_device=device)
|
|
3365
|
+
module_type = ModuleType.objects.create(
|
|
3366
|
+
manufacturer=manufacturer, model="Test Device Filter for Cable Module Type", comments="Module Type test"
|
|
3367
|
+
)
|
|
3368
|
+
module = Module.objects.create(
|
|
3369
|
+
module_type=module_type, parent_module_bay=parent_module_bay, status=self.module_statuses[0]
|
|
3370
|
+
)
|
|
3371
|
+
child_module_bay = ModuleBay.objects.create(name="Child module bay", position="1", parent_module=module)
|
|
3372
|
+
child_module = Module.objects.create(
|
|
3373
|
+
module_type=module_type, parent_module_bay=child_module_bay, status=self.module_statuses[0]
|
|
3374
|
+
)
|
|
3375
|
+
interface_status = Status.objects.get_for_model(Interface).first()
|
|
3376
|
+
top_level_interface = Interface.objects.create(
|
|
3377
|
+
device=device,
|
|
3378
|
+
name="Top level Interface",
|
|
3379
|
+
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
3380
|
+
status=interface_status,
|
|
3381
|
+
)
|
|
3382
|
+
Interface.objects.create(
|
|
3383
|
+
module=module,
|
|
3384
|
+
name="Second level Interface",
|
|
3385
|
+
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
3386
|
+
status=interface_status,
|
|
3387
|
+
)
|
|
3388
|
+
third_level_interface = Interface.objects.create(
|
|
3389
|
+
module=child_module,
|
|
3390
|
+
name="Third level Interface",
|
|
3391
|
+
type=InterfaceTypeChoices.TYPE_1GE_FIXED,
|
|
3392
|
+
status=interface_status,
|
|
3393
|
+
)
|
|
3394
|
+
|
|
3395
|
+
top_level_cable = Cable.objects.create(
|
|
3396
|
+
termination_a=top_level_interface,
|
|
3397
|
+
termination_b=interfaces[0],
|
|
3398
|
+
label="Test Device Filter Cable 1",
|
|
3399
|
+
type=CableTypeChoices.TYPE_CAT5E,
|
|
3400
|
+
status=self.status_connected,
|
|
3401
|
+
color="f44336",
|
|
3402
|
+
length=30,
|
|
3403
|
+
length_unit=CableLengthUnitChoices.UNIT_FOOT,
|
|
3404
|
+
)
|
|
3405
|
+
third_level_cable = Cable.objects.create(
|
|
3406
|
+
termination_a=interfaces[1],
|
|
3407
|
+
termination_b=third_level_interface,
|
|
3408
|
+
label="Test Device Filter Cable 2",
|
|
3409
|
+
type=CableTypeChoices.TYPE_CAT5E,
|
|
3410
|
+
status=self.status_connected,
|
|
3411
|
+
color="f44336",
|
|
3412
|
+
length=30,
|
|
3413
|
+
length_unit=CableLengthUnitChoices.UNIT_FOOT,
|
|
3414
|
+
)
|
|
3415
|
+
|
|
3416
|
+
with self.subTest("device_id filter"):
|
|
3417
|
+
self.assertQuerySetEqual(
|
|
3418
|
+
self.filterset({"device_id": [device.pk]}, self.queryset).qs,
|
|
3419
|
+
[top_level_cable, third_level_cable],
|
|
3420
|
+
ordered=False,
|
|
3421
|
+
)
|
|
3422
|
+
|
|
3423
|
+
with self.subTest("device filter"):
|
|
3424
|
+
self.assertQuerySetEqual(
|
|
3425
|
+
self.filterset({"device": [device.name]}, self.queryset).qs,
|
|
3426
|
+
[top_level_cable, third_level_cable],
|
|
3427
|
+
ordered=False,
|
|
3428
|
+
)
|
|
3429
|
+
|
|
3430
|
+
with self.subTest("device_id filter with an invalid uuid"):
|
|
3431
|
+
self.assertFalse(self.filterset({"device_id": [uuid.uuid4()]}, self.queryset).is_valid())
|
|
2927
3432
|
|
|
2928
3433
|
def test_rack(self):
|
|
2929
3434
|
# TODO: Not a generic_filter_test because this is a method filter.
|
|
@@ -2999,7 +3504,7 @@ class PowerPanelTestCase(FilterTestCases.FilterTestCase):
|
|
|
2999
3504
|
PowerPanel.objects.create(name="Power Panel 4", location=cls.loc1)
|
|
3000
3505
|
|
|
3001
3506
|
|
|
3002
|
-
class PowerFeedTestCase(FilterTestCases.FilterTestCase):
|
|
3507
|
+
class PowerFeedTestCase(PathEndpointModelTestMixin, FilterTestCases.FilterTestCase):
|
|
3003
3508
|
queryset = PowerFeed.objects.all()
|
|
3004
3509
|
filterset = PowerFeedFilterSet
|
|
3005
3510
|
generic_filter_tests = [
|
|
@@ -3088,28 +3593,28 @@ class PowerFeedTestCase(FilterTestCases.FilterTestCase):
|
|
|
3088
3593
|
)
|
|
3089
3594
|
|
|
3090
3595
|
def test_type(self):
|
|
3091
|
-
# TODO: Not a generic_filter_test because this
|
|
3596
|
+
# TODO: Not a generic_filter_test because this field only has 2 valid choices
|
|
3092
3597
|
params = {"type": [PowerFeedTypeChoices.TYPE_PRIMARY]}
|
|
3093
|
-
self.
|
|
3598
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
3599
|
+
self.filterset(params, self.queryset).qs,
|
|
3600
|
+
self.queryset.filter(type=PowerFeedTypeChoices.TYPE_PRIMARY),
|
|
3601
|
+
)
|
|
3094
3602
|
|
|
3095
3603
|
def test_supply(self):
|
|
3096
|
-
# TODO: Not a generic_filter_test because this
|
|
3604
|
+
# TODO: Not a generic_filter_test because this field only has 2 valid choices
|
|
3097
3605
|
params = {"supply": [PowerFeedSupplyChoices.SUPPLY_AC]}
|
|
3098
|
-
self.
|
|
3606
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
3607
|
+
self.filterset(params, self.queryset).qs,
|
|
3608
|
+
self.queryset.filter(supply=PowerFeedSupplyChoices.SUPPLY_AC),
|
|
3609
|
+
)
|
|
3099
3610
|
|
|
3100
3611
|
def test_phase(self):
|
|
3101
|
-
# TODO: Not a generic_filter_test because this
|
|
3612
|
+
# TODO: Not a generic_filter_test because this field only has 2 valid choices
|
|
3102
3613
|
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)
|
|
3614
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
3615
|
+
self.filterset(params, self.queryset).qs,
|
|
3616
|
+
self.queryset.filter(phase=PowerFeedPhaseChoices.PHASE_3PHASE),
|
|
3617
|
+
)
|
|
3113
3618
|
|
|
3114
3619
|
|
|
3115
3620
|
class DeviceRedundancyGroupTestCase(FilterTestCases.FilterTestCase):
|
|
@@ -3249,7 +3754,7 @@ class InterfaceRedundancyGroupAssociationTestCase(FilterTestCases.FilterTestCase
|
|
|
3249
3754
|
|
|
3250
3755
|
statuses = Status.objects.get_for_model(InterfaceRedundancyGroup)
|
|
3251
3756
|
cls.ips = IPAddress.objects.all()
|
|
3252
|
-
cls.interfaces = Interface.objects.all()[:
|
|
3757
|
+
cls.interfaces = Interface.objects.all()[:8]
|
|
3253
3758
|
|
|
3254
3759
|
interface_redundancy_groups = (
|
|
3255
3760
|
InterfaceRedundancyGroup(
|
|
@@ -3297,8 +3802,9 @@ class InterfaceRedundancyGroupAssociationTestCase(FilterTestCases.FilterTestCase
|
|
|
3297
3802
|
interface_redundancy_groups[1].secrets_group = secrets_groups[1]
|
|
3298
3803
|
interface_redundancy_groups[1].validated_save()
|
|
3299
3804
|
|
|
3300
|
-
for i,
|
|
3301
|
-
|
|
3805
|
+
for i, group in enumerate(interface_redundancy_groups):
|
|
3806
|
+
group.add_interface(cls.interfaces[i], 100 * i)
|
|
3807
|
+
group.add_interface(cls.interfaces[i + 4], 100 * (i + 4))
|
|
3302
3808
|
|
|
3303
3809
|
|
|
3304
3810
|
class SoftwareImageFileFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
@@ -3458,3 +3964,123 @@ class ControllerManagedDeviceGroupFilterSetTestCase(FilterTestCases.FilterTestCa
|
|
|
3458
3964
|
@classmethod
|
|
3459
3965
|
def setUpTestData(cls):
|
|
3460
3966
|
common_test_data(cls)
|
|
3967
|
+
|
|
3968
|
+
|
|
3969
|
+
class ModuleTestCase(
|
|
3970
|
+
ModuleDeviceCommonTestsMixin,
|
|
3971
|
+
FilterTestCases.TenancyFilterTestCaseMixin,
|
|
3972
|
+
FilterTestCases.FilterTestCase,
|
|
3973
|
+
):
|
|
3974
|
+
queryset = Module.objects.all()
|
|
3975
|
+
filterset = ModuleFilterSet
|
|
3976
|
+
tenancy_related_name = "modules"
|
|
3977
|
+
generic_filter_tests = [
|
|
3978
|
+
("asset_tag",),
|
|
3979
|
+
("console_ports", "console_ports__id"),
|
|
3980
|
+
("console_ports", "console_ports__name"),
|
|
3981
|
+
("console_server_ports", "console_server_ports__id"),
|
|
3982
|
+
("console_server_ports", "console_server_ports__name"),
|
|
3983
|
+
("front_ports", "front_ports__id"),
|
|
3984
|
+
("front_ports", "front_ports__name"),
|
|
3985
|
+
("interfaces", "interfaces__id"),
|
|
3986
|
+
("interfaces", "interfaces__name"),
|
|
3987
|
+
("mac_address", "interfaces__mac_address"),
|
|
3988
|
+
("manufacturer", "module_type__manufacturer__id"),
|
|
3989
|
+
("manufacturer", "module_type__manufacturer__name"),
|
|
3990
|
+
("module_bays", "module_bays__id"),
|
|
3991
|
+
("module_type", "module_type__id"),
|
|
3992
|
+
("module_type", "module_type__model"),
|
|
3993
|
+
("parent_module_bay", "parent_module_bay__id"),
|
|
3994
|
+
("power_outlets", "power_outlets__id"),
|
|
3995
|
+
("power_outlets", "power_outlets__name"),
|
|
3996
|
+
("power_ports", "power_ports__id"),
|
|
3997
|
+
("power_ports", "power_ports__name"),
|
|
3998
|
+
("rear_ports", "rear_ports__id"),
|
|
3999
|
+
("rear_ports", "rear_ports__name"),
|
|
4000
|
+
("role", "role__id"),
|
|
4001
|
+
("role", "role__name"),
|
|
4002
|
+
("serial",),
|
|
4003
|
+
("status", "status__id"),
|
|
4004
|
+
("status", "status__name"),
|
|
4005
|
+
]
|
|
4006
|
+
|
|
4007
|
+
@classmethod
|
|
4008
|
+
def setUpTestData(cls):
|
|
4009
|
+
common_test_data(cls)
|
|
4010
|
+
|
|
4011
|
+
# Update existing interface objects with mac addresses for filtering
|
|
4012
|
+
interfaces = Interface.objects.filter(module__isnull=False)[:3]
|
|
4013
|
+
Interface.objects.filter(pk=interfaces[0].pk).update(mac_address="00-00-00-00-00-01")
|
|
4014
|
+
Interface.objects.filter(pk=interfaces[1].pk).update(mac_address="00-00-00-00-00-02")
|
|
4015
|
+
|
|
4016
|
+
|
|
4017
|
+
class ModuleTypeTestCase(FilterTestCases.FilterTestCase):
|
|
4018
|
+
queryset = ModuleType.objects.all()
|
|
4019
|
+
filterset = ModuleTypeFilterSet
|
|
4020
|
+
generic_filter_tests = [
|
|
4021
|
+
("comments",),
|
|
4022
|
+
("manufacturer", "manufacturer__id"),
|
|
4023
|
+
("manufacturer", "manufacturer__name"),
|
|
4024
|
+
("model",),
|
|
4025
|
+
("part_number",),
|
|
4026
|
+
("console_port_templates", "console_port_templates__id"),
|
|
4027
|
+
("console_port_templates", "console_port_templates__name"),
|
|
4028
|
+
("console_server_port_templates", "console_server_port_templates__id"),
|
|
4029
|
+
("console_server_port_templates", "console_server_port_templates__name"),
|
|
4030
|
+
("power_port_templates", "power_port_templates__id"),
|
|
4031
|
+
("power_port_templates", "power_port_templates__name"),
|
|
4032
|
+
("power_outlet_templates", "power_outlet_templates__id"),
|
|
4033
|
+
("power_outlet_templates", "power_outlet_templates__name"),
|
|
4034
|
+
("interface_templates", "interface_templates__id"),
|
|
4035
|
+
("interface_templates", "interface_templates__name"),
|
|
4036
|
+
("front_port_templates", "front_port_templates__id"),
|
|
4037
|
+
("front_port_templates", "front_port_templates__name"),
|
|
4038
|
+
("rear_port_templates", "rear_port_templates__id"),
|
|
4039
|
+
("rear_port_templates", "rear_port_templates__name"),
|
|
4040
|
+
("module_bay_templates", "module_bay_templates__id"),
|
|
4041
|
+
]
|
|
4042
|
+
|
|
4043
|
+
@classmethod
|
|
4044
|
+
def setUpTestData(cls):
|
|
4045
|
+
common_test_data(cls)
|
|
4046
|
+
|
|
4047
|
+
|
|
4048
|
+
class ModuleBayTemplateTestCase(FilterTestCases.FilterTestCase):
|
|
4049
|
+
queryset = ModuleBayTemplate.objects.all()
|
|
4050
|
+
filterset = ModuleBayTemplateFilterSet
|
|
4051
|
+
generic_filter_tests = [
|
|
4052
|
+
("description",),
|
|
4053
|
+
("device_type", "device_type__id"),
|
|
4054
|
+
("device_type", "device_type__model"),
|
|
4055
|
+
("label",),
|
|
4056
|
+
("module_type", "module_type__id"),
|
|
4057
|
+
("module_type", "module_type__model"),
|
|
4058
|
+
("name",),
|
|
4059
|
+
("position",),
|
|
4060
|
+
]
|
|
4061
|
+
|
|
4062
|
+
@classmethod
|
|
4063
|
+
def setUpTestData(cls):
|
|
4064
|
+
common_test_data(cls)
|
|
4065
|
+
|
|
4066
|
+
|
|
4067
|
+
class ModuleBayTestCase(FilterTestCases.FilterTestCase):
|
|
4068
|
+
queryset = ModuleBay.objects.all()
|
|
4069
|
+
filterset = ModuleBayFilterSet
|
|
4070
|
+
generic_filter_tests = [
|
|
4071
|
+
("description",),
|
|
4072
|
+
("label",),
|
|
4073
|
+
("parent_device", "parent_device__id"),
|
|
4074
|
+
("parent_device", "parent_device__name"),
|
|
4075
|
+
("parent_module", "parent_module__id"),
|
|
4076
|
+
("installed_module", "installed_module__id"),
|
|
4077
|
+
("name",),
|
|
4078
|
+
("position",),
|
|
4079
|
+
]
|
|
4080
|
+
|
|
4081
|
+
@classmethod
|
|
4082
|
+
def setUpTestData(cls):
|
|
4083
|
+
common_test_data(cls)
|
|
4084
|
+
module_bays = ModuleBay.objects.all()[:2]
|
|
4085
|
+
module_bays[0].tags.set(Tag.objects.get_for_model(ModuleBay))
|
|
4086
|
+
module_bays[1].tags.set(Tag.objects.get_for_model(ModuleBay)[:3])
|