Skip to content

Commit 3f67b5d

Browse files
authored
Merge pull request #16859 from netbox-community/develop
Release v4.0.7
2 parents b1d1b51 + 596514c commit 3f67b5d

File tree

61 files changed

+12169
-11141
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+12169
-11141
lines changed

Diff for: .github/ISSUE_TEMPLATE/bug_report.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ body:
2626
attributes:
2727
label: NetBox Version
2828
description: What version of NetBox are you currently running?
29-
placeholder: v4.0.6
29+
placeholder: v4.0.7
3030
validations:
3131
required: true
3232
- type: dropdown

Diff for: .github/ISSUE_TEMPLATE/feature_request.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ body:
1414
attributes:
1515
label: NetBox version
1616
description: What version of NetBox are you currently running?
17-
placeholder: v4.0.6
17+
placeholder: v4.0.7
1818
validations:
1919
required: true
2020
- type: dropdown

Diff for: docs/configuration/error-reporting.md

+11
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ The sampling rate for errors. Must be a value between 0 (disabled) and 1.0 (repo
3131

3232
---
3333

34+
## SENTRY_SEND_DEFAULT_PII
35+
36+
Default: False
37+
38+
Maps to the Sentry SDK's [`send_default_pii`](https://docs.sentry.io/platforms/python/configuration/options/#send-default-pii) parameter. If enabled, certain personally identifiable information (PII) is added.
39+
40+
!!! warning "Sensitive data"
41+
If you enable this option, be aware that sensitive data such as cookies and authentication tokens will be logged.
42+
43+
---
44+
3445
## SENTRY_TAGS
3546

3647
An optional dictionary of tag names and values to apply to Sentry error reports.For example:

Diff for: docs/configuration/system.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ The dotted path to the desired search backend class. `CachedValueSearchBackend`
177177

178178
Default: None (local storage)
179179

180-
The backend storage engine for handling uploaded files (e.g. image attachments). NetBox supports integration with the [`django-storages`](https://django-storages.readthedocs.io/en/stable/) package, which provides backends for several popular file storage services. If not configured, local filesystem storage will be used.
180+
The backend storage engine for handling uploaded files (e.g. image attachments). NetBox supports integration with the [`django-storages`](https://django-storages.readthedocs.io/en/stable/) and [`django-storage-swift`](https://github.com/dennisv/django-storage-swift) packages, which provide backends for several popular file storage services. If not configured, local filesystem storage will be used.
181181

182182
The configuration parameters for the specified storage backend are defined under the `STORAGE_CONFIG` setting.
183183

@@ -187,7 +187,7 @@ The configuration parameters for the specified storage backend are defined under
187187

188188
Default: Empty
189189

190-
A dictionary of configuration parameters for the storage backend configured as `STORAGE_BACKEND`. The specific parameters to be used here are specific to each backend; see the [`django-storages` documentation](https://django-storages.readthedocs.io/en/stable/) for more detail.
190+
A dictionary of configuration parameters for the storage backend configured as `STORAGE_BACKEND`. The specific parameters to be used here are specific to each backend; see the documentation for your selected backend ([`django-storages`](https://django-storages.readthedocs.io/en/stable/) or [`django-storage-swift`](https://github.com/dennisv/django-storage-swift)) for more detail.
191191

192192
If `STORAGE_BACKEND` is not defined, this setting will be ignored.
193193

Diff for: docs/development/release-checklist.md

+2
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,6 @@ First, run the `build-site` action, by navigating to Actions > build-site > Run
135135

136136
Once the documentation files have been compiled, they must be published by running the `deploy-kinsta` action. Select the desired deployment environment (staging or production) and specify `latest` as the deploy tag.
137137

138+
Clear the CDN cache from the [Kinsta](https://my.kinsta.com/) portal. Navigate to _Sites_ / _NetBox Labs_ / _Live_, select _CDN_ in the left-nav, click the _Clear CDN cache_ button, and confirm the clear operation.
139+
138140
Finally, verify that the documentation at <https://netboxlabs.com/docs/netbox/en/stable/> has been updated.

Diff for: docs/plugins/removal.md

+16
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,19 @@ DROP TABLE
7070
netbox=> DROP TABLE pluginname_bar;
7171
DROP TABLE
7272
```
73+
74+
### Remove the Django Migration Records
75+
76+
After removing the tables created by a plugin, the migrations that created the tables need to be removed from Django's migration history as well. This is necessary to make it possible to reinstall the plugin at a later time. If the migration history were left in place, Django would skip all migrations that were executed in the course of a previous installation, which would cause the plugin to fail after reinstallation.
77+
78+
```no-highlight
79+
netbox=> SELECT * FROM django_migrations WHERE app='pluginname';
80+
id | app | name | applied
81+
-----+------------+------------------------+-------------------------------
82+
492 | pluginname | 0001_initial | 2023-12-21 11:59:59.325995+00
83+
493 | pluginname | 0002_add_foo | 2023-12-21 11:59:59.330026+00
84+
netbox=> DELETE FROM django_migrations WHERE app='pluginname';
85+
```
86+
87+
!!! warning
88+
Exercise extreme caution when altering Django system tables. Users are strongly encouraged to perform a backup of their database immediately before taking these actions.

Diff for: docs/release-notes/version-4.0.md

+36
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
# NetBox v4.0
22

3+
## v4.0.7 (2024-07-09)
4+
5+
### Enhancements
6+
7+
* [#14554](https://github.com/netbox-community/netbox/issues/14554) - Add support for [django-storage-swift](https://github.com/dennisv/django-storage-swift) storage backend
8+
* [#16424](https://github.com/netbox-community/netbox/issues/16424) - Enable filtering of devices by cluster and cluster group
9+
* [#16716](https://github.com/netbox-community/netbox/issues/16716) - Display NAT address (if any) for OOB IP address under device view
10+
* [#16725](https://github.com/netbox-community/netbox/issues/16725) - Always position the admin section last in the navigation menu
11+
* [#16791](https://github.com/netbox-community/netbox/issues/16791) - Add 200 & 400 Gbps selections for circuit termination port speed
12+
* [#16802](https://github.com/netbox-community/netbox/issues/16802) - Introduce `SENTRY_SEND_DEFAULT_PII` configuration parameter and disable PII export by default
13+
* [#16817](https://github.com/netbox-community/netbox/issues/16817) - Add 200 & 400 Gbps selections for circuit commit rate
14+
15+
### Bug Fixes
16+
17+
* [#16523](https://github.com/netbox-community/netbox/issues/16523) - Restore highlighting of current device in virtual chassis members panel
18+
* [#16654](https://github.com/netbox-community/netbox/issues/16654) - Fix parent item assignment for inventory item bulk import
19+
* [#16657](https://github.com/netbox-community/netbox/issues/16657) - Fix translation of object types in global search
20+
* [#16679](https://github.com/netbox-community/netbox/issues/16679) - Avoid overwriting custom JSON fields during bulk edit
21+
* [#16689](https://github.com/netbox-community/netbox/issues/16689) - System configuration view should reflect static parameters when no config revisions exist
22+
* [#16714](https://github.com/netbox-community/netbox/issues/16714) - Fix cloning of device types with 0U height
23+
* [#16721](https://github.com/netbox-community/netbox/issues/16721) - Fix errant API request after deselecting a rack in device edit form
24+
* [#16723](https://github.com/netbox-community/netbox/issues/16723) - Fix escaping of path to virtual environment in `upgrade.sh`
25+
* [#16735](https://github.com/netbox-community/netbox/issues/16735) - Object list "results" tab should show a count of zero when empty
26+
* [#16747](https://github.com/netbox-community/netbox/issues/16747) - Avoid clearing entire search cache when manually reindexing specific apps/models
27+
* [#16758](https://github.com/netbox-community/netbox/issues/16758) - Ensure manually selected lagnuage persists across browser sessions
28+
* [#16779](https://github.com/netbox-community/netbox/issues/16779) - Fix saved filter selection for child object lists
29+
* [#16780](https://github.com/netbox-community/netbox/issues/16780) - IKE proposal created via REST API should not require authentication_algorithm
30+
* [#16796](https://github.com/netbox-community/netbox/issues/16796) - Allow assignment of VM with no site to a cluster with a site
31+
* [#16806](https://github.com/netbox-community/netbox/issues/16806) - Fix redirect URL when creating contact assignments with "add another" button
32+
* [#16807](https://github.com/netbox-community/netbox/issues/16807) - Fix layout of VLAN edit form when custom fields are present
33+
* [#16808](https://github.com/netbox-community/netbox/issues/16808) - Fix event rule triggering in scenario where objects are updated immediately prior to deletion
34+
* [#16813](https://github.com/netbox-community/netbox/issues/16813) - Fix AttributeError exception when filtering bookmarks in dashboard widget by object type
35+
* [#16843](https://github.com/netbox-community/netbox/issues/16843) - Permit creation of IKE policies via REST API without specifying an IKE mode
36+
37+
---
38+
339
## v4.0.6 (2024-06-24)
440

541
### Enhancements

Diff for: netbox/account/views.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def post(self, request):
111111

112112
# Set the user's preferred language (if any)
113113
if language := request.user.config.get('locale.language'):
114-
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language)
114+
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language, max_age=request.session.get_expiry_age())
115115

116116
return response
117117

@@ -206,7 +206,7 @@ def post(self, request):
206206

207207
# Set/clear language cookie
208208
if language := form.cleaned_data['locale.language']:
209-
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language)
209+
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language, max_age=request.session.get_expiry_age())
210210
else:
211211
response.delete_cookie(settings.LANGUAGE_COOKIE_NAME)
212212

Diff for: netbox/circuits/choices.py

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class CircuitCommitRateChoices(ChoiceSet):
3838
(25000000, '25 Gbps'),
3939
(40000000, '40 Gbps'),
4040
(100000000, '100 Gbps'),
41+
(200000000, '200 Gbps'),
42+
(400000000, '400 Gbps'),
4143
(1544, 'T1 (1.544 Mbps)'),
4244
(2048, 'E1 (2.048 Mbps)'),
4345
]
@@ -69,6 +71,8 @@ class CircuitTerminationPortSpeedChoices(ChoiceSet):
6971
(25000000, '25 Gbps'),
7072
(40000000, '40 Gbps'),
7173
(100000000, '100 Gbps'),
74+
(200000000, '200 Gbps'),
75+
(400000000, '400 Gbps'),
7276
(1544, 'T1 (1.544 Mbps)'),
7377
(2048, 'E1 (2.048 Mbps)'),
7478
]

Diff for: netbox/circuits/forms/bulk_import.py

-3
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,6 @@ class CircuitTypeImportForm(NetBoxModelImportForm):
6666
class Meta:
6767
model = CircuitType
6868
fields = ('name', 'slug', 'color', 'description', 'tags')
69-
help_texts = {
70-
'color': mark_safe(_('RGB color in hexadecimal. Example:') + ' <code>00ff00</code>'),
71-
}
7269

7370

7471
class CircuitImportForm(NetBoxModelImportForm):

Diff for: netbox/core/views.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ def get(self, request):
555555
config = ConfigRevision.objects.get(pk=cache.get('config_version'))
556556
except ConfigRevision.DoesNotExist:
557557
# Fall back to using the active config data if no record is found
558-
config = ConfigRevision(data=get_config().defaults)
558+
config = get_config()
559559

560560
# Raw data export
561561
if 'export' in request.GET:

Diff for: netbox/dcim/filtersets.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
ContentTypeFilter, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, MultiValueWWNFilter,
2121
NumericArrayFilter, TreeNodeMultipleChoiceFilter,
2222
)
23-
from virtualization.models import Cluster
23+
from virtualization.models import Cluster, ClusterGroup
2424
from vpn.models import L2VPN
2525
from wireless.choices import WirelessRoleChoices, WirelessChannelChoices
2626
from wireless.models import WirelessLAN, WirelessLink
@@ -1018,6 +1018,17 @@ class DeviceFilterSet(
10181018
queryset=Cluster.objects.all(),
10191019
label=_('VM cluster (ID)'),
10201020
)
1021+
cluster_group = django_filters.ModelMultipleChoiceFilter(
1022+
field_name='cluster__group__slug',
1023+
queryset=ClusterGroup.objects.all(),
1024+
to_field_name='slug',
1025+
label=_('Cluster group (slug)'),
1026+
)
1027+
cluster_group_id = django_filters.ModelMultipleChoiceFilter(
1028+
field_name='cluster__group',
1029+
queryset=ClusterGroup.objects.all(),
1030+
label=_('Cluster group (ID)'),
1031+
)
10211032
model = django_filters.ModelMultipleChoiceFilter(
10221033
field_name='device_type__slug',
10231034
queryset=DeviceType.objects.all(),

Diff for: netbox/dcim/forms/bulk_import.py

+1-13
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,6 @@ class RackRoleImportForm(NetBoxModelImportForm):
174174
class Meta:
175175
model = RackRole
176176
fields = ('name', 'slug', 'color', 'description', 'tags')
177-
help_texts = {
178-
'color': mark_safe(_('RGB color in hexadecimal. Example:') + ' <code>00ff00</code>'),
179-
}
180177

181178

182179
class RackImportForm(NetBoxModelImportForm):
@@ -384,9 +381,6 @@ class DeviceRoleImportForm(NetBoxModelImportForm):
384381
class Meta:
385382
model = DeviceRole
386383
fields = ('name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags')
387-
help_texts = {
388-
'color': mark_safe(_('RGB color in hexadecimal. Example:') + ' <code>00ff00</code>'),
389-
}
390384

391385

392386
class PlatformImportForm(NetBoxModelImportForm):
@@ -1052,7 +1046,7 @@ class InventoryItemImportForm(NetBoxModelImportForm):
10521046
class Meta:
10531047
model = InventoryItem
10541048
fields = (
1055-
'device', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered',
1049+
'device', 'name', 'label', 'role', 'manufacturer', 'parent', 'part_id', 'serial', 'asset_tag', 'discovered',
10561050
'description', 'tags', 'component_type', 'component_name',
10571051
)
10581052

@@ -1104,9 +1098,6 @@ class InventoryItemRoleImportForm(NetBoxModelImportForm):
11041098
class Meta:
11051099
model = InventoryItemRole
11061100
fields = ('name', 'slug', 'color', 'description')
1107-
help_texts = {
1108-
'color': mark_safe(_('RGB color in hexadecimal. Example:') + ' <code>00ff00</code>'),
1109-
}
11101101

11111102

11121103
#
@@ -1183,9 +1174,6 @@ class Meta:
11831174
'side_a_device', 'side_a_type', 'side_a_name', 'side_b_device', 'side_b_type', 'side_b_name', 'type',
11841175
'status', 'tenant', 'label', 'color', 'length', 'length_unit', 'description', 'comments', 'tags',
11851176
]
1186-
help_texts = {
1187-
'color': mark_safe(_('RGB color in hexadecimal. Example:') + ' <code>00ff00</code>'),
1188-
}
11891177

11901178
def _clean_side(self, side):
11911179
"""

Diff for: netbox/dcim/forms/filtersets.py

+12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from utilities.forms.fields import ColorField, DynamicModelMultipleChoiceField, TagFilterField
1515
from utilities.forms.rendering import FieldSet
1616
from utilities.forms.widgets import NumberWithOptions
17+
from virtualization.models import Cluster, ClusterGroup
1718
from vpn.models import L2VPN
1819
from wireless.choices import *
1920

@@ -655,6 +656,7 @@ class DeviceFilterForm(
655656
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports',
656657
name=_('Components')
657658
),
659+
FieldSet('cluster_group_id', 'cluster_id', name=_('Cluster')),
658660
FieldSet(
659661
'has_primary_ip', 'has_oob_ip', 'virtual_chassis_member', 'config_template_id', 'local_context_data',
660662
'has_virtual_device_context',
@@ -821,6 +823,16 @@ class DeviceFilterForm(
821823
choices=BOOLEAN_WITH_BLANK_CHOICES
822824
)
823825
)
826+
cluster_id = DynamicModelMultipleChoiceField(
827+
queryset=Cluster.objects.all(),
828+
required=False,
829+
label=_('Cluster')
830+
)
831+
cluster_group_id = DynamicModelMultipleChoiceField(
832+
queryset=ClusterGroup.objects.all(),
833+
required=False,
834+
label=_('Cluster group')
835+
)
824836
tag = TagFilterField(model)
825837

826838

Diff for: netbox/dcim/tests/test_filtersets.py

+17-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from netbox.choices import ColorChoices
1010
from tenancy.models import Tenant, TenantGroup
1111
from utilities.testing import ChangeLoggedFilterSetTests, create_test_device
12-
from virtualization.models import Cluster, ClusterType
12+
from virtualization.models import Cluster, ClusterType, ClusterGroup
1313
from wireless.choices import WirelessChannelChoices, WirelessRoleChoices
1414

1515
User = get_user_model()
@@ -1959,10 +1959,16 @@ def setUpTestData(cls):
19591959
Rack.objects.bulk_create(racks)
19601960

19611961
cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
1962+
cluster_groups = (
1963+
ClusterGroup(name='Cluster Group 1', slug='cluster-group-1'),
1964+
ClusterGroup(name='Cluster Group 2', slug='cluster-group-2'),
1965+
ClusterGroup(name='Cluster Group 3', slug='cluster-group-3'),
1966+
)
1967+
ClusterGroup.objects.bulk_create(cluster_groups)
19621968
clusters = (
1963-
Cluster(name='Cluster 1', type=cluster_type),
1964-
Cluster(name='Cluster 2', type=cluster_type),
1965-
Cluster(name='Cluster 3', type=cluster_type),
1969+
Cluster(name='Cluster 1', type=cluster_type, group=cluster_groups[0]),
1970+
Cluster(name='Cluster 2', type=cluster_type, group=cluster_groups[1]),
1971+
Cluster(name='Cluster 3', type=cluster_type, group=cluster_groups[2]),
19661972
)
19671973
Cluster.objects.bulk_create(clusters)
19681974

@@ -2213,6 +2219,13 @@ def test_cluster(self):
22132219
params = {'cluster_id': [clusters[0].pk, clusters[1].pk]}
22142220
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
22152221

2222+
def test_cluster_group(self):
2223+
cluster_groups = ClusterGroup.objects.all()[:2]
2224+
params = {'cluster_group_id': [cluster_groups[0].pk, cluster_groups[1].pk]}
2225+
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
2226+
params = {'cluster_group': [cluster_groups[0].slug, cluster_groups[1].slug]}
2227+
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
2228+
22162229
def test_model(self):
22172230
params = {'model': ['model-1', 'model-2']}
22182231
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

0 commit comments

Comments
 (0)