From 4a88d5e3d90501909130868cb57c5c5a321f3703 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Fri, 2 Jun 2023 15:42:34 -0400 Subject: [PATCH 01/21] PRVB --- docs/release-notes/version-3.5.md | 4 ++++ netbox/netbox/settings.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 3143bbdeaf6..e0c34bb400b 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -1,5 +1,9 @@ # NetBox v3.5 +## v3.5.4 (FUTURE) + +--- + ## v3.5.3 (2023-06-02) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 4e27e59a401..e77ac43c013 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -25,7 +25,7 @@ # Environment setup # -VERSION = '3.5.3' +VERSION = '3.5.4-dev' # Hostname HOSTNAME = platform.node() From 01d9e0afb6212ade33e85b655d156ef442906739 Mon Sep 17 00:00:00 2001 From: Brian Candler Date: Thu, 8 Jun 2023 14:31:46 +0100 Subject: [PATCH 02/21] Round rack power utilization to nearest 0.1% Fixes #12838 --- netbox/dcim/models/racks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index e5412a3ab98..54de5c434d1 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -466,7 +466,7 @@ def get_power_utilization(self): powerport.get_power_draw()['allocated'] for powerport in powerports ]) - return int(allocated_draw / available_power_total * 100) + return round(allocated_draw / available_power_total * 100, 1) @cached_property def total_weight(self): From 210879d3807ed7036e2b886f39ac59e45ed6703a Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Sun, 11 Jun 2023 16:50:48 +0530 Subject: [PATCH 03/21] fix contact assignment table modal --- netbox/templates/tenancy/object_contacts.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/templates/tenancy/object_contacts.html b/netbox/templates/tenancy/object_contacts.html index aca63a3793c..bbe2d9bc1fc 100644 --- a/netbox/templates/tenancy/object_contacts.html +++ b/netbox/templates/tenancy/object_contacts.html @@ -10,7 +10,7 @@ {% endblock %} {% block content %} - {% include 'inc/table_controls_htmx.html' with table_modal="ContactTable_config" %} + {% include 'inc/table_controls_htmx.html' with table_modal="ContactAssignmentTable_config" %}
{% csrf_token %}
From 82cd6c5f4c261555f207f650558442b9c48b095b Mon Sep 17 00:00:00 2001 From: Sudheesh Singanamalla Date: Sun, 11 Jun 2023 12:17:32 -0700 Subject: [PATCH 04/21] Fixes #12862 - Add Button for Wireless Links in Sidebar Signed-off-by: Sudheesh Singanamalla --- netbox/netbox/navigation/menu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/navigation/menu.py b/netbox/netbox/navigation/menu.py index 6e5bcfc23f4..d139546d99b 100644 --- a/netbox/netbox/navigation/menu.py +++ b/netbox/netbox/navigation/menu.py @@ -102,7 +102,7 @@ label=_('Connections'), items=( get_model_item('dcim', 'cable', _('Cables'), actions=['import']), - get_model_item('wireless', 'wirelesslink', _('Wireless Links'), actions=['import']), + get_model_item('wireless', 'wirelesslink', _('Wireless Links')), MenuItem( link='dcim:interface_connections_list', link_text=_('Interface Connections'), From 22a0ce3f76089b4974f8aac3c75207b1237d1bf6 Mon Sep 17 00:00:00 2001 From: Jamie Murphy Date: Mon, 12 Jun 2023 21:01:43 +0100 Subject: [PATCH 05/21] broadcast error fixes for ipv6 and /31/32 --- netbox/ipam/forms/model_forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/ipam/forms/model_forms.py b/netbox/ipam/forms/model_forms.py index eb6dbe598eb..d80dabe5ffd 100644 --- a/netbox/ipam/forms/model_forms.py +++ b/netbox/ipam/forms/model_forms.py @@ -370,7 +370,7 @@ def clean(self): raise ValidationError(msg) if address.version == 6 and address.prefixlen not in (127, 128): raise ValidationError(msg) - if address.ip == address.broadcast: + if address.version == 4 and address.ip == address.broadcast and address.prefixlen not in (31, 32): msg = f"{address} is a broadcast address, which may not be assigned to an interface." raise ValidationError(msg) From 2e9586523f75e588bb47ba3d7d148caa72a670b9 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 13 Jun 2023 15:47:40 -0400 Subject: [PATCH 06/21] Changelog for #12687, #12838, #12850, #12862 --- docs/release-notes/version-3.5.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index e0c34bb400b..ae5766113f5 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -2,6 +2,16 @@ ## v3.5.4 (FUTURE) +### Enhancements + +* [#12862](https://github.com/netbox-community/netbox/issues/12862) - Add menu navigation button to add wireless links directly + +### Bug Fixes + +* [#12687](https://github.com/netbox-community/netbox/issues/12687) - Allow the assignment of all /31 IP addresses to interfaces +* [#12838](https://github.com/netbox-community/netbox/issues/12838) - Correct rounding of rack power utilization values +* [#12850](https://github.com/netbox-community/netbox/issues/12850) - Fix table configuration modal for the contact assignments list + --- ## v3.5.3 (2023-06-02) From 96cf95d1769d1a8318ced18ffbfdc0e2d4f4ce38 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Wed, 14 Jun 2023 14:06:23 +0530 Subject: [PATCH 07/21] fixes typo in register_model_view docstring #12824 --- netbox/utilities/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index 43ca9a58981..589b71f5072 100644 --- a/netbox/utilities/views.py +++ b/netbox/utilities/views.py @@ -178,7 +178,7 @@ def register_model_view(model, name='', path=None, kwargs=None): This decorator can be used to "attach" a view to any model in NetBox. This is typically used to inject additional tabs within a model's detail view. For example, to add a custom tab to NetBox's dcim.Site model: - @netbox_model_view(Site, 'myview', path='my-custom-view') + @register_model_view(Site, 'myview', path='my-custom-view') class MyView(ObjectView): ... From 928a34674e9e777f84bdaf00e71674ff3b8fd9f1 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Wed, 14 Jun 2023 14:16:04 +0530 Subject: [PATCH 08/21] change link parsing from quote_plus to quote #12822 --- netbox/extras/models/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index 9433ab6b0aa..b7034645f38 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -285,7 +285,7 @@ def render(self, context): text = clean_html(text, allowed_schemes) # Sanitize link - link = urllib.parse.quote_plus(link, safe='/:?&=%+[]@#') + link = urllib.parse.quote(link, safe='/:?&=%+[]@#') # Verify link scheme is allowed result = urllib.parse.urlparse(link) From c8cbced55e7879148623d65b69ff81a483b1d4db Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Wed, 14 Jun 2023 14:43:18 +0530 Subject: [PATCH 09/21] fix permission #12818 --- netbox/core/api/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/core/api/views.py b/netbox/core/api/views.py index fc4ef2927c8..7bf2f87a666 100644 --- a/netbox/core/api/views.py +++ b/netbox/core/api/views.py @@ -33,7 +33,7 @@ def sync(self, request, pk): """ Enqueue a job to synchronize the DataSource. """ - if not request.user.has_perm('extras.sync_datasource'): + if not request.user.has_perm('core.sync_datasource'): raise PermissionDenied("Syncing data sources requires the core.sync_datasource permission.") datasource = get_object_or_404(DataSource, pk=pk) From d03bfe89c0adec4a30fcd9f29e829bc4020183c0 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Wed, 14 Jun 2023 15:45:07 +0530 Subject: [PATCH 10/21] fix connected device api schema #12682 --- netbox/dcim/api/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 5b87c4e5d52..e8a2eabbf8a 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -646,7 +646,10 @@ class ConnectedDeviceViewSet(ViewSet): def get_view_name(self): return "Connected Device Locator" - @extend_schema(responses={200: OpenApiTypes.OBJECT}) + @extend_schema( + parameters=[_device_param, _interface_param], + responses={200: serializers.DeviceSerializer} + ) def list(self, request): peer_device_name = request.query_params.get(self._device_param.name) From c5f71c0c19afe1048f3ac608a6a82e1182c14dfe Mon Sep 17 00:00:00 2001 From: Sudheesh Singanamalla Date: Sun, 11 Jun 2023 13:08:29 -0700 Subject: [PATCH 11/21] Fixes #12847 - Include Missing Add buttons to Views Signed-off-by: Sudheesh Singanamalla --- netbox/dcim/views.py | 10 ---------- netbox/virtualization/views.py | 1 - 2 files changed, 11 deletions(-) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 0def4f4a8ae..b52e0afa516 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -2193,7 +2193,6 @@ class ConsolePortListView(generic.ObjectListView): filterset = filtersets.ConsolePortFilterSet filterset_form = forms.ConsolePortFilterForm table = tables.ConsolePortTable - actions = ('import', 'export', 'bulk_edit', 'bulk_delete') @register_model_view(ConsolePort) @@ -2257,7 +2256,6 @@ class ConsoleServerPortListView(generic.ObjectListView): filterset = filtersets.ConsoleServerPortFilterSet filterset_form = forms.ConsoleServerPortFilterForm table = tables.ConsoleServerPortTable - actions = ('import', 'export', 'bulk_edit', 'bulk_delete') @register_model_view(ConsoleServerPort) @@ -2321,7 +2319,6 @@ class PowerPortListView(generic.ObjectListView): filterset = filtersets.PowerPortFilterSet filterset_form = forms.PowerPortFilterForm table = tables.PowerPortTable - actions = ('import', 'export', 'bulk_edit', 'bulk_delete') @register_model_view(PowerPort) @@ -2385,7 +2382,6 @@ class PowerOutletListView(generic.ObjectListView): filterset = filtersets.PowerOutletFilterSet filterset_form = forms.PowerOutletFilterForm table = tables.PowerOutletTable - actions = ('import', 'export', 'bulk_edit', 'bulk_delete') @register_model_view(PowerOutlet) @@ -2449,7 +2445,6 @@ class InterfaceListView(generic.ObjectListView): filterset = filtersets.InterfaceFilterSet filterset_form = forms.InterfaceFilterForm table = tables.InterfaceTable - actions = ('import', 'export', 'bulk_edit', 'bulk_delete') @register_model_view(Interface) @@ -2559,7 +2554,6 @@ class FrontPortListView(generic.ObjectListView): filterset = filtersets.FrontPortFilterSet filterset_form = forms.FrontPortFilterForm table = tables.FrontPortTable - actions = ('import', 'export', 'bulk_edit', 'bulk_delete') @register_model_view(FrontPort) @@ -2623,7 +2617,6 @@ class RearPortListView(generic.ObjectListView): filterset = filtersets.RearPortFilterSet filterset_form = forms.RearPortFilterForm table = tables.RearPortTable - actions = ('import', 'export', 'bulk_edit', 'bulk_delete') @register_model_view(RearPort) @@ -2687,7 +2680,6 @@ class ModuleBayListView(generic.ObjectListView): filterset = filtersets.ModuleBayFilterSet filterset_form = forms.ModuleBayFilterForm table = tables.ModuleBayTable - actions = ('import', 'export', 'bulk_edit', 'bulk_delete') @register_model_view(ModuleBay) @@ -2743,7 +2735,6 @@ class DeviceBayListView(generic.ObjectListView): filterset = filtersets.DeviceBayFilterSet filterset_form = forms.DeviceBayFilterForm table = tables.DeviceBayTable - actions = ('import', 'export', 'bulk_edit', 'bulk_delete') @register_model_view(DeviceBay) @@ -2868,7 +2859,6 @@ class InventoryItemListView(generic.ObjectListView): filterset = filtersets.InventoryItemFilterSet filterset_form = forms.InventoryItemFilterForm table = tables.InventoryItemTable - actions = ('import', 'export', 'bulk_edit', 'bulk_delete') @register_model_view(InventoryItem) diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index 4a501e14e2b..75e83f9e1ac 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -415,7 +415,6 @@ class VMInterfaceListView(generic.ObjectListView): filterset = filtersets.VMInterfaceFilterSet filterset_form = forms.VMInterfaceFilterForm table = tables.VMInterfaceTable - actions = ('import', 'export', 'bulk_edit', 'bulk_delete') @register_model_view(VMInterface) From 0e873a01b8fa22face378db529cdb20df1702458 Mon Sep 17 00:00:00 2001 From: Dillon Henschen Date: Wed, 14 Jun 2023 13:49:00 -0400 Subject: [PATCH 12/21] Closes #12622: Fix assigning VLAN without site to Prefix (#12784) * Issue #12622: Fix creating Prefix using VLAN without site * Issue #12622: Fix importing Prefix using VLAN without site This commit also adds tests to verify the import changes implemented in this commit. * Issue #12622: Cleanup code to filter allowed VLANs on a prefix import * Closes #12622: Switch to VLAN selector dialog when creating Prefix --- netbox/ipam/forms/bulk_import.py | 34 +++++++++++++----- netbox/ipam/forms/model_forms.py | 4 +-- netbox/ipam/tests/test_views.py | 59 ++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 12 deletions(-) diff --git a/netbox/ipam/forms/bulk_import.py b/netbox/ipam/forms/bulk_import.py index fd0b315a0dd..683d40f4908 100644 --- a/netbox/ipam/forms/bulk_import.py +++ b/netbox/ipam/forms/bulk_import.py @@ -1,6 +1,7 @@ from django import forms from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError +from django.db.models import Q from django.utils.translation import gettext as _ from dcim.models import Device, Interface, Site @@ -181,16 +182,31 @@ class Meta: def __init__(self, data=None, *args, **kwargs): super().__init__(data, *args, **kwargs) - if data: + if not data: + return + + site = data.get('site') + vlan_group = data.get('vlan_group') + + # Limit VLAN queryset by assigned site and/or group (if specified) + query = Q() + + if site: + query |= Q(**{ + f"site__{self.fields['site'].to_field_name}": site + }) + # Don't Forget to include VLANs without a site in the filter + query |= Q(**{ + f"site__{self.fields['site'].to_field_name}__isnull": True + }) + + if vlan_group: + query &= Q(**{ + f"group__{self.fields['vlan_group'].to_field_name}": vlan_group + }) - # Limit VLAN queryset by assigned site and/or group (if specified) - params = {} - if data.get('site'): - params[f"site__{self.fields['site'].to_field_name}"] = data.get('site') - if data.get('vlan_group'): - params[f"group__{self.fields['vlan_group'].to_field_name}"] = data.get('vlan_group') - if params: - self.fields['vlan'].queryset = self.fields['vlan'].queryset.filter(**params) + queryset = self.fields['vlan'].queryset.filter(query) + self.fields['vlan'].queryset = queryset class IPRangeImportForm(NetBoxModelImportForm): diff --git a/netbox/ipam/forms/model_forms.py b/netbox/ipam/forms/model_forms.py index d80dabe5ffd..b0b08e4e073 100644 --- a/netbox/ipam/forms/model_forms.py +++ b/netbox/ipam/forms/model_forms.py @@ -211,10 +211,8 @@ class PrefixForm(TenancyForm, NetBoxModelForm): vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, + selector=True, label=_('VLAN'), - query_params={ - 'site_id': '$site', - } ) role = DynamicModelChoiceField( queryset=Role.objects.all(), diff --git a/netbox/ipam/tests/test_views.py b/netbox/ipam/tests/test_views.py index 44af9eae210..c9128c0f696 100644 --- a/netbox/ipam/tests/test_views.py +++ b/netbox/ipam/tests/test_views.py @@ -495,6 +495,65 @@ def test_prefix_ipaddresses(self): url = reverse('ipam:prefix_ipaddresses', kwargs={'pk': prefix.pk}) self.assertHttpStatus(self.client.get(url), 200) + @override_settings(EXEMPT_VIEW_PERMISSIONS=['*']) + def test_prefix_import(self): + """ + Custom import test for YAML-based imports (versus CSV) + """ + IMPORT_DATA = """ +prefix: 10.1.1.0/24 +status: active +vlan: 101 +site: Site 1 +""" + # Note, a site is not tied to the VLAN to verify the fix for #12622 + VLAN.objects.create(vid=101, name='VLAN101') + + # Add all required permissions to the test user + self.add_permissions('ipam.view_prefix', 'ipam.add_prefix') + + form_data = { + 'data': IMPORT_DATA, + 'format': 'yaml' + } + response = self.client.post(reverse('ipam:prefix_import'), data=form_data, follow=True) + self.assertHttpStatus(response, 200) + + prefix = Prefix.objects.get(prefix='10.1.1.0/24') + self.assertEqual(prefix.status, PrefixStatusChoices.STATUS_ACTIVE) + self.assertEqual(prefix.vlan.vid, 101) + self.assertEqual(prefix.site.name, "Site 1") + + @override_settings(EXEMPT_VIEW_PERMISSIONS=['*']) + def test_prefix_import_with_vlan_group(self): + """ + This test covers a unique import edge case where VLAN group is specified during the import. + """ + IMPORT_DATA = """ +prefix: 10.1.2.0/24 +status: active +vlan: 102 +site: Site 1 +vlan_group: Group 1 +""" + vlan_group = VLANGroup.objects.create(name='Group 1', slug='group-1', scope=Site.objects.get(name="Site 1")) + VLAN.objects.create(vid=102, name='VLAN102', group=vlan_group) + + # Add all required permissions to the test user + self.add_permissions('ipam.view_prefix', 'ipam.add_prefix') + + form_data = { + 'data': IMPORT_DATA, + 'format': 'yaml' + } + response = self.client.post(reverse('ipam:prefix_import'), data=form_data, follow=True) + self.assertHttpStatus(response, 200) + + prefix = Prefix.objects.get(prefix='10.1.2.0/24') + self.assertEqual(prefix.status, PrefixStatusChoices.STATUS_ACTIVE) + self.assertEqual(prefix.vlan.vid, 102) + self.assertEqual(prefix.site.name, "Site 1") + class IPRangeTestCase(ViewTestCases.PrimaryObjectViewTestCase): model = IPRange From 4d686e8162e229fdab6261808f57a760f42fee9e Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 14 Jun 2023 13:54:40 -0400 Subject: [PATCH 13/21] Changelog for #12622, #12682, #12818, #12822, #12847 --- docs/release-notes/version-3.5.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index ae5766113f5..f2a3de0e8ff 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -4,11 +4,16 @@ ### Enhancements +* [#12847](https://github.com/netbox-community/netbox/issues/12847) - Include "add" button on all device & virtual machine component list views * [#12862](https://github.com/netbox-community/netbox/issues/12862) - Add menu navigation button to add wireless links directly ### Bug Fixes +* [#12622](https://github.com/netbox-community/netbox/issues/12622) - Permit the assignment of non-site VLANs to prefixes assigned to a site +* [#12682](https://github.com/netbox-community/netbox/issues/12682) - Correct OpenAPI schema for connected device API endpoint * [#12687](https://github.com/netbox-community/netbox/issues/12687) - Allow the assignment of all /31 IP addresses to interfaces +* [#12818](https://github.com/netbox-community/netbox/issues/12818) - Fix permissions evaluation when queuing a data sync job +* [#12822](https://github.com/netbox-community/netbox/issues/12822) - Fix encoding of whitespace in custom link URLs * [#12838](https://github.com/netbox-community/netbox/issues/12838) - Correct rounding of rack power utilization values * [#12850](https://github.com/netbox-community/netbox/issues/12850) - Fix table configuration modal for the contact assignments list From 93175888f088aa99c58b05e8deef806f0b640c24 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Wed, 14 Jun 2023 13:36:30 +0530 Subject: [PATCH 14/21] add color to ChangeActionChoices #12828 --- netbox/extras/choices.py | 6 +++--- netbox/extras/models/staging.py | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/netbox/extras/choices.py b/netbox/extras/choices.py index 6fc14b96588..63bdbf7dbe0 100644 --- a/netbox/extras/choices.py +++ b/netbox/extras/choices.py @@ -210,7 +210,7 @@ class ChangeActionChoices(ChoiceSet): ACTION_DELETE = 'delete' CHOICES = ( - (ACTION_CREATE, 'Create'), - (ACTION_UPDATE, 'Update'), - (ACTION_DELETE, 'Delete'), + (ACTION_CREATE, 'Create', 'green'), + (ACTION_UPDATE, 'Update', 'blue'), + (ACTION_DELETE, 'Delete', 'red'), ) diff --git a/netbox/extras/models/staging.py b/netbox/extras/models/staging.py index b46d6a7bcc6..6d86e0dfeab 100644 --- a/netbox/extras/models/staging.py +++ b/netbox/extras/models/staging.py @@ -112,3 +112,6 @@ def apply(self): instance = self.model.objects.get(pk=self.object_id) logger.info(f'Deleting {self.model._meta.verbose_name} {instance}') instance.delete() + + def get_action_color(self): + return ChangeActionChoices.colors.get(self.action) From 0b2162569ff3801d9e51aa69348baffd6d8dc464 Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 16 May 2023 10:49:01 -0700 Subject: [PATCH 15/21] 12474 update cable terminations when moving location between sites --- netbox/dcim/signals.py | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/dcim/signals.py b/netbox/dcim/signals.py index 7ef08d2cc3d..a51872719a7 100644 --- a/netbox/dcim/signals.py +++ b/netbox/dcim/signals.py @@ -27,6 +27,7 @@ def handle_location_site_change(instance, created, **kwargs): Rack.objects.filter(location__in=locations).update(site=instance.site) Device.objects.filter(location__in=locations).update(site=instance.site) PowerPanel.objects.filter(location__in=locations).update(site=instance.site) + CableTermination.objects.filter(_location__in=locations).update(_site=instance.site) @receiver(post_save, sender=Rack) From 8aeb31751ab6b36d92ffd485aab5879473e63eca Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 14 Jun 2023 15:29:48 -0400 Subject: [PATCH 16/21] Fixes #12845: Fix pagination of related IP addresses table --- .../ipam/ipaddress/ip_addresses.html | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/netbox/templates/ipam/ipaddress/ip_addresses.html b/netbox/templates/ipam/ipaddress/ip_addresses.html index 7034329aa52..b82ec2375cb 100644 --- a/netbox/templates/ipam/ipaddress/ip_addresses.html +++ b/netbox/templates/ipam/ipaddress/ip_addresses.html @@ -2,18 +2,18 @@ {% load helpers %} {% block content %} - {% include 'inc/table_controls_htmx.html' with table_modal="IPAddressTable_config" %} - - {% csrf_token %} -
-
- {% include 'htmx/table.html' %} -
-
- -{% endblock content %} + {% include 'inc/table_controls_htmx.html' with table_modal="IPAddressTable_config" %} +
+ {% csrf_token %} +
+
+ {% include 'htmx/table.html' %} +
+
+
+{% endblock %} {% block modals %} - {{ block.super }} - {% table_config_form table %} + {{ block.super }} + {% table_config_form table %} {% endblock modals %} From 7fc69f3945a123aff522f3a2fe110a1f96245ebc Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 15 Jun 2023 09:17:03 -0400 Subject: [PATCH 17/21] Fixes #12914: Clear stored ordering from user config when cleared by request --- netbox/netbox/tables/tables.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/netbox/netbox/tables/tables.py b/netbox/netbox/tables/tables.py index 839d8599666..20eab822db4 100644 --- a/netbox/netbox/tables/tables.py +++ b/netbox/netbox/tables/tables.py @@ -140,10 +140,14 @@ def configure(self, request): if request.user.is_authenticated: table_name = self.__class__.__name__ if self.prefixed_order_by_field in request.GET: - # If an ordering has been specified as a query parameter, save it as the - # user's preferred ordering for this table. - ordering = request.GET.getlist(self.prefixed_order_by_field) - request.user.config.set(f'tables.{table_name}.ordering', ordering, commit=True) + if request.GET[self.prefixed_order_by_field]: + # If an ordering has been specified as a query parameter, save it as the + # user's preferred ordering for this table. + ordering = request.GET.getlist(self.prefixed_order_by_field) + request.user.config.set(f'tables.{table_name}.ordering', ordering, commit=True) + else: + # If the ordering has been set to none (empty), clear any existing preference. + request.user.config.clear(f'tables.{table_name}.ordering', commit=True) elif ordering := request.user.config.get(f'tables.{table_name}.ordering'): # If no ordering has been specified, set the preferred ordering (if any). self.order_by = ordering From 6ef333ea6870f2b62bf62053f05cc93fdbb83bc3 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 15 Jun 2023 15:00:45 -0400 Subject: [PATCH 18/21] Fixes #12885: Permit mounting of devices in U100 (#12901) * Fixes #12885: Permit mounting of devices in U100 * Define a RACK_U_HEIGHT_MAX constant --- netbox/dcim/constants.py | 1 + netbox/dcim/migrations/0154_half_height_rack_units.py | 2 +- netbox/dcim/models/devices.py | 2 +- netbox/dcim/models/racks.py | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/netbox/dcim/constants.py b/netbox/dcim/constants.py index 80d7558c9bc..b3c065b5a55 100644 --- a/netbox/dcim/constants.py +++ b/netbox/dcim/constants.py @@ -11,6 +11,7 @@ # RACK_U_HEIGHT_DEFAULT = 42 +RACK_U_HEIGHT_MAX = 100 RACK_ELEVATION_BORDER_WIDTH = 2 RACK_ELEVATION_DEFAULT_LEGEND_WIDTH = 30 diff --git a/netbox/dcim/migrations/0154_half_height_rack_units.py b/netbox/dcim/migrations/0154_half_height_rack_units.py index dd21fddcfc6..f212aa21a64 100644 --- a/netbox/dcim/migrations/0154_half_height_rack_units.py +++ b/netbox/dcim/migrations/0154_half_height_rack_units.py @@ -18,6 +18,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='device', name='position', - field=models.DecimalField(blank=True, decimal_places=1, max_digits=4, null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(99.5)]), + field=models.DecimalField(blank=True, decimal_places=1, max_digits=4, null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100.5)]), ), ] diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index 85a5d687079..4cf330ffd98 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -568,7 +568,7 @@ class Device(PrimaryModel, ConfigContextModel): decimal_places=1, blank=True, null=True, - validators=[MinValueValidator(1), MaxValueValidator(99.5)], + validators=[MinValueValidator(1), MaxValueValidator(RACK_U_HEIGHT_MAX + 0.5)], verbose_name='Position (U)', help_text=_('The lowest-numbered unit occupied by the device') ) diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index 54de5c434d1..d73c8e27b7d 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -126,7 +126,7 @@ class Rack(PrimaryModel, WeightMixin): u_height = models.PositiveSmallIntegerField( default=RACK_U_HEIGHT_DEFAULT, verbose_name='Height (U)', - validators=[MinValueValidator(1), MaxValueValidator(100)], + validators=[MinValueValidator(1), MaxValueValidator(RACK_U_HEIGHT_MAX)], help_text=_('Height in rack units') ) desc_units = models.BooleanField( From e11991c7a4caceb33f55412d8dffa1051223abcd Mon Sep 17 00:00:00 2001 From: Luke Anderson Date: Fri, 16 Jun 2023 04:34:08 +0930 Subject: [PATCH 19/21] Fix #12865 - Include Add Nav Buttons for Report and Script Objects (#12909) --- netbox/netbox/navigation/menu.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/netbox/netbox/navigation/menu.py b/netbox/netbox/navigation/menu.py index d139546d99b..e009f62f184 100644 --- a/netbox/netbox/navigation/menu.py +++ b/netbox/netbox/navigation/menu.py @@ -301,12 +301,14 @@ MenuItem( link='extras:report_list', link_text=_('Reports'), - permissions=['extras.view_report'] + permissions=['extras.view_report'], + buttons=get_model_buttons('extras', "reportmodule", actions=['add']) ), MenuItem( link='extras:script_list', link_text=_('Scripts'), - permissions=['extras.view_script'] + permissions=['extras.view_script'], + buttons=get_model_buttons('extras', "scriptmodule", actions=['add']) ), ), ), From cdce500d909ffc91d24107fa60191da9d00828ec Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 15 Jun 2023 16:15:15 -0400 Subject: [PATCH 20/21] Changelog for #12474, #12828, #12845, #12865, #12885, #12914 --- docs/release-notes/version-3.5.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index f2a3de0e8ff..29c9b5d509f 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -4,18 +4,24 @@ ### Enhancements +* [#12828](https://github.com/netbox-community/netbox/issues/12828) - Define colors for staged change action choices * [#12847](https://github.com/netbox-community/netbox/issues/12847) - Include "add" button on all device & virtual machine component list views * [#12862](https://github.com/netbox-community/netbox/issues/12862) - Add menu navigation button to add wireless links directly +* [#12865](https://github.com/netbox-community/netbox/issues/12865) - Add "add" buttons for reports & scripts to navigation menu ### Bug Fixes +* [#12474](https://github.com/netbox-community/netbox/issues/12474) - Update cable terminations when assigning a location to a new site * [#12622](https://github.com/netbox-community/netbox/issues/12622) - Permit the assignment of non-site VLANs to prefixes assigned to a site * [#12682](https://github.com/netbox-community/netbox/issues/12682) - Correct OpenAPI schema for connected device API endpoint * [#12687](https://github.com/netbox-community/netbox/issues/12687) - Allow the assignment of all /31 IP addresses to interfaces * [#12818](https://github.com/netbox-community/netbox/issues/12818) - Fix permissions evaluation when queuing a data sync job * [#12822](https://github.com/netbox-community/netbox/issues/12822) - Fix encoding of whitespace in custom link URLs * [#12838](https://github.com/netbox-community/netbox/issues/12838) - Correct rounding of rack power utilization values +* [#12845](https://github.com/netbox-community/netbox/issues/12845) - Fix pagination of objects for related IP addresses table * [#12850](https://github.com/netbox-community/netbox/issues/12850) - Fix table configuration modal for the contact assignments list +* [#12885](https://github.com/netbox-community/netbox/issues/12885) - Permit mounting of devices in rack unit 100 +* [#12914](https://github.com/netbox-community/netbox/issues/12914) - Clear stored ordering from user config when cleared by request --- From 54622b5f9263dfe2bea9edb2b2e9559096762697 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 20 Jun 2023 13:56:09 -0400 Subject: [PATCH 21/21] Release v3.5.4 --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- .github/ISSUE_TEMPLATE/feature_request.yaml | 2 +- docs/release-notes/version-3.5.md | 2 +- netbox/netbox/settings.py | 2 +- requirements.txt | 16 ++++++++-------- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 5e456d0dfb2..b3dd583ca4f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.5.3 + placeholder: v3.5.4 validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index e317dd64c98..bd93001e736 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.5.3 + placeholder: v3.5.4 validations: required: true - type: dropdown diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 29c9b5d509f..49d2e63478a 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -1,6 +1,6 @@ # NetBox v3.5 -## v3.5.4 (FUTURE) +## v3.5.4 (2023-06-20) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index e77ac43c013..22193dbacdb 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -25,7 +25,7 @@ # Environment setup # -VERSION = '3.5.4-dev' +VERSION = '3.5.4' # Hostname HOSTNAME = platform.node() diff --git a/requirements.txt b/requirements.txt index ee6a79635cf..e6e56ce5633 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,19 +1,19 @@ bleach==6.0.0 -boto3==1.26.145 +boto3==1.26.156 Django==4.1.9 -django-cors-headers==4.0.0 +django-cors-headers==4.1.0 django-debug-toolbar==4.1.0 django-filter==23.2 django-graphiql-debug-toolbar==0.2.0 django-mptt==0.14 django-pglocks==1.0.4 django-prometheus==2.3.1 -django-redis==5.2.0 -django-rich==1.5.0 +django-redis==5.3.0 +django-rich==1.6.0 django-rq==2.8.1 django-tables2==2.5.3 django-taggit==4.0.0 -django-timezone-field==5.0 +django-timezone-field==5.1 djangorestframework==3.14.0 drf-spectacular==0.26.2 drf-spectacular-sidecar==2023.6.1 @@ -23,15 +23,15 @@ graphene-django==3.0.0 gunicorn==20.1.0 Jinja2==3.1.2 Markdown==3.3.7 -mkdocs-material==9.1.15 +mkdocs-material==9.1.16 mkdocstrings[python-legacy]==0.22.0 netaddr==0.8.0 Pillow==9.5.0 psycopg2-binary==2.9.6 PyYAML==6.0 -sentry-sdk==1.25.0 +sentry-sdk==1.25.1 social-auth-app-django==5.2.0 social-auth-core[openidconnect]==4.4.2 svgwrite==1.4.3 -tablib==3.4.0 +tablib==3.5.0 tzdata==2023.3