nautobot 2.2.8__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 +110 -14
- nautobot/core/forms/fields.py +10 -4
- nautobot/core/forms/forms.py +11 -3
- nautobot/core/forms/widgets.py +18 -1
- nautobot/core/graphql/generators.py +2 -2
- nautobot/core/graphql/schema.py +28 -7
- nautobot/core/jobs/__init__.py +20 -3
- 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 +15 -19
- nautobot/core/settings.yaml +48 -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 +28 -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_general_functionality.py +1 -1
- nautobot/core/tests/integration/test_import_objects_ui.py +1 -0
- nautobot/core/tests/integration/test_swagger.py +1 -1
- nautobot/core/tests/nautobot_config.py +0 -1
- nautobot/core/tests/runner.py +2 -2
- nautobot/core/tests/test_api.py +1 -0
- nautobot/core/tests/test_authentication.py +7 -2
- nautobot/core/tests/test_filters.py +11 -9
- nautobot/core/tests/test_forms.py +9 -0
- nautobot/core/tests/test_graphql.py +27 -16
- nautobot/core/tests/test_jobs.py +204 -2
- nautobot/core/tests/test_tables.py +3 -1
- nautobot/core/tests/test_templatetags_helpers.py +12 -5
- nautobot/core/tests/test_templatetags_netutils.py +3 -3
- 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 +282 -99
- nautobot/dcim/models/devices.py +472 -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 +248 -47
- 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/deviceredundancygroup_retrieve.html +6 -0
- 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 +1103 -8
- nautobot/dcim/tests/test_views.py +1525 -343
- nautobot/dcim/urls.py +17 -2
- nautobot/dcim/utils.py +2 -3
- nautobot/dcim/views.py +1109 -113
- 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 +73 -59
- 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 +26 -3
- nautobot/extras/jobs.py +2 -2
- nautobot/extras/management/__init__.py +1 -0
- nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +1 -16
- nautobot/extras/migrations/0021_customfield_changelog_data.py +1 -0
- nautobot/extras/migrations/0109_dynamicgroup_group_type_dynamicgroup_tags_and_more.py +108 -0
- nautobot/extras/migrations/0110_alter_configcontext_cluster_groups_and_more.py +111 -0
- nautobot/extras/migrations/0111_metadata.py +162 -0
- nautobot/extras/migrations/0112_dynamic_group_group_type_data_migration.py +28 -0
- nautobot/extras/migrations/0113_saved_views.py +77 -0
- nautobot/extras/models/__init__.py +15 -1
- nautobot/extras/models/change_logging.py +3 -3
- nautobot/extras/models/contacts.py +4 -0
- nautobot/extras/models/customfields.py +18 -3
- nautobot/extras/models/groups.py +389 -225
- nautobot/extras/models/jobs.py +87 -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 +109 -101
- nautobot/extras/tables.py +201 -17
- nautobot/extras/templates/extras/dynamicgroup.html +44 -15
- nautobot/extras/templates/extras/dynamicgroup_edit.html +2 -0
- nautobot/extras/templates/extras/job.html +1 -1
- nautobot/extras/templates/extras/job_detail.html +11 -0
- 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 +586 -8
- nautobot/extras/tests/test_webhooks.py +1 -1
- nautobot/extras/urls.py +5 -0
- nautobot/extras/utils.py +85 -16
- nautobot/extras/views.py +562 -122
- 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 +20 -20
- 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 +9 -2
- 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 +20 -34
- nautobot/project-static/css/base.css +21 -0
- nautobot/project-static/css/dark.css +11 -0
- nautobot/project-static/docs/404.html +894 -90
- nautobot/project-static/docs/apps/index.html +894 -90
- nautobot/project-static/docs/apps/nautobot-apps.html +894 -90
- 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 +921 -122
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +906 -103
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1620 -905
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +937 -146
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +979 -190
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +903 -101
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +899 -95
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +993 -195
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +976 -133
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +1080 -274
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1244 -336
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1729 -877
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +1166 -383
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2090 -1376
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2248 -1424
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +914 -113
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +965 -165
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1012 -225
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +1915 -1279
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1848 -1104
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +906 -103
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +2335 -1701
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +1804 -1026
- nautobot/project-static/docs/development/apps/api/configuration-view.html +894 -90
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +894 -90
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +894 -90
- nautobot/project-static/docs/development/apps/api/models/global-search.html +894 -90
- nautobot/project-static/docs/development/apps/api/models/graphql.html +894 -90
- nautobot/project-static/docs/development/apps/api/models/index.html +944 -92
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +894 -90
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +894 -90
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +894 -90
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +894 -90
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +894 -90
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +894 -90
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +894 -90
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +894 -90
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +894 -90
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +894 -90
- nautobot/project-static/docs/development/apps/api/prometheus.html +894 -90
- nautobot/project-static/docs/development/apps/api/setup.html +894 -90
- nautobot/project-static/docs/development/apps/api/testing.html +894 -90
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +894 -90
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +894 -90
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +894 -90
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +894 -90
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +894 -90
- nautobot/project-static/docs/development/apps/api/views/base-template.html +894 -90
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +894 -90
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +894 -90
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +894 -90
- nautobot/project-static/docs/development/apps/api/views/index.html +894 -90
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +894 -90
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +894 -90
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +894 -90
- nautobot/project-static/docs/development/apps/api/views/notes.html +894 -90
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +894 -90
- nautobot/project-static/docs/development/apps/api/views/urls.html +894 -90
- nautobot/project-static/docs/development/apps/index.html +894 -90
- nautobot/project-static/docs/development/apps/migration/code-updates.html +894 -90
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +894 -90
- nautobot/project-static/docs/development/apps/migration/from-v1.html +894 -90
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +894 -90
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +894 -90
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +894 -90
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +894 -90
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +894 -90
- nautobot/project-static/docs/development/core/application-registry.html +894 -90
- nautobot/project-static/docs/development/core/best-practices.html +895 -90
- nautobot/project-static/docs/development/core/bootstrap-ui.html +894 -90
- nautobot/project-static/docs/development/core/caching.html +894 -90
- nautobot/project-static/docs/development/core/controllers.html +894 -90
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +894 -90
- nautobot/project-static/docs/development/core/generic-views.html +894 -90
- nautobot/project-static/docs/development/core/getting-started.html +894 -90
- nautobot/project-static/docs/development/core/homepage.html +894 -90
- nautobot/project-static/docs/development/core/index.html +905 -90
- nautobot/project-static/docs/development/core/model-checklist.html +903 -91
- nautobot/project-static/docs/development/core/model-features.html +894 -90
- nautobot/project-static/docs/development/core/natural-keys.html +894 -90
- nautobot/project-static/docs/development/core/navigation-menu.html +894 -90
- nautobot/project-static/docs/development/core/release-checklist.html +897 -93
- nautobot/project-static/docs/development/core/role-internals.html +894 -90
- nautobot/project-static/docs/development/core/settings.html +894 -90
- nautobot/project-static/docs/development/core/style-guide.html +895 -91
- nautobot/project-static/docs/development/core/templates.html +906 -91
- nautobot/project-static/docs/development/core/testing.html +894 -90
- nautobot/project-static/docs/development/core/user-preferences.html +894 -90
- nautobot/project-static/docs/development/index.html +894 -90
- nautobot/project-static/docs/development/jobs/index.html +1271 -453
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +894 -90
- nautobot/project-static/docs/index.html +9032 -13
- 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 +902 -91
- nautobot/project-static/docs/overview/design_philosophy.html +896 -92
- nautobot/project-static/docs/overview/index.html +13 -8228
- nautobot/project-static/docs/release-notes/index.html +1131 -94
- nautobot/project-static/docs/release-notes/version-1.0.html +894 -90
- nautobot/project-static/docs/release-notes/version-1.1.html +894 -90
- nautobot/project-static/docs/release-notes/version-1.2.html +894 -90
- nautobot/project-static/docs/release-notes/version-1.3.html +894 -90
- nautobot/project-static/docs/release-notes/version-1.4.html +894 -90
- nautobot/project-static/docs/release-notes/version-1.5.html +895 -91
- nautobot/project-static/docs/release-notes/version-1.6.html +895 -91
- nautobot/project-static/docs/release-notes/version-2.0.html +894 -90
- nautobot/project-static/docs/release-notes/version-2.1.html +894 -90
- nautobot/project-static/docs/release-notes/version-2.2.html +1137 -196
- 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 +335 -260
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +894 -90
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +894 -90
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +894 -90
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +894 -90
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +1025 -175
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +894 -90
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +894 -90
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +894 -90
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +902 -90
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +894 -90
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +894 -90
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +894 -90
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +894 -90
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +894 -90
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +894 -90
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +894 -90
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +894 -90
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +946 -155
- nautobot/project-static/docs/user-guide/administration/installation/index.html +903 -95
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +936 -124
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +956 -159
- nautobot/project-static/docs/user-guide/administration/installation/services.html +915 -114
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +910 -101
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +894 -90
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +894 -90
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +894 -90
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +894 -90
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +977 -121
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +894 -90
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +894 -90
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +894 -90
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +894 -90
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +894 -90
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +894 -90
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +894 -90
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +894 -90
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +894 -90
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +895 -91
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +898 -90
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +897 -93
- 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 +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +925 -107
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +925 -107
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +920 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +925 -107
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +915 -107
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +922 -118
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +923 -119
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +920 -116
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +916 -107
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +928 -110
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +938 -120
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +930 -108
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +939 -121
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +930 -112
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +920 -116
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +923 -119
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +925 -117
- 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 +918 -114
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +942 -85
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +926 -108
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +945 -88
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +923 -105
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +931 -127
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +920 -116
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +924 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +926 -108
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +938 -90
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +899 -91
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +899 -91
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +903 -98
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +894 -90
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +899 -91
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +894 -90
- 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 +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +894 -90
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +894 -90
- nautobot/project-static/docs/user-guide/index.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +1260 -787
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +897 -93
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +898 -90
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +897 -93
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +9061 -0
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +897 -93
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +897 -93
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +9137 -0
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +897 -93
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +8933 -0
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +952 -123
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +894 -90
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +894 -90
- 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 +12 -8
- 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.8.dist-info → nautobot-2.3.0.dist-info}/METADATA +21 -19
- {nautobot-2.2.8.dist-info → nautobot-2.3.0.dist-info}/RECORD +684 -564
- 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.8.dist-info → nautobot-2.3.0.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.8.dist-info → nautobot-2.3.0.dist-info}/NOTICE +0 -0
- {nautobot-2.2.8.dist-info → nautobot-2.3.0.dist-info}/WHEEL +0 -0
- {nautobot-2.2.8.dist-info → nautobot-2.3.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
1
3
|
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
|
|
2
4
|
from django.contrib.contenttypes.models import ContentType
|
|
3
5
|
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
|
@@ -24,6 +26,7 @@ from nautobot.dcim.choices import (
|
|
|
24
26
|
PowerOutletFeedLegChoices,
|
|
25
27
|
PowerOutletTypeChoices,
|
|
26
28
|
PowerPortTypeChoices,
|
|
29
|
+
SubdeviceRoleChoices,
|
|
27
30
|
)
|
|
28
31
|
from nautobot.dcim.constants import (
|
|
29
32
|
NONCONNECTABLE_IFACE_TYPES,
|
|
@@ -35,6 +38,7 @@ from nautobot.dcim.constants import (
|
|
|
35
38
|
from nautobot.extras.models import (
|
|
36
39
|
ChangeLoggedModel,
|
|
37
40
|
RelationshipModel,
|
|
41
|
+
RoleField,
|
|
38
42
|
Status,
|
|
39
43
|
StatusField,
|
|
40
44
|
)
|
|
@@ -51,6 +55,7 @@ __all__ = (
|
|
|
51
55
|
"InterfaceRedundancyGroup",
|
|
52
56
|
"InterfaceRedundancyGroupAssociation",
|
|
53
57
|
"InventoryItem",
|
|
58
|
+
"ModuleBay",
|
|
54
59
|
"PathEndpoint",
|
|
55
60
|
"PowerOutlet",
|
|
56
61
|
"PowerPort",
|
|
@@ -69,7 +74,7 @@ class ComponentModel(PrimaryModel):
|
|
|
69
74
|
label = models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True, help_text="Physical label")
|
|
70
75
|
description = models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True)
|
|
71
76
|
|
|
72
|
-
natural_key_field_names = ["
|
|
77
|
+
natural_key_field_names = ["device", "name"]
|
|
73
78
|
|
|
74
79
|
class Meta:
|
|
75
80
|
abstract = True
|
|
@@ -83,6 +88,9 @@ class ComponentModel(PrimaryModel):
|
|
|
83
88
|
"""
|
|
84
89
|
Return a new ObjectChange with the `related_object` pinned to the `device` by default.
|
|
85
90
|
"""
|
|
91
|
+
if "related_object" in kwargs:
|
|
92
|
+
return super().to_objectchange(action, **kwargs)
|
|
93
|
+
|
|
86
94
|
# Annotate the parent Device
|
|
87
95
|
try:
|
|
88
96
|
device = self.device
|
|
@@ -92,6 +100,114 @@ class ComponentModel(PrimaryModel):
|
|
|
92
100
|
|
|
93
101
|
return super().to_objectchange(action, related_object=device, **kwargs)
|
|
94
102
|
|
|
103
|
+
@property
|
|
104
|
+
def parent(self):
|
|
105
|
+
return self.device
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class ModularComponentModel(ComponentModel):
|
|
109
|
+
device = ForeignKeyWithAutoRelatedName(
|
|
110
|
+
to="dcim.Device",
|
|
111
|
+
on_delete=models.CASCADE,
|
|
112
|
+
blank=True,
|
|
113
|
+
null=True,
|
|
114
|
+
)
|
|
115
|
+
module = ForeignKeyWithAutoRelatedName(
|
|
116
|
+
to="dcim.Module",
|
|
117
|
+
on_delete=models.CASCADE,
|
|
118
|
+
blank=True,
|
|
119
|
+
null=True,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
natural_key_field_names = ["device", "module", "name"]
|
|
123
|
+
|
|
124
|
+
class Meta:
|
|
125
|
+
abstract = True
|
|
126
|
+
ordering = ("device", "module", "_name")
|
|
127
|
+
constraints = [
|
|
128
|
+
models.UniqueConstraint(
|
|
129
|
+
fields=("device", "name"),
|
|
130
|
+
name="%(app_label)s_%(class)s_device_name_unique",
|
|
131
|
+
),
|
|
132
|
+
models.UniqueConstraint(
|
|
133
|
+
fields=("module", "name"),
|
|
134
|
+
name="%(app_label)s_%(class)s_module_name_unique",
|
|
135
|
+
),
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def parent(self):
|
|
140
|
+
"""Device that this component belongs to, walking up module inheritance if necessary."""
|
|
141
|
+
return self.module.device if self.module else self.device
|
|
142
|
+
|
|
143
|
+
def render_name_template(self, save=False):
|
|
144
|
+
"""
|
|
145
|
+
Replace the {module}, {module.parent}, {module.parent.parent}, etc. variables in the name
|
|
146
|
+
field with the actual module bay positions.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
save (bool, optional): If True, save the object after updating the name field. Defaults to False.
|
|
150
|
+
|
|
151
|
+
If a module bay position is blank, it will be skipped and the parents will be checked until a non-blank
|
|
152
|
+
position is found. If all parent module bays are exhausted, the variable is left as-is.
|
|
153
|
+
|
|
154
|
+
Example:
|
|
155
|
+
- Device (name="Device 1")
|
|
156
|
+
- ModuleBay (position="A")
|
|
157
|
+
- Module
|
|
158
|
+
- ModuleBay (position="")
|
|
159
|
+
- Module
|
|
160
|
+
- Interface (name="{module}{module.parent}")
|
|
161
|
+
|
|
162
|
+
The deeply nested interface would be named "A{module.parent}" after calling this method.
|
|
163
|
+
"""
|
|
164
|
+
if self.module and self.module.parent_module_bay and "{module" in self.name:
|
|
165
|
+
name = ""
|
|
166
|
+
module_bay = self.module.parent_module_bay
|
|
167
|
+
positions = []
|
|
168
|
+
while module_bay is not None:
|
|
169
|
+
position = getattr(module_bay, "position", None)
|
|
170
|
+
if position:
|
|
171
|
+
positions.append(position)
|
|
172
|
+
module_bay = getattr(getattr(module_bay, "parent_module", None), "parent_module_bay", None)
|
|
173
|
+
for part in re.split(r"({module(?:\.parent)*})", self.name):
|
|
174
|
+
if re.fullmatch(r"{module(\.parent)*}", part):
|
|
175
|
+
depth = part.count(".parent")
|
|
176
|
+
if depth < len(positions):
|
|
177
|
+
name += positions[depth]
|
|
178
|
+
continue
|
|
179
|
+
name += part
|
|
180
|
+
if self.name != name:
|
|
181
|
+
self.name = name
|
|
182
|
+
if save:
|
|
183
|
+
self.save(update_fields=["_name", "name"])
|
|
184
|
+
|
|
185
|
+
def to_objectchange(self, action, **kwargs):
|
|
186
|
+
"""
|
|
187
|
+
Return a new ObjectChange with the `related_object` pinned to the parent `device` or `module`.
|
|
188
|
+
"""
|
|
189
|
+
if "related_object" in kwargs:
|
|
190
|
+
return super().to_objectchange(action, **kwargs)
|
|
191
|
+
|
|
192
|
+
# Annotate the parent
|
|
193
|
+
try:
|
|
194
|
+
parent = self.device if self.device else self.module
|
|
195
|
+
except ObjectDoesNotExist:
|
|
196
|
+
# The parent may have already been deleted
|
|
197
|
+
parent = None
|
|
198
|
+
|
|
199
|
+
return super().to_objectchange(action, related_object=parent, **kwargs)
|
|
200
|
+
|
|
201
|
+
def clean(self):
|
|
202
|
+
super().clean()
|
|
203
|
+
|
|
204
|
+
# Validate that a Device or Module is set, but not both
|
|
205
|
+
if self.device and self.module:
|
|
206
|
+
raise ValidationError("Only one of device or module must be set")
|
|
207
|
+
|
|
208
|
+
if not (self.device or self.module):
|
|
209
|
+
raise ValidationError("Either device or module must be set")
|
|
210
|
+
|
|
95
211
|
|
|
96
212
|
class CableTermination(models.Model):
|
|
97
213
|
"""
|
|
@@ -211,9 +327,9 @@ class PathEndpoint(models.Model):
|
|
|
211
327
|
"graphql",
|
|
212
328
|
"webhooks",
|
|
213
329
|
)
|
|
214
|
-
class ConsolePort(CableTermination, PathEndpoint
|
|
330
|
+
class ConsolePort(ModularComponentModel, CableTermination, PathEndpoint):
|
|
215
331
|
"""
|
|
216
|
-
A physical console port within a Device. ConsolePorts connect to ConsoleServerPorts.
|
|
332
|
+
A physical console port within a Device or Module. ConsolePorts connect to ConsoleServerPorts.
|
|
217
333
|
"""
|
|
218
334
|
|
|
219
335
|
type = models.CharField(
|
|
@@ -223,14 +339,6 @@ class ConsolePort(CableTermination, PathEndpoint, ComponentModel):
|
|
|
223
339
|
help_text="Physical port type",
|
|
224
340
|
)
|
|
225
341
|
|
|
226
|
-
class Meta:
|
|
227
|
-
ordering = ("device", "_name")
|
|
228
|
-
unique_together = ("device", "name")
|
|
229
|
-
|
|
230
|
-
@property
|
|
231
|
-
def parent(self):
|
|
232
|
-
return self.device
|
|
233
|
-
|
|
234
342
|
|
|
235
343
|
#
|
|
236
344
|
# Console server ports
|
|
@@ -238,9 +346,9 @@ class ConsolePort(CableTermination, PathEndpoint, ComponentModel):
|
|
|
238
346
|
|
|
239
347
|
|
|
240
348
|
@extras_features("custom_links", "cable_terminations", "custom_validators", "graphql", "webhooks")
|
|
241
|
-
class ConsoleServerPort(CableTermination, PathEndpoint
|
|
349
|
+
class ConsoleServerPort(ModularComponentModel, CableTermination, PathEndpoint):
|
|
242
350
|
"""
|
|
243
|
-
A physical port within a Device (typically a designated console server) which provides access to ConsolePorts.
|
|
351
|
+
A physical port within a Device or Module (typically a designated console server) which provides access to ConsolePorts.
|
|
244
352
|
"""
|
|
245
353
|
|
|
246
354
|
type = models.CharField(
|
|
@@ -250,14 +358,6 @@ class ConsoleServerPort(CableTermination, PathEndpoint, ComponentModel):
|
|
|
250
358
|
help_text="Physical port type",
|
|
251
359
|
)
|
|
252
360
|
|
|
253
|
-
class Meta:
|
|
254
|
-
ordering = ("device", "_name")
|
|
255
|
-
unique_together = ("device", "name")
|
|
256
|
-
|
|
257
|
-
@property
|
|
258
|
-
def parent(self):
|
|
259
|
-
return self.device
|
|
260
|
-
|
|
261
361
|
|
|
262
362
|
#
|
|
263
363
|
# Power ports
|
|
@@ -272,9 +372,9 @@ class ConsoleServerPort(CableTermination, PathEndpoint, ComponentModel):
|
|
|
272
372
|
"graphql",
|
|
273
373
|
"webhooks",
|
|
274
374
|
)
|
|
275
|
-
class PowerPort(CableTermination, PathEndpoint
|
|
375
|
+
class PowerPort(ModularComponentModel, CableTermination, PathEndpoint):
|
|
276
376
|
"""
|
|
277
|
-
A physical power supply (intake) port within a Device. PowerPorts connect to PowerOutlets.
|
|
377
|
+
A physical power supply (intake) port within a Device or Module. PowerPorts connect to PowerOutlets.
|
|
278
378
|
"""
|
|
279
379
|
|
|
280
380
|
type = models.CharField(
|
|
@@ -296,14 +396,6 @@ class PowerPort(CableTermination, PathEndpoint, ComponentModel):
|
|
|
296
396
|
help_text="Allocated power draw (watts)",
|
|
297
397
|
)
|
|
298
398
|
|
|
299
|
-
class Meta:
|
|
300
|
-
ordering = ("device", "_name")
|
|
301
|
-
unique_together = ("device", "name")
|
|
302
|
-
|
|
303
|
-
@property
|
|
304
|
-
def parent(self):
|
|
305
|
-
return self.device
|
|
306
|
-
|
|
307
399
|
def clean(self):
|
|
308
400
|
super().clean()
|
|
309
401
|
|
|
@@ -383,9 +475,9 @@ class PowerPort(CableTermination, PathEndpoint, ComponentModel):
|
|
|
383
475
|
|
|
384
476
|
|
|
385
477
|
@extras_features("cable_terminations", "custom_links", "custom_validators", "graphql", "webhooks")
|
|
386
|
-
class PowerOutlet(CableTermination, PathEndpoint
|
|
478
|
+
class PowerOutlet(ModularComponentModel, CableTermination, PathEndpoint):
|
|
387
479
|
"""
|
|
388
|
-
A physical power outlet (output) within a Device which provides power to a PowerPort.
|
|
480
|
+
A physical power outlet (output) within a Device or Module which provides power to a PowerPort.
|
|
389
481
|
"""
|
|
390
482
|
|
|
391
483
|
type = models.CharField(
|
|
@@ -409,19 +501,11 @@ class PowerOutlet(CableTermination, PathEndpoint, ComponentModel):
|
|
|
409
501
|
help_text="Phase (for three-phase feeds)",
|
|
410
502
|
)
|
|
411
503
|
|
|
412
|
-
class Meta:
|
|
413
|
-
ordering = ("device", "_name")
|
|
414
|
-
unique_together = ("device", "name")
|
|
415
|
-
|
|
416
|
-
@property
|
|
417
|
-
def parent(self):
|
|
418
|
-
return self.device
|
|
419
|
-
|
|
420
504
|
def clean(self):
|
|
421
505
|
super().clean()
|
|
422
506
|
|
|
423
507
|
# Validate power port assignment
|
|
424
|
-
if self.power_port and self.power_port.
|
|
508
|
+
if self.power_port and self.parent and self.power_port.parent != self.parent:
|
|
425
509
|
raise ValidationError(f"Parent power port ({self.power_port}) must belong to the same device")
|
|
426
510
|
|
|
427
511
|
|
|
@@ -445,6 +529,7 @@ class BaseInterface(RelationshipModel):
|
|
|
445
529
|
validators=[MinValueValidator(1), MaxValueValidator(65536)],
|
|
446
530
|
verbose_name="MTU",
|
|
447
531
|
)
|
|
532
|
+
role = RoleField(blank=True, null=True)
|
|
448
533
|
mode = models.CharField(max_length=50, choices=InterfaceModeChoices, blank=True)
|
|
449
534
|
parent_interface = models.ForeignKey(
|
|
450
535
|
to="self",
|
|
@@ -499,9 +584,9 @@ class BaseInterface(RelationshipModel):
|
|
|
499
584
|
"statuses",
|
|
500
585
|
"webhooks",
|
|
501
586
|
)
|
|
502
|
-
class Interface(CableTermination, PathEndpoint,
|
|
587
|
+
class Interface(ModularComponentModel, CableTermination, PathEndpoint, BaseInterface):
|
|
503
588
|
"""
|
|
504
|
-
A network interface within a Device. A physical Interface can connect to exactly one other Interface.
|
|
589
|
+
A network interface within a Device or Module. A physical Interface can connect to exactly one other Interface.
|
|
505
590
|
"""
|
|
506
591
|
|
|
507
592
|
# Override ComponentModel._name to specify naturalize_interface function
|
|
@@ -558,15 +643,14 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface):
|
|
|
558
643
|
verbose_name="IP Addresses",
|
|
559
644
|
)
|
|
560
645
|
|
|
561
|
-
class Meta:
|
|
562
|
-
ordering = ("device", CollateAsChar("_name"))
|
|
563
|
-
unique_together = ("device", "name")
|
|
646
|
+
class Meta(ModularComponentModel.Meta):
|
|
647
|
+
ordering = ("device", "module", CollateAsChar("_name"))
|
|
564
648
|
|
|
565
649
|
def clean(self):
|
|
566
650
|
super().clean()
|
|
567
651
|
|
|
568
652
|
# VRF validation
|
|
569
|
-
if self.vrf and self.vrf not in self.
|
|
653
|
+
if self.vrf and self.parent and self.vrf not in self.parent.vrfs.all():
|
|
570
654
|
# TODO(jathan): Or maybe we automatically add the VRF to the device?
|
|
571
655
|
raise ValidationError({"vrf": "VRF must be assigned to same Device."})
|
|
572
656
|
|
|
@@ -577,19 +661,23 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface):
|
|
|
577
661
|
raise ValidationError({"lag": "A LAG interface cannot be its own parent."})
|
|
578
662
|
|
|
579
663
|
# An interface's LAG must belong to the same device or virtual chassis
|
|
580
|
-
if self.lag.
|
|
581
|
-
if self.
|
|
664
|
+
if self.parent and self.lag.parent != self.parent:
|
|
665
|
+
if self.lag.parent is None:
|
|
666
|
+
raise ValidationError(
|
|
667
|
+
{"lag": f"The selected LAG interface ({self.lag}) does not belong to a device."}
|
|
668
|
+
)
|
|
669
|
+
elif self.parent.virtual_chassis is None:
|
|
582
670
|
raise ValidationError(
|
|
583
671
|
{
|
|
584
|
-
"lag": f"The selected LAG interface ({self.lag}) belongs to a different device ({self.lag.
|
|
672
|
+
"lag": f"The selected LAG interface ({self.lag}) belongs to a different device ({self.lag.parent})."
|
|
585
673
|
}
|
|
586
674
|
)
|
|
587
|
-
elif self.lag.
|
|
675
|
+
elif self.lag.parent.virtual_chassis_id != self.parent.virtual_chassis_id:
|
|
588
676
|
raise ValidationError(
|
|
589
677
|
{
|
|
590
678
|
"lag": (
|
|
591
|
-
f"The selected LAG interface ({self.lag}) belongs to {self.lag.
|
|
592
|
-
f"of virtual chassis {self.
|
|
679
|
+
f"The selected LAG interface ({self.lag}) belongs to {self.lag.parent}, which is not part "
|
|
680
|
+
f"of virtual chassis {self.parent.virtual_chassis}."
|
|
593
681
|
)
|
|
594
682
|
}
|
|
595
683
|
)
|
|
@@ -622,19 +710,19 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface):
|
|
|
622
710
|
)
|
|
623
711
|
|
|
624
712
|
# An interface's parent must belong to the same device or virtual chassis
|
|
625
|
-
if self.parent_interface.
|
|
626
|
-
if getattr(self.
|
|
713
|
+
if self.parent and self.parent_interface.parent != self.parent:
|
|
714
|
+
if getattr(self.parent, "virtual_chassis", None) is None:
|
|
627
715
|
raise ValidationError(
|
|
628
716
|
{
|
|
629
717
|
"parent_interface": f"The selected parent interface ({self.parent_interface}) belongs to a different device "
|
|
630
|
-
f"({self.parent_interface.
|
|
718
|
+
f"({self.parent_interface.parent})."
|
|
631
719
|
}
|
|
632
720
|
)
|
|
633
|
-
elif self.parent_interface.
|
|
721
|
+
elif self.parent_interface.parent.virtual_chassis != self.parent.virtual_chassis:
|
|
634
722
|
raise ValidationError(
|
|
635
723
|
{
|
|
636
|
-
"parent_interface": f"The selected parent interface ({self.parent_interface}) belongs to {self.parent_interface.
|
|
637
|
-
f"is not part of virtual chassis {self.
|
|
724
|
+
"parent_interface": f"The selected parent interface ({self.parent_interface}) belongs to {self.parent_interface.parent}, which "
|
|
725
|
+
f"is not part of virtual chassis {self.parent.virtual_chassis}."
|
|
638
726
|
}
|
|
639
727
|
)
|
|
640
728
|
|
|
@@ -644,7 +732,8 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface):
|
|
|
644
732
|
if (
|
|
645
733
|
self.untagged_vlan
|
|
646
734
|
and self.untagged_vlan.locations.exists()
|
|
647
|
-
and
|
|
735
|
+
and self.parent
|
|
736
|
+
and not self.untagged_vlan.locations.filter(id=self.parent.location_id).exists()
|
|
648
737
|
):
|
|
649
738
|
raise ValidationError(
|
|
650
739
|
{
|
|
@@ -662,22 +751,22 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface):
|
|
|
662
751
|
raise ValidationError({"bridge": "An interface cannot be bridged to itself."})
|
|
663
752
|
|
|
664
753
|
# A bridged interface belong to the same device or virtual chassis
|
|
665
|
-
if self.bridge.
|
|
666
|
-
if getattr(self.
|
|
754
|
+
if self.parent and self.bridge.parent != self.parent:
|
|
755
|
+
if getattr(self.parent, "virtual_chassis", None) is None:
|
|
667
756
|
raise ValidationError(
|
|
668
757
|
{
|
|
669
758
|
"bridge": (
|
|
670
759
|
f"The selected bridge interface ({self.bridge}) belongs to a different device "
|
|
671
|
-
f"({self.bridge.
|
|
760
|
+
f"({self.bridge.parent})."
|
|
672
761
|
)
|
|
673
762
|
}
|
|
674
763
|
)
|
|
675
|
-
elif self.bridge.
|
|
764
|
+
elif self.bridge.parent.virtual_chassis_id != self.parent.virtual_chassis_id:
|
|
676
765
|
raise ValidationError(
|
|
677
766
|
{
|
|
678
767
|
"bridge": (
|
|
679
|
-
f"The selected bridge interface ({self.bridge}) belongs to {self.bridge.
|
|
680
|
-
f"is not part of virtual chassis {self.
|
|
768
|
+
f"The selected bridge interface ({self.bridge}) belongs to {self.bridge.parent}, which "
|
|
769
|
+
f"is not part of virtual chassis {self.parent.virtual_chassis}."
|
|
681
770
|
)
|
|
682
771
|
}
|
|
683
772
|
)
|
|
@@ -765,10 +854,6 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface):
|
|
|
765
854
|
def ip_address_count(self):
|
|
766
855
|
return self.ip_addresses.count()
|
|
767
856
|
|
|
768
|
-
@property
|
|
769
|
-
def parent(self):
|
|
770
|
-
return self.device
|
|
771
|
-
|
|
772
857
|
|
|
773
858
|
@extras_features(
|
|
774
859
|
"custom_fields",
|
|
@@ -878,6 +963,7 @@ class InterfaceRedundancyGroupAssociation(BaseModel, ChangeLoggedModel):
|
|
|
878
963
|
related_name="interface_redundancy_group_associations",
|
|
879
964
|
)
|
|
880
965
|
priority = models.PositiveSmallIntegerField()
|
|
966
|
+
is_metadata_associable_model = False
|
|
881
967
|
|
|
882
968
|
class Meta:
|
|
883
969
|
"""Meta class."""
|
|
@@ -887,7 +973,7 @@ class InterfaceRedundancyGroupAssociation(BaseModel, ChangeLoggedModel):
|
|
|
887
973
|
|
|
888
974
|
def __str__(self):
|
|
889
975
|
"""Return a string representation of the instance."""
|
|
890
|
-
return f"{self.interface_redundancy_group}: {self.interface.device} {self.interface}: {self.priority}"
|
|
976
|
+
return f"{self.interface_redundancy_group}: {self.interface.device or self.interface.module} {self.interface}: {self.priority}"
|
|
891
977
|
|
|
892
978
|
|
|
893
979
|
#
|
|
@@ -896,9 +982,9 @@ class InterfaceRedundancyGroupAssociation(BaseModel, ChangeLoggedModel):
|
|
|
896
982
|
|
|
897
983
|
|
|
898
984
|
@extras_features("cable_terminations", "custom_links", "custom_validators", "graphql", "webhooks")
|
|
899
|
-
class FrontPort(
|
|
985
|
+
class FrontPort(ModularComponentModel, CableTermination):
|
|
900
986
|
"""
|
|
901
|
-
A pass-through port on the front of a Device.
|
|
987
|
+
A pass-through port on the front of a Device or Module.
|
|
902
988
|
"""
|
|
903
989
|
|
|
904
990
|
type = models.CharField(max_length=50, choices=PortTypeChoices)
|
|
@@ -911,22 +997,22 @@ class FrontPort(CableTermination, ComponentModel):
|
|
|
911
997
|
],
|
|
912
998
|
)
|
|
913
999
|
|
|
914
|
-
|
|
915
|
-
ordering = ("device", "_name")
|
|
916
|
-
unique_together = (
|
|
917
|
-
("device", "name"),
|
|
918
|
-
("rear_port", "rear_port_position"),
|
|
919
|
-
)
|
|
1000
|
+
natural_key_field_names = ["device", "module", "name", "rear_port", "rear_port_position"]
|
|
920
1001
|
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1002
|
+
class Meta(ModularComponentModel.Meta):
|
|
1003
|
+
constraints = [
|
|
1004
|
+
*ModularComponentModel.Meta.constraints,
|
|
1005
|
+
models.UniqueConstraint(
|
|
1006
|
+
fields=("rear_port", "rear_port_position"),
|
|
1007
|
+
name="dcim_frontport_rear_port_position_unique",
|
|
1008
|
+
),
|
|
1009
|
+
]
|
|
924
1010
|
|
|
925
1011
|
def clean(self):
|
|
926
1012
|
super().clean()
|
|
927
1013
|
|
|
928
1014
|
# Validate rear port assignment
|
|
929
|
-
if self.rear_port.
|
|
1015
|
+
if self.parent and self.rear_port.parent != self.parent:
|
|
930
1016
|
raise ValidationError({"rear_port": f"Rear port ({self.rear_port}) must belong to the same device"})
|
|
931
1017
|
|
|
932
1018
|
# Validate rear port position assignment
|
|
@@ -940,9 +1026,9 @@ class FrontPort(CableTermination, ComponentModel):
|
|
|
940
1026
|
|
|
941
1027
|
|
|
942
1028
|
@extras_features("cable_terminations", "custom_links", "custom_validators", "graphql", "webhooks")
|
|
943
|
-
class RearPort(
|
|
1029
|
+
class RearPort(ModularComponentModel, CableTermination):
|
|
944
1030
|
"""
|
|
945
|
-
A pass-through port on the rear of a Device.
|
|
1031
|
+
A pass-through port on the rear of a Device or Module.
|
|
946
1032
|
"""
|
|
947
1033
|
|
|
948
1034
|
type = models.CharField(max_length=50, choices=PortTypeChoices)
|
|
@@ -954,10 +1040,6 @@ class RearPort(CableTermination, ComponentModel):
|
|
|
954
1040
|
],
|
|
955
1041
|
)
|
|
956
1042
|
|
|
957
|
-
class Meta:
|
|
958
|
-
ordering = ("device", "_name")
|
|
959
|
-
unique_together = ("device", "name")
|
|
960
|
-
|
|
961
1043
|
def clean(self):
|
|
962
1044
|
super().clean()
|
|
963
1045
|
|
|
@@ -971,10 +1053,6 @@ class RearPort(CableTermination, ComponentModel):
|
|
|
971
1053
|
}
|
|
972
1054
|
)
|
|
973
1055
|
|
|
974
|
-
@property
|
|
975
|
-
def parent(self):
|
|
976
|
-
return self.device
|
|
977
|
-
|
|
978
1056
|
|
|
979
1057
|
#
|
|
980
1058
|
# Device bays
|
|
@@ -1019,10 +1097,12 @@ class DeviceBay(ComponentModel):
|
|
|
1019
1097
|
"installed_device": f"Cannot install the specified device; device is already installed in {current_bay}"
|
|
1020
1098
|
}
|
|
1021
1099
|
)
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1100
|
+
if self.installed_device.device_type.subdevice_role != SubdeviceRoleChoices.ROLE_CHILD:
|
|
1101
|
+
raise ValidationError(
|
|
1102
|
+
{
|
|
1103
|
+
"installed_device": f'Cannot install device "{self.installed_device}"; device-type "{self.installed_device.device_type}" subdevice_role is not "child".'
|
|
1104
|
+
}
|
|
1105
|
+
)
|
|
1026
1106
|
|
|
1027
1107
|
|
|
1028
1108
|
#
|
|
@@ -1072,7 +1152,8 @@ class InventoryItem(TreeModel, ComponentModel):
|
|
|
1072
1152
|
related_name="inventory_items",
|
|
1073
1153
|
blank=True,
|
|
1074
1154
|
null=True,
|
|
1075
|
-
verbose_name="
|
|
1155
|
+
verbose_name="Software Version",
|
|
1156
|
+
help_text="The software version installed on this inventory item",
|
|
1076
1157
|
)
|
|
1077
1158
|
software_image_files = models.ManyToManyField(
|
|
1078
1159
|
to="dcim.SoftwareImageFile",
|
|
@@ -1094,3 +1175,105 @@ class InventoryItem(TreeModel, ComponentModel):
|
|
|
1094
1175
|
For the time being we just use the PK as a natural key.
|
|
1095
1176
|
"""
|
|
1096
1177
|
return ["pk"]
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
@extras_features(
|
|
1181
|
+
"custom_links",
|
|
1182
|
+
"custom_validators",
|
|
1183
|
+
"export_templates",
|
|
1184
|
+
"graphql",
|
|
1185
|
+
"webhooks",
|
|
1186
|
+
)
|
|
1187
|
+
class ModuleBay(PrimaryModel):
|
|
1188
|
+
"""
|
|
1189
|
+
A slot in a Device or Module which can contain Modules.
|
|
1190
|
+
"""
|
|
1191
|
+
|
|
1192
|
+
parent_device = models.ForeignKey(
|
|
1193
|
+
to="dcim.Device",
|
|
1194
|
+
on_delete=models.CASCADE,
|
|
1195
|
+
related_name="module_bays",
|
|
1196
|
+
blank=True,
|
|
1197
|
+
null=True,
|
|
1198
|
+
)
|
|
1199
|
+
parent_module = models.ForeignKey(
|
|
1200
|
+
to="dcim.Module",
|
|
1201
|
+
on_delete=models.CASCADE,
|
|
1202
|
+
related_name="module_bays",
|
|
1203
|
+
blank=True,
|
|
1204
|
+
null=True,
|
|
1205
|
+
)
|
|
1206
|
+
name = models.CharField(max_length=CHARFIELD_MAX_LENGTH, db_index=True)
|
|
1207
|
+
_name = NaturalOrderingField(target_field="name", max_length=CHARFIELD_MAX_LENGTH, blank=True, db_index=True)
|
|
1208
|
+
position = models.CharField(
|
|
1209
|
+
blank=True,
|
|
1210
|
+
max_length=CHARFIELD_MAX_LENGTH,
|
|
1211
|
+
help_text="The position of the module bay within the parent device/module",
|
|
1212
|
+
)
|
|
1213
|
+
label = models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True, help_text="Physical label")
|
|
1214
|
+
description = models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True)
|
|
1215
|
+
|
|
1216
|
+
clone_fields = ["parent_device", "parent_module"]
|
|
1217
|
+
|
|
1218
|
+
# The recursive nature of this model combined with the fact that it can be a child of a
|
|
1219
|
+
# device or location makes our natural key implementation unusable, so just use the pk
|
|
1220
|
+
natural_key_field_names = ["pk"]
|
|
1221
|
+
|
|
1222
|
+
class Meta:
|
|
1223
|
+
# TODO: Ordering by parent_module.id is not correct but prevents an infinite loop
|
|
1224
|
+
ordering = (
|
|
1225
|
+
"parent_device",
|
|
1226
|
+
"parent_module__id",
|
|
1227
|
+
"_name",
|
|
1228
|
+
)
|
|
1229
|
+
constraints = [
|
|
1230
|
+
models.UniqueConstraint(
|
|
1231
|
+
fields=["parent_device", "name"],
|
|
1232
|
+
name="dcim_modulebay_parent_device_name_unique",
|
|
1233
|
+
),
|
|
1234
|
+
models.UniqueConstraint(
|
|
1235
|
+
fields=["parent_module", "name"],
|
|
1236
|
+
name="dcim_modulebay_parent_module_name_unique",
|
|
1237
|
+
),
|
|
1238
|
+
]
|
|
1239
|
+
|
|
1240
|
+
@property
|
|
1241
|
+
def parent(self):
|
|
1242
|
+
"""Walk up parent chain to find the Device that this ModuleBay is installed in, if one exists."""
|
|
1243
|
+
return self.parent_module.device if self.parent_module else self.parent_device
|
|
1244
|
+
|
|
1245
|
+
def __str__(self):
|
|
1246
|
+
if self.parent_device is not None:
|
|
1247
|
+
return f"{self.parent_device} ({self.name})"
|
|
1248
|
+
else:
|
|
1249
|
+
return f"{self.parent_module} ({self.name})"
|
|
1250
|
+
|
|
1251
|
+
@property
|
|
1252
|
+
def display(self):
|
|
1253
|
+
if self.parent_device is not None:
|
|
1254
|
+
return f"{self.parent_device.display} ({self.name})"
|
|
1255
|
+
else:
|
|
1256
|
+
return f"{self.parent_module.display} ({self.name})"
|
|
1257
|
+
|
|
1258
|
+
def to_objectchange(self, action, **kwargs):
|
|
1259
|
+
"""
|
|
1260
|
+
Return a new ObjectChange with the `related_object` pinned to the parent `device` or `module`.
|
|
1261
|
+
"""
|
|
1262
|
+
# Annotate the parent
|
|
1263
|
+
try:
|
|
1264
|
+
parent = self.parent
|
|
1265
|
+
except ObjectDoesNotExist:
|
|
1266
|
+
# The parent has already been deleted
|
|
1267
|
+
parent = None
|
|
1268
|
+
|
|
1269
|
+
return super().to_objectchange(action, related_object=parent, **kwargs)
|
|
1270
|
+
|
|
1271
|
+
def clean(self):
|
|
1272
|
+
super().clean()
|
|
1273
|
+
|
|
1274
|
+
# Validate that a Device or Module is set, but not both
|
|
1275
|
+
if self.parent_device and self.parent_module:
|
|
1276
|
+
raise ValidationError("Only one of parent_device or parent_module must be set")
|
|
1277
|
+
|
|
1278
|
+
if not (self.parent_device or self.parent_module):
|
|
1279
|
+
raise ValidationError("Either parent_device or parent_module must be set")
|