nautobot 2.4.17__py3-none-any.whl → 2.4.19__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/ui.py +6 -0
- nautobot/apps/views.py +2 -0
- nautobot/circuits/tables.py +1 -1
- nautobot/circuits/templates/circuits/circuit_create.html +7 -7
- nautobot/circuits/templates/circuits/circuit_retrieve.html +1 -5
- nautobot/circuits/templates/circuits/circuittermination_create.html +26 -26
- nautobot/circuits/templates/circuits/circuittermination_retrieve.html +1 -8
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +20 -20
- nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +3 -3
- nautobot/circuits/templates/circuits/inc/circuit_termination_speed_fragment.html +9 -0
- nautobot/circuits/templates/circuits/providernetwork_retrieve.html +1 -3
- nautobot/circuits/tests/integration/test_circuit.py +2 -2
- nautobot/circuits/views.py +49 -15
- nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +1 -4
- nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +1 -7
- nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +1 -3
- nautobot/cloud/templates/cloud/cloudservice_retrieve.html +1 -5
- nautobot/cloud/views.py +45 -0
- nautobot/core/filters.py +2 -2
- nautobot/core/graphql/generators.py +5 -2
- nautobot/core/jobs/bulk_actions.py +48 -85
- nautobot/core/models/querysets.py +2 -1
- nautobot/core/settings.py +1 -0
- nautobot/core/settings.yaml +9 -0
- nautobot/core/tables.py +21 -23
- nautobot/core/templates/40x.html +15 -15
- nautobot/core/templates/500.html +21 -21
- nautobot/core/templates/admin/app_index.html +8 -8
- nautobot/core/templates/admin/base.html +104 -104
- nautobot/core/templates/admin/change_form.html +65 -65
- nautobot/core/templates/admin/change_list.html +60 -60
- nautobot/core/templates/admin/change_list_results.html +39 -39
- nautobot/core/templates/admin/config/config.html +47 -47
- nautobot/core/templates/admin/delete_confirmation.html +47 -47
- nautobot/core/templates/admin/edit_inline/stacked.html +124 -124
- nautobot/core/templates/admin/edit_inline/tabular.html +60 -60
- nautobot/core/templates/admin/includes/fieldset.html +4 -4
- nautobot/core/templates/admin/index.html +60 -60
- nautobot/core/templates/admin/prepopulated_fields_js.html +18 -18
- nautobot/core/templates/admin/submit_line.html +4 -4
- nautobot/core/templates/base_django.html +46 -46
- nautobot/core/templates/buttons/consolidated_bulk_action_buttons.html +8 -8
- nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +8 -8
- nautobot/core/templates/buttons/export.html +3 -3
- nautobot/core/templates/components/breadcrumbs.html +19 -0
- nautobot/core/templates/components/button/default.html +3 -3
- nautobot/core/templates/components/button/dropdown.html +7 -7
- nautobot/core/templates/components/button/formbutton.html +4 -4
- nautobot/core/templates/components/panel/body_content_data_table.html +1 -1
- nautobot/core/templates/components/panel/body_wrapper_generic_table.html +3 -0
- nautobot/core/templates/components/panel/footer_content_table.html +3 -1
- nautobot/core/templates/components/panel/header_extra_content_table.html +10 -1
- nautobot/core/templates/components/tab/content_wrapper.html +1 -1
- nautobot/core/templates/components/tab/label_wrapper.html +1 -1
- nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +10 -3
- nautobot/core/templates/generic/object_bulk_add_component.html +40 -40
- nautobot/core/templates/generic/object_bulk_create.html +3 -3
- nautobot/core/templates/generic/object_bulk_destroy.html +6 -6
- nautobot/core/templates/generic/object_bulk_update.html +52 -52
- nautobot/core/templates/generic/object_changelog.html +0 -2
- nautobot/core/templates/generic/object_import.html +33 -33
- nautobot/core/templates/generic/object_list.html +271 -268
- nautobot/core/templates/generic/object_notes.html +0 -2
- nautobot/core/templates/generic/object_retrieve.html +264 -257
- nautobot/core/templates/graphene/graphiql.html +127 -127
- nautobot/core/templates/home.html +62 -62
- nautobot/core/templates/inc/computed_fields/panel_data.html +13 -13
- nautobot/core/templates/inc/created_updated.html +8 -8
- nautobot/core/templates/inc/custom_fields/panel_data.html +13 -13
- nautobot/core/templates/inc/dynamic_groups_panel.html +11 -11
- nautobot/core/templates/inc/footer.html +19 -19
- nautobot/core/templates/inc/javascript.html +1 -1
- nautobot/core/templates/inc/media.html +46 -46
- nautobot/core/templates/inc/nav_menu.html +1 -1
- nautobot/core/templates/inc/relationships_table_rows.html +22 -22
- nautobot/core/templates/inc/tenant_table_row.html +1 -1
- nautobot/core/templates/login.html +77 -77
- nautobot/core/templates/media_failure.html +38 -38
- nautobot/core/templates/panel_table.html +1 -1
- nautobot/core/templates/rest_framework/api.html +3 -3
- nautobot/core/templates/search.html +1 -1
- nautobot/core/templates/swagger_ui.html +9 -9
- nautobot/core/templates/utilities/confirmation_form.html +18 -18
- nautobot/core/templates/utilities/render_field.html +1 -1
- nautobot/core/templates/utilities/render_jinja2.html +43 -43
- nautobot/core/templates/utilities/templatetags/filter_form_modal.html +56 -56
- nautobot/core/templates/utilities/templatetags/utilization_graph.html +1 -1
- nautobot/core/templates/utilities/theme_preview.html +799 -799
- nautobot/core/templates/utilities/worker_status.html +122 -122
- nautobot/core/templates/widgets/clearable_file.html +3 -3
- nautobot/core/templates/widgets/sluginput.html +1 -1
- nautobot/core/templatetags/buttons.py +8 -2
- nautobot/core/templatetags/helpers.py +24 -0
- nautobot/core/templatetags/ui_framework.py +40 -5
- nautobot/core/testing/filters.py +37 -21
- nautobot/core/testing/integration.py +7 -4
- nautobot/core/testing/views.py +49 -5
- nautobot/core/tests/test_breadcrumbs.py +78 -4
- nautobot/core/tests/test_commands.py +7 -4
- nautobot/core/tests/test_graphql.py +20 -5
- nautobot/core/tests/test_jobs.py +34 -21
- nautobot/core/tests/test_tables.py +43 -6
- nautobot/core/tests/test_templatetags_ui_framework.py +146 -0
- nautobot/core/tests/test_titles.py +2 -2
- nautobot/core/tests/test_ui.py +188 -1
- nautobot/core/tests/test_utils.py +35 -0
- nautobot/core/tests/test_views.py +45 -0
- nautobot/core/tests/test_views_generic.py +43 -0
- nautobot/core/tests/test_views_utils.py +239 -5
- nautobot/core/ui/breadcrumbs.py +220 -28
- nautobot/core/ui/bulk_buttons.py +8 -0
- nautobot/core/ui/object_detail.py +181 -60
- nautobot/core/ui/titles.py +10 -5
- nautobot/core/utils/requests.py +27 -2
- nautobot/core/views/__init__.py +24 -3
- nautobot/core/views/generic.py +70 -35
- nautobot/core/views/mixins.py +226 -122
- nautobot/core/views/utils.py +270 -1
- nautobot/dcim/api/serializers.py +8 -2
- nautobot/dcim/constants.py +1 -0
- nautobot/dcim/factory.py +4 -3
- nautobot/dcim/filters/mixins.py +1 -2
- nautobot/dcim/forms.py +5 -1
- nautobot/dcim/migrations/0074_alter_rack_u_height.py +21 -0
- nautobot/dcim/models/devices.py +30 -1
- nautobot/dcim/models/racks.py +2 -2
- nautobot/dcim/tables/__init__.py +2 -0
- nautobot/dcim/tables/devices.py +24 -0
- nautobot/dcim/tables/power.py +2 -2
- nautobot/dcim/templates/dcim/cable.html +53 -53
- nautobot/dcim/templates/dcim/cable_connect.html +182 -182
- nautobot/dcim/templates/dcim/cable_trace.html +1 -1
- nautobot/dcim/templates/dcim/console_port_connection_list.html +5 -5
- nautobot/dcim/templates/dcim/consoleport.html +86 -86
- nautobot/dcim/templates/dcim/consoleserverport.html +86 -86
- nautobot/dcim/templates/dcim/controller_create.html +34 -34
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +68 -68
- nautobot/dcim/templates/dcim/device/base.html +1 -114
- nautobot/dcim/templates/dcim/device/config.html +17 -17
- nautobot/dcim/templates/dcim/device/consoleports.html +1 -52
- nautobot/dcim/templates/dcim/device/consoleserverports.html +1 -52
- nautobot/dcim/templates/dcim/device/devicebays.html +1 -48
- nautobot/dcim/templates/dcim/device/frontports.html +1 -52
- nautobot/dcim/templates/dcim/device/interfaces.html +1 -56
- nautobot/dcim/templates/dcim/device/inventory.html +1 -48
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +64 -64
- nautobot/dcim/templates/dcim/device/modulebays.html +1 -48
- nautobot/dcim/templates/dcim/device/poweroutlets.html +1 -52
- nautobot/dcim/templates/dcim/device/powerports.html +1 -52
- nautobot/dcim/templates/dcim/device/rearports.html +1 -52
- nautobot/dcim/templates/dcim/device/status.html +66 -66
- nautobot/dcim/templates/dcim/device/wireless.html +1 -72
- nautobot/dcim/templates/dcim/device.html +4 -422
- nautobot/dcim/templates/dcim/device_component.html +0 -19
- nautobot/dcim/templates/dcim/device_component_add.html +25 -25
- nautobot/dcim/templates/dcim/device_create.html +229 -0
- nautobot/dcim/templates/dcim/device_edit.html +2 -227
- nautobot/dcim/templates/dcim/devicebay.html +41 -41
- nautobot/dcim/templates/dcim/devicebay_populate.html +32 -32
- nautobot/dcim/templates/dcim/devicetype_component_add.html +28 -28
- nautobot/dcim/templates/dcim/devicetype_retrieve.html +1 -3
- nautobot/dcim/templates/dcim/frontport.html +84 -84
- nautobot/dcim/templates/dcim/inc/cable_toggle_buttons.html +1 -1
- nautobot/dcim/templates/dcim/inc/device_interface_filter.html +8 -0
- nautobot/dcim/templates/dcim/inc/device_napalm_tabs.html +1 -15
- nautobot/dcim/templates/dcim/inc/location_hierarchy.html +22 -22
- nautobot/dcim/templates/dcim/interface.html +206 -206
- nautobot/dcim/templates/dcim/interface_connection_list.html +5 -5
- nautobot/dcim/templates/dcim/interfaceredundancygroupassociation_create.html +6 -6
- nautobot/dcim/templates/dcim/inventoryitem.html +44 -44
- nautobot/dcim/templates/dcim/inventoryitem_add.html +32 -32
- nautobot/dcim/templates/dcim/inventoryitem_edit.html +22 -22
- nautobot/dcim/templates/dcim/location_migrate_data_to_contact.html +46 -46
- nautobot/dcim/templates/dcim/location_retrieve.html +1 -7
- nautobot/dcim/templates/dcim/locationtype.html +1 -6
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +1 -7
- nautobot/dcim/templates/dcim/module/base.html +85 -85
- nautobot/dcim/templates/dcim/module_interfaces.html +1 -1
- nautobot/dcim/templates/dcim/module_modulebays.html +1 -1
- nautobot/dcim/templates/dcim/module_retrieve.html +52 -52
- nautobot/dcim/templates/dcim/module_update.html +61 -61
- nautobot/dcim/templates/dcim/modulebay_destroy.html +1 -1
- nautobot/dcim/templates/dcim/modulebay_retrieve.html +83 -99
- nautobot/dcim/templates/dcim/modulebay_update.html +33 -33
- nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +140 -144
- nautobot/dcim/templates/dcim/platform_create.html +38 -38
- nautobot/dcim/templates/dcim/power_port_connection_list.html +5 -5
- nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -8
- nautobot/dcim/templates/dcim/poweroutlet.html +85 -85
- nautobot/dcim/templates/dcim/powerpanel_retrieve.html +1 -8
- nautobot/dcim/templates/dcim/powerport.html +91 -91
- nautobot/dcim/templates/dcim/rack_elevation_list.html +18 -18
- nautobot/dcim/templates/dcim/rack_retrieve.html +264 -274
- nautobot/dcim/templates/dcim/rackreservation_retrieve.html +0 -3
- nautobot/dcim/templates/dcim/rearport.html +78 -78
- nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +1 -50
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -5
- nautobot/dcim/tests/integration/test_device_bulk_operations.py +3 -2
- nautobot/dcim/tests/integration/test_location_bulk_operations.py +6 -2
- nautobot/dcim/tests/test_api.py +33 -1
- nautobot/dcim/tests/test_views.py +189 -4
- nautobot/dcim/ui.py +29 -0
- nautobot/dcim/urls.py +1 -109
- nautobot/dcim/utils.py +30 -0
- nautobot/dcim/views.py +1149 -550
- nautobot/extras/filters/mixins.py +1 -1
- nautobot/extras/forms/forms.py +15 -0
- nautobot/extras/models/groups.py +10 -1
- nautobot/extras/models/jobs.py +2 -2
- nautobot/extras/plugins/views.py +18 -5
- nautobot/extras/tables.py +24 -2
- nautobot/extras/templates/extras/computedfield_edit.html +4 -4
- nautobot/extras/templates/extras/configcontext_update.html +1 -1
- nautobot/extras/templates/extras/configcontextschema_retrieve.html +32 -32
- nautobot/extras/templates/extras/customfield_retrieve.html +1 -128
- nautobot/extras/templates/extras/customfield_update.html +23 -23
- nautobot/extras/templates/extras/dynamicgroup.html +2 -99
- nautobot/extras/templates/extras/dynamicgroup_edit.html +2 -199
- nautobot/extras/templates/extras/dynamicgroup_retrieve.html +99 -0
- nautobot/extras/templates/extras/dynamicgroup_update.html +199 -0
- nautobot/extras/templates/extras/gitrepository.html +2 -82
- nautobot/extras/templates/extras/gitrepository_list.html +10 -10
- nautobot/extras/templates/extras/gitrepository_object_edit.html +2 -13
- nautobot/extras/templates/extras/gitrepository_retrieve.html +82 -0
- nautobot/extras/templates/extras/gitrepository_update.html +13 -0
- nautobot/extras/templates/extras/graphqlquery_retrieve.html +73 -73
- nautobot/extras/templates/extras/inc/configcontext_format.html +2 -2
- nautobot/extras/templates/extras/inc/job_table.html +10 -10
- nautobot/extras/templates/extras/inc/jobresult.html +21 -21
- nautobot/extras/templates/extras/inc/jobresult_js.html +6 -6
- nautobot/extras/templates/extras/inc/tags_panel.html +10 -10
- nautobot/extras/templates/extras/job.html +64 -64
- nautobot/extras/templates/extras/job_approval_request.html +9 -9
- nautobot/extras/templates/extras/job_bulk_edit.html +13 -13
- nautobot/extras/templates/extras/job_edit.html +45 -45
- nautobot/extras/templates/extras/job_list.html +4 -4
- nautobot/extras/templates/extras/jobresult_retrieve.html +0 -25
- nautobot/extras/templates/extras/marketplace.html +101 -101
- nautobot/extras/templates/extras/metadatatype_create.html +20 -20
- nautobot/extras/templates/extras/note_retrieve.html +0 -52
- nautobot/extras/templates/extras/object_assign_contact_or_team.html +18 -18
- nautobot/extras/templates/extras/object_configcontext.html +1 -3
- nautobot/extras/templates/extras/objectchange.html +2 -165
- nautobot/extras/templates/extras/objectchange_retrieve.html +165 -0
- nautobot/extras/templates/extras/plugin_detail.html +44 -48
- nautobot/extras/templates/extras/plugins_list.html +9 -11
- nautobot/extras/templates/extras/plugins_tiles.html +26 -26
- nautobot/extras/templates/extras/relationship_edit.html +4 -4
- nautobot/extras/templates/extras/role_retrieve.html +13 -13
- nautobot/extras/templates/extras/scheduled_jobs_approval_queue_list.html +21 -21
- nautobot/extras/templates/extras/scheduledjob.html +128 -128
- nautobot/extras/templates/extras/secret_create.html +53 -53
- nautobot/extras/templates/extras/secretsgroup_update.html +13 -13
- nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +3 -3
- nautobot/extras/templates/extras/webhook.html +79 -79
- nautobot/extras/tests/integration/test_relationships.py +6 -6
- nautobot/extras/tests/test_dynamicgroups.py +73 -18
- nautobot/extras/tests/test_filters.py +1 -1
- nautobot/extras/tests/test_jobs.py +2 -0
- nautobot/extras/tests/test_views.py +8 -3
- nautobot/extras/urls.py +3 -97
- nautobot/extras/views.py +524 -456
- nautobot/ipam/filters.py +2 -2
- nautobot/ipam/migrations/0053_alter_vrfdeviceassignment_options_and_more.py +20 -0
- nautobot/ipam/models.py +34 -0
- nautobot/ipam/querysets.py +3 -3
- nautobot/ipam/signals.py +6 -1
- nautobot/ipam/tables.py +3 -1
- nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +4 -0
- nautobot/ipam/templates/ipam/inc/toggle_available.html +8 -8
- nautobot/ipam/templates/ipam/inc/vlangroup_header.html +4 -4
- nautobot/ipam/templates/ipam/ipaddress.html +119 -123
- nautobot/ipam/templates/ipam/ipaddress_assign.html +10 -10
- nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -1
- nautobot/ipam/templates/ipam/ipaddress_merge.html +180 -180
- nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +48 -48
- nautobot/ipam/templates/ipam/prefix.html +2 -115
- nautobot/ipam/templates/ipam/prefix_create.html +34 -0
- nautobot/ipam/templates/ipam/prefix_edit.html +1 -34
- nautobot/ipam/templates/ipam/prefix_retrieve.html +3 -0
- nautobot/ipam/templates/ipam/service_retrieve.html +1 -6
- nautobot/ipam/templates/ipam/vlan_retrieve.html +1 -7
- nautobot/ipam/templates/ipam/vrf_edit.html +1 -1
- nautobot/ipam/tests/test_api.py +5 -0
- nautobot/ipam/tests/test_models.py +387 -0
- nautobot/ipam/tests/test_querysets.py +46 -0
- nautobot/ipam/tests/test_views.py +34 -0
- nautobot/ipam/ui.py +145 -0
- nautobot/ipam/urls.py +1 -46
- nautobot/ipam/utils/__init__.py +26 -0
- nautobot/ipam/utils/migrations.py +1 -1
- nautobot/ipam/views.py +234 -112
- nautobot/project-static/docs/404.html +11 -11
- nautobot/project-static/docs/apps/index.html +11 -11
- nautobot/project-static/docs/apps/nautobot-apps.html +11 -11
- nautobot/project-static/docs/assets/javascripts/{bundle.92b07e13.min.js → bundle.f55a23d4.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.92b07e13.min.js.map → bundle.f55a23d4.min.js.map} +2 -2
- nautobot/project-static/docs/assets/stylesheets/{main.7e37652d.min.css → main.e53b48f4.min.css} +1 -1
- nautobot/project-static/docs/assets/stylesheets/{main.7e37652d.min.css.map → main.e53b48f4.min.css.map} +1 -1
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +83 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1265 -281
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +11 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +12 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +452 -29
- nautobot/project-static/docs/development/apps/api/configuration-view.html +11 -11
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +11 -11
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +11 -11
- nautobot/project-static/docs/development/apps/api/models/global-search.html +11 -11
- nautobot/project-static/docs/development/apps/api/models/graphql.html +11 -11
- nautobot/project-static/docs/development/apps/api/models/index.html +11 -11
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +12 -12
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/prepopulating-data.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +11 -11
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +11 -11
- nautobot/project-static/docs/development/apps/api/prometheus.html +11 -11
- nautobot/project-static/docs/development/apps/api/setup.html +11 -11
- nautobot/project-static/docs/development/apps/api/testing.html +11 -11
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +11 -11
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +11 -11
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +11 -11
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +11 -11
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/base-template.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/index.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/notes.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +11 -11
- nautobot/project-static/docs/development/apps/api/views/urls.html +11 -11
- nautobot/project-static/docs/development/apps/index.html +11 -11
- nautobot/project-static/docs/development/apps/migration/code-updates.html +11 -11
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +11 -11
- nautobot/project-static/docs/development/apps/migration/from-v1.html +11 -11
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +11 -11
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +11 -11
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +11 -11
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +11 -11
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +11 -11
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/breadcrumbs-titles.html +11 -11
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +11 -11
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +11 -11
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +11 -11
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +11 -11
- nautobot/project-static/docs/development/core/application-registry.html +11 -11
- nautobot/project-static/docs/development/core/best-practices.html +11 -11
- nautobot/project-static/docs/development/core/bootstrap-ui.html +11 -11
- nautobot/project-static/docs/development/core/caching.html +11 -11
- nautobot/project-static/docs/development/core/controllers.html +11 -11
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +11 -11
- nautobot/project-static/docs/development/core/generic-views.html +11 -11
- nautobot/project-static/docs/development/core/getting-started.html +50 -63
- nautobot/project-static/docs/development/core/homepage.html +11 -11
- nautobot/project-static/docs/development/core/index.html +11 -11
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +11 -11
- nautobot/project-static/docs/development/core/model-checklist.html +11 -11
- nautobot/project-static/docs/development/core/model-features.html +11 -11
- nautobot/project-static/docs/development/core/natural-keys.html +11 -11
- nautobot/project-static/docs/development/core/navigation-menu.html +11 -11
- nautobot/project-static/docs/development/core/release-checklist.html +11 -11
- nautobot/project-static/docs/development/core/role-internals.html +11 -11
- nautobot/project-static/docs/development/core/settings.html +11 -11
- nautobot/project-static/docs/development/core/style-guide.html +15 -11
- nautobot/project-static/docs/development/core/templates.html +11 -11
- nautobot/project-static/docs/development/core/testing.html +11 -11
- nautobot/project-static/docs/development/core/ui-component-framework.html +17 -22
- nautobot/project-static/docs/development/core/user-preferences.html +11 -11
- nautobot/project-static/docs/development/index.html +11 -11
- nautobot/project-static/docs/development/jobs/getting-started.html +11 -11
- nautobot/project-static/docs/development/jobs/index.html +11 -11
- nautobot/project-static/docs/development/jobs/installation.html +11 -11
- nautobot/project-static/docs/development/jobs/job-extensions.html +11 -11
- nautobot/project-static/docs/development/jobs/job-logging.html +11 -11
- nautobot/project-static/docs/development/jobs/job-patterns.html +11 -11
- nautobot/project-static/docs/development/jobs/job-structure.html +11 -11
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +11 -11
- nautobot/project-static/docs/development/jobs/testing.html +11 -11
- nautobot/project-static/docs/index.html +11 -11
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +11 -11
- nautobot/project-static/docs/overview/design_philosophy.html +11 -11
- nautobot/project-static/docs/release-notes/index.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.0.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.1.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.2.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.3.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.4.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.5.html +11 -11
- nautobot/project-static/docs/release-notes/version-1.6.html +11 -11
- nautobot/project-static/docs/release-notes/version-2.0.html +11 -11
- nautobot/project-static/docs/release-notes/version-2.1.html +11 -11
- nautobot/project-static/docs/release-notes/version-2.2.html +11 -11
- nautobot/project-static/docs/release-notes/version-2.3.html +11 -11
- nautobot/project-static/docs/release-notes/version-2.4.html +418 -11
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +300 -300
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +11 -11
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +11 -11
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +11 -11
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +11 -11
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +11 -11
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +38 -11
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +89 -14
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +11 -11
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/index.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +11 -11
- nautobot/project-static/docs/user-guide/administration/installation/services.html +11 -11
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +11 -11
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +11 -11
- nautobot/project-static/docs/user-guide/administration/security/index.html +11 -11
- nautobot/project-static/docs/user-guide/administration/security/notices.html +11 -11
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +11 -11
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +11 -11
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +11 -11
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +11 -11
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +11 -11
- nautobot/project-static/docs/user-guide/index.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +11 -11
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +11 -11
- nautobot/project-static/img/nautobot_icon.svg +32 -34
- nautobot/project-static/js/table_sorting_indicator.js +0 -2
- nautobot/tenancy/templates/tenancy/tenant.html +1 -7
- nautobot/tenancy/views.py +13 -0
- nautobot/users/templates/users/api_tokens.html +4 -4
- nautobot/users/templates/users/base.html +28 -28
- nautobot/virtualization/templates/virtualization/cluster.html +64 -64
- nautobot/virtualization/templates/virtualization/inc/virtualmachine_vminterface_filter.html +8 -0
- nautobot/virtualization/templates/virtualization/virtualmachine_component_add.html +25 -25
- nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +1 -251
- nautobot/virtualization/templates/virtualization/vminterface.html +70 -70
- nautobot/virtualization/urls.py +0 -12
- nautobot/virtualization/views.py +158 -54
- nautobot/wireless/templates/wireless/wirelessnetwork_create.html +13 -13
- nautobot/wireless/tests/integration/test_radio_profile.py +1 -1
- {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/METADATA +4 -4
- {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/RECORD +623 -607
- nautobot/core/templates/inc/breadcrumbs.html +0 -14
- nautobot/ipam/templates/ipam/prefix_ipaddresses.html +0 -11
- nautobot/ipam/templates/ipam/prefix_prefixes.html +0 -11
- nautobot/project-static/docs/requirements.txt +0 -14
- {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/NOTICE +0 -0
- {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/WHEEL +0 -0
- {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{% extends 'generic/object_create.html' %}
|
|
2
|
+
{% load form_helpers %}
|
|
3
|
+
|
|
4
|
+
{% block form %}
|
|
5
|
+
<div class="panel panel-default">
|
|
6
|
+
<div class="panel-heading"><strong>Prefix</strong></div>
|
|
7
|
+
<div class="panel-body">
|
|
8
|
+
{% render_field form.prefix %}
|
|
9
|
+
{% render_field form.namespace %}
|
|
10
|
+
{% render_field form.type %}
|
|
11
|
+
{% render_field form.status %}
|
|
12
|
+
{% render_field form.role %}
|
|
13
|
+
{% render_field form.rir %}
|
|
14
|
+
{% render_field form.date_allocated %}
|
|
15
|
+
{% render_field form.description %}
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="panel panel-default">
|
|
19
|
+
<div class="panel-heading"><strong>VRF Assignment</strong></div>
|
|
20
|
+
<div class="panel-body">
|
|
21
|
+
{% render_field form.vrfs %}
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="panel panel-default">
|
|
25
|
+
<div class="panel-heading"><strong>Location/VLAN Assignment</strong></div>
|
|
26
|
+
<div class="panel-body">
|
|
27
|
+
{% render_field form.locations %}
|
|
28
|
+
{% render_field form.vlan_group %}
|
|
29
|
+
{% render_field form.vlan %}
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
{% include 'inc/tenancy_form_panel.html' %}
|
|
33
|
+
{% include 'inc/extras_features_edit_form_fields.html' %}
|
|
34
|
+
{% endblock %}
|
|
@@ -1,34 +1 @@
|
|
|
1
|
-
{% extends '
|
|
2
|
-
{% load form_helpers %}
|
|
3
|
-
|
|
4
|
-
{% block form %}
|
|
5
|
-
<div class="panel panel-default">
|
|
6
|
-
<div class="panel-heading"><strong>Prefix</strong></div>
|
|
7
|
-
<div class="panel-body">
|
|
8
|
-
{% render_field form.prefix %}
|
|
9
|
-
{% render_field form.namespace %}
|
|
10
|
-
{% render_field form.type %}
|
|
11
|
-
{% render_field form.status %}
|
|
12
|
-
{% render_field form.role %}
|
|
13
|
-
{% render_field form.rir %}
|
|
14
|
-
{% render_field form.date_allocated %}
|
|
15
|
-
{% render_field form.description %}
|
|
16
|
-
</div>
|
|
17
|
-
</div>
|
|
18
|
-
<div class="panel panel-default">
|
|
19
|
-
<div class="panel-heading"><strong>VRF Assignment</strong></div>
|
|
20
|
-
<div class="panel-body">
|
|
21
|
-
{% render_field form.vrfs %}
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
<div class="panel panel-default">
|
|
25
|
-
<div class="panel-heading"><strong>Location/VLAN Assignment</strong></div>
|
|
26
|
-
<div class="panel-body">
|
|
27
|
-
{% render_field form.locations %}
|
|
28
|
-
{% render_field form.vlan_group %}
|
|
29
|
-
{% render_field form.vlan %}
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
32
|
-
{% include 'inc/tenancy_form_panel.html' %}
|
|
33
|
-
{% include 'inc/extras_features_edit_form_fields.html' %}
|
|
34
|
-
{% endblock %}
|
|
1
|
+
{% extends 'ipam/prefix_create.html' %}
|
|
@@ -1,7 +1,2 @@
|
|
|
1
1
|
{% extends 'generic/object_retrieve.html' %}
|
|
2
|
-
{%
|
|
3
|
-
|
|
4
|
-
{% block extra_breadcrumbs %}
|
|
5
|
-
<li>{{ object.parent|hyperlinked_object }}</li>
|
|
6
|
-
{% endblock extra_breadcrumbs %}
|
|
7
|
-
|
|
2
|
+
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
|
@@ -1,8 +1,2 @@
|
|
|
1
1
|
{% extends 'generic/object_retrieve.html' %}
|
|
2
|
-
{%
|
|
3
|
-
|
|
4
|
-
{% block extra_breadcrumbs %}
|
|
5
|
-
{% if object.vlan_group %}
|
|
6
|
-
<li><a href="{% url 'ipam:vlan_list' %}?vlan_group={{ object.vlan_group.name }}">{{ object.vlan_group }}</a></li>
|
|
7
|
-
{% endif %}
|
|
8
|
-
{% endblock extra_breadcrumbs %}
|
|
2
|
+
{% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
|
nautobot/ipam/tests/test_api.py
CHANGED
|
@@ -413,6 +413,11 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
|
|
|
413
413
|
}
|
|
414
414
|
cls.choices_fields = ["type"]
|
|
415
415
|
|
|
416
|
+
# Generic `test_update_object()` will grab and update the first Prefix
|
|
417
|
+
first_pfx = Prefix.objects.first()
|
|
418
|
+
cls.update_data = cls.create_data[0].copy()
|
|
419
|
+
cls.update_data["namespace"] = first_pfx.namespace.pk # can't change network and namespace in the same update
|
|
420
|
+
|
|
416
421
|
def test_legacy_api_behavior(self):
|
|
417
422
|
"""
|
|
418
423
|
Tests for the 2.0/2.1 REST API of Prefixes.
|
|
@@ -284,6 +284,393 @@ class IPAddressToInterfaceTest(TestCase):
|
|
|
284
284
|
self.assertEqual(remaining_assignments.count(), 1)
|
|
285
285
|
self.assertIn(assignment_nested_module, remaining_assignments)
|
|
286
286
|
|
|
287
|
+
def test_ip_address_to_interface_delete_signal_no_save_when_device_has_no_primary_ips(self):
|
|
288
|
+
"""
|
|
289
|
+
Test that Device is not saved when removing an IP from an interface and the device
|
|
290
|
+
has no primary IPs assigned.
|
|
291
|
+
"""
|
|
292
|
+
# Create an IP address
|
|
293
|
+
ip_addr = IPAddress.objects.create(address="192.0.2.1/24", status=self.status, namespace=self.namespace)
|
|
294
|
+
|
|
295
|
+
# Assign IP to interface
|
|
296
|
+
assignment_device_int1 = IPAddressToInterface.objects.create(interface=self.test_int1, ip_address=ip_addr)
|
|
297
|
+
|
|
298
|
+
# Mock the device save method to verify it's not called
|
|
299
|
+
with patch.object(self.test_device, "save") as mock_save:
|
|
300
|
+
# Remove the IP assignment from interface - this should NOT trigger a device save
|
|
301
|
+
assignment_device_int1.delete()
|
|
302
|
+
|
|
303
|
+
# Assert save was not called since no primary IPs were affected
|
|
304
|
+
mock_save.assert_not_called()
|
|
305
|
+
|
|
306
|
+
def test_ip_address_to_interface_delete_signal_no_save_when_removing_non_primary_ip_from_device(self):
|
|
307
|
+
"""
|
|
308
|
+
Test that Device is not saved when removing an IP from an interface and the IP
|
|
309
|
+
is not the device's primary IP.
|
|
310
|
+
"""
|
|
311
|
+
# Test removing non-primary IPv4 assignment
|
|
312
|
+
with self.subTest("IPv4 non-primary IP removal"):
|
|
313
|
+
# Create IPv4 addresses
|
|
314
|
+
primary_ipv4_addr = IPAddress.objects.create(
|
|
315
|
+
address="192.0.2.1/24", status=self.status, namespace=self.namespace
|
|
316
|
+
)
|
|
317
|
+
other_ipv4_addr = IPAddress.objects.create(
|
|
318
|
+
address="192.0.2.2/24", status=self.status, namespace=self.namespace
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
# Assign primary IP to interface first (required before setting as primary)
|
|
322
|
+
IPAddressToInterface.objects.create(interface=self.test_int2, ip_address=primary_ipv4_addr)
|
|
323
|
+
|
|
324
|
+
# Set it as the device's primary IP
|
|
325
|
+
self.test_device.primary_ip4 = primary_ipv4_addr
|
|
326
|
+
self.test_device.save()
|
|
327
|
+
|
|
328
|
+
# Assign the other IP to a different interface
|
|
329
|
+
assignment_other_ipv4 = IPAddressToInterface.objects.create(
|
|
330
|
+
interface=self.test_int1, ip_address=other_ipv4_addr
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
with patch.object(self.test_device, "save") as mock_save:
|
|
334
|
+
assignment_other_ipv4.delete()
|
|
335
|
+
mock_save.assert_not_called()
|
|
336
|
+
|
|
337
|
+
# Test removing non-primary IPv6 assignment
|
|
338
|
+
with self.subTest("IPv6 non-primary IP removal"):
|
|
339
|
+
# Create IPv6 prefix first
|
|
340
|
+
Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
|
|
341
|
+
|
|
342
|
+
# Create IPv6 addresses
|
|
343
|
+
primary_ipv6_addr = IPAddress.objects.create(
|
|
344
|
+
address="2001:db8::1/64", status=self.status, namespace=self.namespace
|
|
345
|
+
)
|
|
346
|
+
other_ipv6_addr = IPAddress.objects.create(
|
|
347
|
+
address="2001:db8::2/64", status=self.status, namespace=self.namespace
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
# Assign primary IP to interface first (required before setting as primary)
|
|
351
|
+
IPAddressToInterface.objects.create(interface=self.test_int2, ip_address=primary_ipv6_addr)
|
|
352
|
+
|
|
353
|
+
# Set it as the device's primary IP
|
|
354
|
+
self.test_device.primary_ip6 = primary_ipv6_addr
|
|
355
|
+
self.test_device.save()
|
|
356
|
+
|
|
357
|
+
# Assign the other IP to a different interface
|
|
358
|
+
assignment_other_ipv6 = IPAddressToInterface.objects.create(
|
|
359
|
+
interface=self.test_int1, ip_address=other_ipv6_addr
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
with patch.object(self.test_device, "save") as mock_save:
|
|
363
|
+
assignment_other_ipv6.delete()
|
|
364
|
+
mock_save.assert_not_called()
|
|
365
|
+
|
|
366
|
+
def test_ip_address_to_interface_delete_signal_save_when_removing_primary_ip_from_device(self):
|
|
367
|
+
"""
|
|
368
|
+
Test that Device is saved when removing an IP from an interface and the IP is the device's
|
|
369
|
+
primary IP and no other assignments exist.
|
|
370
|
+
"""
|
|
371
|
+
# Test removing primary IPv4 assignment
|
|
372
|
+
with self.subTest("IPv4 primary IP removal"):
|
|
373
|
+
# Create primary IPv4 address
|
|
374
|
+
primary_ipv4_addr = IPAddress.objects.create(
|
|
375
|
+
address="192.0.2.1/24", status=self.status, namespace=self.namespace
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
# Assign primary IPv4 to an interface first
|
|
379
|
+
assignment_primary_ipv4 = IPAddressToInterface.objects.create(
|
|
380
|
+
interface=self.test_int1, ip_address=primary_ipv4_addr
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
# Set it as the device's primary IP
|
|
384
|
+
self.test_device.primary_ip4 = primary_ipv4_addr
|
|
385
|
+
self.test_device.save()
|
|
386
|
+
|
|
387
|
+
# Mock the device save method to verify it's called
|
|
388
|
+
with patch.object(self.test_device, "save") as mock_save:
|
|
389
|
+
# Remove the primary IP assignment - this SHOULD trigger a device save
|
|
390
|
+
assignment_primary_ipv4.delete()
|
|
391
|
+
|
|
392
|
+
# Assert save was called to nullify primary_ip4
|
|
393
|
+
mock_save.assert_called_once()
|
|
394
|
+
|
|
395
|
+
# Test removing primary IPv6 assignment
|
|
396
|
+
with self.subTest("IPv6 primary IP removal"):
|
|
397
|
+
# Create IPv6 prefix first
|
|
398
|
+
Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
|
|
399
|
+
|
|
400
|
+
# Create primary IPv6 address
|
|
401
|
+
primary_ipv6_addr = IPAddress.objects.create(
|
|
402
|
+
address="2001:db8::1/64", status=self.status, namespace=self.namespace
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
# Assign primary IPv6 to an interface first
|
|
406
|
+
assignment_primary_ipv6 = IPAddressToInterface.objects.create(
|
|
407
|
+
interface=self.test_int1, ip_address=primary_ipv6_addr
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
# Set it as the device's primary IP
|
|
411
|
+
self.test_device.primary_ip6 = primary_ipv6_addr
|
|
412
|
+
self.test_device.save()
|
|
413
|
+
|
|
414
|
+
# Mock the device save method to verify it's called
|
|
415
|
+
with patch.object(self.test_device, "save") as mock_save:
|
|
416
|
+
# Remove the primary IP assignment - this SHOULD trigger a device save
|
|
417
|
+
assignment_primary_ipv6.delete()
|
|
418
|
+
|
|
419
|
+
# Assert save was called to nullify primary_ip6
|
|
420
|
+
mock_save.assert_called_once()
|
|
421
|
+
|
|
422
|
+
def test_ip_address_to_interface_delete_signal_no_save_when_device_primary_ip_has_multiple_assignments(self):
|
|
423
|
+
"""
|
|
424
|
+
Test that Device is not saved when removing an IP from an interface and the IP is the device's
|
|
425
|
+
primary IP but is assigned to other interfaces on that device.
|
|
426
|
+
"""
|
|
427
|
+
# Test IPv4 primary IP with multiple assignments
|
|
428
|
+
with self.subTest("IPv4 primary IP with multiple assignments"):
|
|
429
|
+
# Create primary IPv4 address
|
|
430
|
+
primary_ipv4_addr = IPAddress.objects.create(
|
|
431
|
+
address="192.0.2.1/24", status=self.status, namespace=self.namespace
|
|
432
|
+
)
|
|
433
|
+
# Assign primary IPv4 to multiple interfaces
|
|
434
|
+
assignment_ipv4_int1 = IPAddressToInterface.objects.create(
|
|
435
|
+
interface=self.test_int1, ip_address=primary_ipv4_addr
|
|
436
|
+
)
|
|
437
|
+
IPAddressToInterface.objects.create(interface=self.test_int2, ip_address=primary_ipv4_addr)
|
|
438
|
+
|
|
439
|
+
# Set it as the device's primary IP
|
|
440
|
+
self.test_device.primary_ip4 = primary_ipv4_addr
|
|
441
|
+
self.test_device.save()
|
|
442
|
+
|
|
443
|
+
# Mock the device save method to verify it's not called
|
|
444
|
+
with patch.object(self.test_device, "save") as mock_save:
|
|
445
|
+
# Remove primary IP from one interface - should NOT trigger save since other assignment exists
|
|
446
|
+
assignment_ipv4_int1.delete()
|
|
447
|
+
|
|
448
|
+
# Assert save was not called since IP is still assigned to test_int2
|
|
449
|
+
mock_save.assert_not_called()
|
|
450
|
+
|
|
451
|
+
# Test IPv6 primary IP with multiple assignments
|
|
452
|
+
with self.subTest("IPv6 primary IP with multiple assignments"):
|
|
453
|
+
# Create IPv6 prefix first
|
|
454
|
+
Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
|
|
455
|
+
|
|
456
|
+
# Create primary IPv6 address
|
|
457
|
+
primary_ipv6_addr = IPAddress.objects.create(
|
|
458
|
+
address="2001:db8::1/64", status=self.status, namespace=self.namespace
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
# Assign primary IPv6 to multiple interfaces
|
|
462
|
+
assignment_ipv6_int1 = IPAddressToInterface.objects.create(
|
|
463
|
+
interface=self.test_int1, ip_address=primary_ipv6_addr
|
|
464
|
+
)
|
|
465
|
+
IPAddressToInterface.objects.create(interface=self.test_int2, ip_address=primary_ipv6_addr)
|
|
466
|
+
|
|
467
|
+
# Set it as the device's primary IP
|
|
468
|
+
self.test_device.primary_ip6 = primary_ipv6_addr
|
|
469
|
+
self.test_device.save()
|
|
470
|
+
|
|
471
|
+
# Mock the device save method to verify it's not called
|
|
472
|
+
with patch.object(self.test_device, "save") as mock_save:
|
|
473
|
+
# Remove primary IP from one interface - should NOT trigger save since other assignment exists
|
|
474
|
+
assignment_ipv6_int1.delete()
|
|
475
|
+
|
|
476
|
+
# Assert save was not called since IP is still assigned to test_int2
|
|
477
|
+
mock_save.assert_not_called()
|
|
478
|
+
|
|
479
|
+
def test_ip_address_to_interface_delete_signal_no_save_when_vm_has_no_primary_ips(self):
|
|
480
|
+
"""
|
|
481
|
+
Test that VM is not saved when removing an IP from a VM interface and the VM
|
|
482
|
+
has no primary IPs assigned.
|
|
483
|
+
"""
|
|
484
|
+
# Create an IP address
|
|
485
|
+
ip_addr = IPAddress.objects.create(address="192.0.2.1/24", status=self.status, namespace=self.namespace)
|
|
486
|
+
|
|
487
|
+
# VM has no primary IPs by default (both are None)
|
|
488
|
+
|
|
489
|
+
# Assign IP to VM interface
|
|
490
|
+
assignment_vm_int1 = IPAddressToInterface.objects.create(vm_interface=self.test_vmint1, ip_address=ip_addr)
|
|
491
|
+
|
|
492
|
+
# Mock the VM save method to verify it's not called
|
|
493
|
+
with patch.object(self.test_vm, "save") as mock_save:
|
|
494
|
+
# Remove the IP assignment from VM interface - this should NOT trigger a VM save
|
|
495
|
+
assignment_vm_int1.delete()
|
|
496
|
+
|
|
497
|
+
# Assert save was not called since no primary IPs were affected
|
|
498
|
+
mock_save.assert_not_called()
|
|
499
|
+
|
|
500
|
+
def test_ip_address_to_interface_delete_signal_no_save_when_removing_non_primary_ip_from_vm(self):
|
|
501
|
+
"""
|
|
502
|
+
Test that VM is not saved when removing an IP from a VM interface and the IP
|
|
503
|
+
is not the VM's primary IP.
|
|
504
|
+
"""
|
|
505
|
+
# Test removing non-primary IPv4 assignment
|
|
506
|
+
with self.subTest("IPv4 non-primary IP removal"):
|
|
507
|
+
# Create IPv4 addresses
|
|
508
|
+
primary_ipv4_addr = IPAddress.objects.create(
|
|
509
|
+
address="192.0.2.1/24", status=self.status, namespace=self.namespace
|
|
510
|
+
)
|
|
511
|
+
other_ipv4_addr = IPAddress.objects.create(
|
|
512
|
+
address="192.0.2.2/24", status=self.status, namespace=self.namespace
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
# Assign primary IP to VM interface first (required before setting as primary)
|
|
516
|
+
IPAddressToInterface.objects.create(vm_interface=self.test_vmint2, ip_address=primary_ipv4_addr)
|
|
517
|
+
|
|
518
|
+
# Set it as the VM's primary IP
|
|
519
|
+
self.test_vm.primary_ip4 = primary_ipv4_addr
|
|
520
|
+
self.test_vm.save()
|
|
521
|
+
|
|
522
|
+
# Assign the other IP to a different VM interface
|
|
523
|
+
assignment_vm_int1 = IPAddressToInterface.objects.create(
|
|
524
|
+
vm_interface=self.test_vmint1, ip_address=other_ipv4_addr
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
with patch.object(self.test_vm, "save") as mock_save:
|
|
528
|
+
assignment_vm_int1.delete()
|
|
529
|
+
mock_save.assert_not_called()
|
|
530
|
+
|
|
531
|
+
# Test removing non-primary IPv6 assignment
|
|
532
|
+
with self.subTest("IPv6 non-primary IP removal"):
|
|
533
|
+
# Create IPv6 prefix first
|
|
534
|
+
Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
|
|
535
|
+
|
|
536
|
+
# Create IPv6 addresses
|
|
537
|
+
primary_ipv6_addr = IPAddress.objects.create(
|
|
538
|
+
address="2001:db8::1/64", status=self.status, namespace=self.namespace
|
|
539
|
+
)
|
|
540
|
+
other_ipv6_addr = IPAddress.objects.create(
|
|
541
|
+
address="2001:db8::2/64", status=self.status, namespace=self.namespace
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
# Assign primary IP to VM interface first (required before setting as primary)
|
|
545
|
+
IPAddressToInterface.objects.create(vm_interface=self.test_vmint2, ip_address=primary_ipv6_addr)
|
|
546
|
+
|
|
547
|
+
# Set it as the VM's primary IP
|
|
548
|
+
self.test_vm.primary_ip6 = primary_ipv6_addr
|
|
549
|
+
self.test_vm.save()
|
|
550
|
+
|
|
551
|
+
# Assign the other IP to a different VM interface
|
|
552
|
+
assignment_vm_int1 = IPAddressToInterface.objects.create(
|
|
553
|
+
vm_interface=self.test_vmint1, ip_address=other_ipv6_addr
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
with patch.object(self.test_vm, "save") as mock_save:
|
|
557
|
+
assignment_vm_int1.delete()
|
|
558
|
+
mock_save.assert_not_called()
|
|
559
|
+
|
|
560
|
+
def test_ip_address_to_interface_delete_signal_save_when_removing_primary_ip_from_vm(self):
|
|
561
|
+
"""
|
|
562
|
+
Test that VM is saved when removing an IP from a VM interface and the IP is the VM's
|
|
563
|
+
primary IP and no other assignments exist.
|
|
564
|
+
"""
|
|
565
|
+
# Test removing primary IPv4 assignment
|
|
566
|
+
with self.subTest("IPv4 primary IP removal"):
|
|
567
|
+
# Create primary IPv4 address
|
|
568
|
+
primary_ipv4_addr = IPAddress.objects.create(
|
|
569
|
+
address="192.0.2.1/24", status=self.status, namespace=self.namespace
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
# Assign primary IPv4 to VM interface first
|
|
573
|
+
assignment_primary_ipv4 = IPAddressToInterface.objects.create(
|
|
574
|
+
vm_interface=self.test_vmint1, ip_address=primary_ipv4_addr
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
# Set it as the VM's primary IP
|
|
578
|
+
self.test_vm.primary_ip4 = primary_ipv4_addr
|
|
579
|
+
self.test_vm.save()
|
|
580
|
+
|
|
581
|
+
# Mock the VM save method to verify it's called
|
|
582
|
+
with patch.object(self.test_vm, "save") as mock_save:
|
|
583
|
+
# Remove the primary IP assignment - this SHOULD trigger a VM save
|
|
584
|
+
assignment_primary_ipv4.delete()
|
|
585
|
+
|
|
586
|
+
# Assert save was called to nullify primary_ip4
|
|
587
|
+
mock_save.assert_called_once()
|
|
588
|
+
|
|
589
|
+
# Test removing primary IPv6 assignment
|
|
590
|
+
with self.subTest("IPv6 primary IP removal"):
|
|
591
|
+
# Create IPv6 prefix first
|
|
592
|
+
Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
|
|
593
|
+
|
|
594
|
+
# Create primary IPv6 address
|
|
595
|
+
primary_ipv6_addr = IPAddress.objects.create(
|
|
596
|
+
address="2001:db8::1/64", status=self.status, namespace=self.namespace
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
# Assign primary IPv6 to VM interface first
|
|
600
|
+
assignment_primary_ipv6 = IPAddressToInterface.objects.create(
|
|
601
|
+
vm_interface=self.test_vmint1, ip_address=primary_ipv6_addr
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
# Set it as the VM's primary IP
|
|
605
|
+
self.test_vm.primary_ip6 = primary_ipv6_addr
|
|
606
|
+
self.test_vm.save()
|
|
607
|
+
|
|
608
|
+
# Mock the VM save method to verify it's called
|
|
609
|
+
with patch.object(self.test_vm, "save") as mock_save:
|
|
610
|
+
# Remove the primary IP assignment - this SHOULD trigger a VM save
|
|
611
|
+
assignment_primary_ipv6.delete()
|
|
612
|
+
|
|
613
|
+
# Assert save was called to nullify primary_ip6
|
|
614
|
+
mock_save.assert_called_once()
|
|
615
|
+
|
|
616
|
+
def test_ip_address_to_interface_delete_signal_no_save_when_vm_primary_ip_has_multiple_assignments(self):
|
|
617
|
+
"""
|
|
618
|
+
Test that VM is not saved when removing an IP from a VM interface and the IP is the VM's
|
|
619
|
+
primary IP but is assigned to other VM interfaces on that VM.
|
|
620
|
+
"""
|
|
621
|
+
# Test IPv4 primary IP with multiple assignments
|
|
622
|
+
with self.subTest("IPv4 primary IP with multiple assignments"):
|
|
623
|
+
# Create primary IPv4 address
|
|
624
|
+
primary_ipv4_addr = IPAddress.objects.create(
|
|
625
|
+
address="192.0.2.1/24", status=self.status, namespace=self.namespace
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
# Assign primary IPv4 to multiple VM interfaces
|
|
629
|
+
assignment_ipv4_vmint1 = IPAddressToInterface.objects.create(
|
|
630
|
+
vm_interface=self.test_vmint1, ip_address=primary_ipv4_addr
|
|
631
|
+
)
|
|
632
|
+
IPAddressToInterface.objects.create(vm_interface=self.test_vmint2, ip_address=primary_ipv4_addr)
|
|
633
|
+
|
|
634
|
+
# Set it as the VM's primary IP
|
|
635
|
+
self.test_vm.primary_ip4 = primary_ipv4_addr
|
|
636
|
+
self.test_vm.save()
|
|
637
|
+
|
|
638
|
+
# Mock the VM save method to verify it's not called
|
|
639
|
+
with patch.object(self.test_vm, "save") as mock_save:
|
|
640
|
+
# Remove primary IP from one VM interface - should NOT trigger save since other assignment exists
|
|
641
|
+
assignment_ipv4_vmint1.delete()
|
|
642
|
+
|
|
643
|
+
# Assert save was not called since IP is still assigned to test_vmint2
|
|
644
|
+
mock_save.assert_not_called()
|
|
645
|
+
|
|
646
|
+
# Test IPv6 primary IP with multiple assignments
|
|
647
|
+
with self.subTest("IPv6 primary IP with multiple assignments"):
|
|
648
|
+
# Create IPv6 prefix first
|
|
649
|
+
Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
|
|
650
|
+
|
|
651
|
+
# Create primary IPv6 address
|
|
652
|
+
primary_ipv6_addr = IPAddress.objects.create(
|
|
653
|
+
address="2001:db8::1/64", status=self.status, namespace=self.namespace
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
# Assign primary IPv6 to multiple VM interfaces
|
|
657
|
+
assignment_ipv6_vmint1 = IPAddressToInterface.objects.create(
|
|
658
|
+
vm_interface=self.test_vmint1, ip_address=primary_ipv6_addr
|
|
659
|
+
)
|
|
660
|
+
IPAddressToInterface.objects.create(vm_interface=self.test_vmint2, ip_address=primary_ipv6_addr)
|
|
661
|
+
|
|
662
|
+
# Set it as the VM's primary IP
|
|
663
|
+
self.test_vm.primary_ip6 = primary_ipv6_addr
|
|
664
|
+
self.test_vm.save()
|
|
665
|
+
|
|
666
|
+
# Mock the VM save method to verify it's not called
|
|
667
|
+
with patch.object(self.test_vm, "save") as mock_save:
|
|
668
|
+
# Remove primary IP from one VM interface - should NOT trigger save since other assignment exists
|
|
669
|
+
assignment_ipv6_vmint1.delete()
|
|
670
|
+
|
|
671
|
+
# Assert save was not called since IP is still assigned to test_vmint2
|
|
672
|
+
mock_save.assert_not_called()
|
|
673
|
+
|
|
287
674
|
|
|
288
675
|
class TestVarbinaryIPField(TestCase):
|
|
289
676
|
"""Tests for `nautobot.ipam.fields.VarbinaryIPField`."""
|
|
@@ -802,6 +802,23 @@ class PrefixQuerysetTestCase(TestCase):
|
|
|
802
802
|
status=self.status,
|
|
803
803
|
)
|
|
804
804
|
|
|
805
|
+
# same but for IPv6
|
|
806
|
+
container_v6 = netaddr.IPNetwork("2001:db8::/120")
|
|
807
|
+
Prefix.objects.create(
|
|
808
|
+
prefix=container_v6,
|
|
809
|
+
type=choices.PrefixTypeChoices.TYPE_CONTAINER,
|
|
810
|
+
namespace=namespace,
|
|
811
|
+
status=self.status,
|
|
812
|
+
)
|
|
813
|
+
for prefix_length in range(121, 129):
|
|
814
|
+
network = list(container_v6.subnet(prefix_length))[1]
|
|
815
|
+
Prefix.objects.create(
|
|
816
|
+
prefix=network,
|
|
817
|
+
type=choices.PrefixTypeChoices.TYPE_NETWORK,
|
|
818
|
+
namespace=namespace,
|
|
819
|
+
status=self.status,
|
|
820
|
+
)
|
|
821
|
+
|
|
805
822
|
for last_octet in range(1, 255):
|
|
806
823
|
ip = netaddr.IPAddress(f"10.0.0.{last_octet}")
|
|
807
824
|
expected_prefix_length = 33 - len(bin(last_octet)[2:]) # [1] = 32, [2,3] = 31, [4,5,6,7] = 30, etc.
|
|
@@ -819,3 +836,32 @@ class PrefixQuerysetTestCase(TestCase):
|
|
|
819
836
|
.order_by("-prefix_length")
|
|
820
837
|
.first(),
|
|
821
838
|
)
|
|
839
|
+
|
|
840
|
+
ip = netaddr.IPAddress(f"2001:db8::{last_octet:x}")
|
|
841
|
+
expected_prefix_length = 129 - len(bin(last_octet)[2:]) # [1] = 128, [2,3] = 127, [4,5,6,7] = 126, etc.
|
|
842
|
+
with self.subTest(ip=ip, expected_prefix_length=expected_prefix_length):
|
|
843
|
+
closest_parent = Prefix.objects.filter(namespace=namespace).get_closest_parent(ip, include_self=True)
|
|
844
|
+
expected_parent = list(container_v6.subnet(expected_prefix_length))[1]
|
|
845
|
+
self.assertEqual(closest_parent.prefix, expected_parent)
|
|
846
|
+
self.assertEqual(
|
|
847
|
+
closest_parent,
|
|
848
|
+
Prefix.objects.filter(
|
|
849
|
+
network__lte=ip.value,
|
|
850
|
+
broadcast__gte=ip.value,
|
|
851
|
+
namespace=namespace,
|
|
852
|
+
)
|
|
853
|
+
.order_by("-prefix_length")
|
|
854
|
+
.first(),
|
|
855
|
+
)
|
|
856
|
+
|
|
857
|
+
slash32 = Prefix.objects.create(prefix="10.1.1.154/32", namespace=namespace, status=self.status)
|
|
858
|
+
slash31 = Prefix.objects.create(prefix="10.1.1.154/31", namespace=namespace, status=self.status)
|
|
859
|
+
slash30 = Prefix.objects.create(prefix="10.1.1.154/30", namespace=namespace, status=self.status)
|
|
860
|
+
self.assertEqual(slash31, Prefix.objects.get_closest_parent(slash32.prefix))
|
|
861
|
+
self.assertEqual(slash30, Prefix.objects.get_closest_parent(slash31.prefix))
|
|
862
|
+
|
|
863
|
+
slash126 = Prefix.objects.create(prefix="::1/126", namespace=namespace, status=self.status)
|
|
864
|
+
slash127 = Prefix.objects.create(prefix="::1/127", namespace=namespace, status=self.status)
|
|
865
|
+
slash128 = Prefix.objects.create(prefix="::1/128", namespace=namespace, status=self.status)
|
|
866
|
+
self.assertEqual(slash126, Prefix.objects.get_closest_parent(slash127.prefix))
|
|
867
|
+
self.assertEqual(slash127, Prefix.objects.get_closest_parent(slash128.prefix))
|
|
@@ -303,6 +303,8 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.List
|
|
|
303
303
|
status=ip_status,
|
|
304
304
|
namespace=self.namespace,
|
|
305
305
|
)
|
|
306
|
+
# add this permission to can test button Add an IP Address
|
|
307
|
+
self.add_permissions("ipam.add_ipaddress")
|
|
306
308
|
url = reverse("ipam:prefix_ipaddresses", args=(instance.pk,))
|
|
307
309
|
response = self.client.get(url)
|
|
308
310
|
self.assertHttpStatus(response, 200)
|
|
@@ -314,6 +316,35 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.List
|
|
|
314
316
|
f'<li role="presentation" class="active"><a href="{url}">IP Addresses <span class="badge">2</span></a></li>'
|
|
315
317
|
)
|
|
316
318
|
self.assertInHTML(ip_address_tab, content)
|
|
319
|
+
# Checks if the button is in the content.
|
|
320
|
+
self.assertInHTML("""<span class="mdi mdi-plus-thick" aria-hidden="true"></span>Add an IP Address""", content)
|
|
321
|
+
|
|
322
|
+
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
323
|
+
def test_prefix_child_prefixes_table_list(self):
|
|
324
|
+
instance = Prefix.objects.create(
|
|
325
|
+
prefix="5.5.10.0/23",
|
|
326
|
+
namespace=self.namespace,
|
|
327
|
+
type=PrefixTypeChoices.TYPE_NETWORK,
|
|
328
|
+
status=self.statuses[1],
|
|
329
|
+
)
|
|
330
|
+
Prefix.objects.create(
|
|
331
|
+
prefix="5.5.10.0/30",
|
|
332
|
+
namespace=self.namespace,
|
|
333
|
+
type=PrefixTypeChoices.TYPE_POOL,
|
|
334
|
+
status=self.statuses[1],
|
|
335
|
+
)
|
|
336
|
+
# add this permission to can test button Add Child Prefix
|
|
337
|
+
self.add_permissions("ipam.add_prefix")
|
|
338
|
+
url = reverse("ipam:prefix_prefixes", args=(instance.pk,))
|
|
339
|
+
response = self.client.get(url)
|
|
340
|
+
self.assertHttpStatus(response, 200)
|
|
341
|
+
content = extract_page_body(response.content.decode(response.charset))
|
|
342
|
+
# This validates that both parent prefix and child prefix IPAddresses are present in parent prefix IPAddresses list
|
|
343
|
+
self.assertIn("5.5.10.0/30", strip_tags(content))
|
|
344
|
+
ip_address_tab = f'<li role="presentation" class="active"><a href="{url}">Child Prefixes <span class="badge">1</span></a></li>'
|
|
345
|
+
self.assertInHTML(ip_address_tab, content)
|
|
346
|
+
# Checks if the button is in the content.
|
|
347
|
+
self.assertInHTML("""<span class="mdi mdi-plus-thick" aria-hidden="true"></span>Add Child Prefix""", content)
|
|
317
348
|
|
|
318
349
|
|
|
319
350
|
class IPAddressTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
@@ -1036,6 +1067,9 @@ class VLANTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
1036
1067
|
|
|
1037
1068
|
class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
1038
1069
|
model = Service
|
|
1070
|
+
allowed_number_of_tree_queries_per_view_type = {
|
|
1071
|
+
"retrieve": 1,
|
|
1072
|
+
}
|
|
1039
1073
|
|
|
1040
1074
|
@classmethod
|
|
1041
1075
|
def setUpTestData(cls):
|