Skip to content

Commit 9fb52be

Browse files
Merge pull request #12805 from netbox-community/develop
Release v3.5.3
2 parents c9b79ca + 46d1d5a commit 9fb52be

File tree

40 files changed

+583
-174
lines changed

40 files changed

+583
-174
lines changed

.github/ISSUE_TEMPLATE/bug_report.yaml

Lines changed: 1 addition & 1 deletion
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: v3.5.2
17+
placeholder: v3.5.3
1818
validations:
1919
required: true
2020
- type: dropdown

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ blank_issues_enabled: false
33
contact_links:
44
- name: 📖 Contributing Policy
55
url: https://github.com/netbox-community/netbox/blob/develop/CONTRIBUTING.md
6-
about: "Please read through our contributing policy before opening an issue or pull request"
6+
about: "Please read through our contributing policy before opening an issue or pull request."
77
- name: ❓ Discussion
88
url: https://github.com/netbox-community/netbox/discussions
9-
about: "If you're just looking for help, try starting a discussion instead"
9+
about: "If you're just looking for help, try starting a discussion instead."
10+
- name: 💡 Plugin Idea
11+
url: https://plugin-ideas.netbox.dev
12+
about: "Have an idea for a plugin? Head over to the ideas board!"
1013
- name: 💬 Community Slack
11-
url: https://netdev.chat/
12-
about: "Join #netbox on the NetDev Community Slack for assistance with installation issues and other problems"
14+
url: https://netdev.chat
15+
about: "Join #netbox on the NetDev Community Slack for assistance with installation issues and other problems."

.github/ISSUE_TEMPLATE/feature_request.yaml

Lines changed: 1 addition & 1 deletion
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: v3.5.2
17+
placeholder: v3.5.3
1818
validations:
1919
required: true
2020
- type: dropdown

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
<div align="center">
2-
<strong>The :ballot_box_with_check: <a href="https://forms.gle/zUHrrPo7K34yKaqC9">2023 NetBox Community Survey</a> is now open!</strong>
3-
<p>Please take a few minutes to tell us about your NetBox deployment.</p>
4-
52
<img src="https://raw.githubusercontent.com/netbox-community/netbox/develop/docs/netbox_logo.svg" width="400" alt="NetBox logo" />
63
<p>The premiere source of truth powering network automation</p>
74
<img src="https://github.com/netbox-community/netbox/workflows/CI/badge.svg?branch=master" alt="CI status" />

base_requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ feedparser
8484

8585
# Django wrapper for Graphene (GraphQL support)
8686
# https://github.com/graphql-python/graphene-django/releases
87-
graphene_django
87+
# Pinned to v3.0.0 for GraphiQL UI issue (see #12762)
88+
graphene_django==3.0.0
8889

8990
# WSGI HTTP server
9091
# https://docs.gunicorn.org/en/latest/news.html

docs/models/extras/customfield.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,12 @@ Defines how filters are evaluated against custom field values.
6868

6969
Controls how and whether the custom field is displayed within the NetBox user interface.
7070

71-
| Option | Description |
72-
|------------|--------------------------------------|
73-
| Read/write | Display and permit editing (default) |
74-
| Read-only | Display field but disallow editing |
75-
| Hidden | Do not display field in the UI |
71+
| Option | Description |
72+
|-------------------|--------------------------------------------------|
73+
| Read/write | Display and permit editing (default) |
74+
| Read-only | Display field but disallow editing |
75+
| Hidden | Do not display field in the UI |
76+
| Hidden (if unset) | Display in the UI only when a value has been set |
7677

7778
### Default
7879

docs/release-notes/version-3.5.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,34 @@
11
# NetBox v3.5
22

3+
## v3.5.3 (2023-06-02)
4+
5+
### Enhancements
6+
7+
* [#9876](https://github.com/netbox-community/netbox/issues/9876) - Improve support for matching tags in conditional rules
8+
* [#12015](https://github.com/netbox-community/netbox/issues/12015) - Add device type & role filters for device components
9+
* [#12470](https://github.com/netbox-community/netbox/issues/12470) - Collapse context data by default when viewing a rendered device configuration
10+
* [#12562](https://github.com/netbox-community/netbox/issues/12562) - Record client IP address when logging authentication failures
11+
* [#12597](https://github.com/netbox-community/netbox/issues/12597) - Add an option to hide custom fields only if unset
12+
* [#12599](https://github.com/netbox-community/netbox/issues/12599) - Apply filter parameters to links in object count dashboard widgets
13+
14+
### Bug Fixes
15+
16+
* [#7503](https://github.com/netbox-community/netbox/issues/7503) - Improve rack space validation when creating multiple devices via REST API
17+
* [#11539](https://github.com/netbox-community/netbox/issues/11539) - Fix exception when applying "empty" filter lookup with invalid value
18+
* [#11934](https://github.com/netbox-community/netbox/issues/11934) - Prevent reassignment of an IP address designated as primary for its parent object
19+
* [#12538](https://github.com/netbox-community/netbox/issues/12538) - Redirect user to originating view after editing/deleting an image attachment
20+
* [#12627](https://github.com/netbox-community/netbox/issues/12627) - Restore hover preview for embedded image attachment tables
21+
* [#12694](https://github.com/netbox-community/netbox/issues/12694) - Strip leading & trailing whitespace from custom link URL & text
22+
* [#12702](https://github.com/netbox-community/netbox/issues/12702) - Fix sizing of rear port selection widget on front port template creation form
23+
* [#12715](https://github.com/netbox-community/netbox/issues/12715) - Use contact assignments table to display the contacts assigned to an object
24+
* [#12730](https://github.com/netbox-community/netbox/issues/12730) - Fix extraneous contacts listed in object contact assignments view
25+
* [#12742](https://github.com/netbox-community/netbox/issues/12742) - Object counts dashboard widget should support URL-compatible query filters
26+
* [#12762](https://github.com/netbox-community/netbox/issues/12762) - Fix GraphiQL UI by reverting graphene-django to earlier version
27+
* [#12745](https://github.com/netbox-community/netbox/issues/12745) - Escape display text in API-backed selection widgets
28+
* [#12779](https://github.com/netbox-community/netbox/issues/12779) - Correct arithmetic for converting inches to meters
29+
30+
---
31+
332
## v3.5.2 (2023-05-22)
433

534
### Enhancements

netbox/dcim/api/views.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
from django.http import Http404, HttpResponse
22
from django.shortcuts import get_object_or_404
3-
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter
43
from drf_spectacular.types import OpenApiTypes
4+
from drf_spectacular.utils import extend_schema, OpenApiParameter
55
from rest_framework.decorators import action
66
from rest_framework.renderers import JSONRenderer
77
from rest_framework.response import Response
8-
from rest_framework.status import HTTP_400_BAD_REQUEST
98
from rest_framework.routers import APIRootView
9+
from rest_framework.status import HTTP_400_BAD_REQUEST
1010
from rest_framework.viewsets import ViewSet
1111

1212
from circuits.models import Circuit
1313
from dcim import filtersets
1414
from dcim.constants import CABLE_TRACE_SVG_DEFAULT_WIDTH
1515
from dcim.models import *
1616
from dcim.svg import CableTraceSVG
17-
from extras.api.nested_serializers import NestedConfigTemplateSerializer
1817
from extras.api.mixins import ConfigContextQuerySetMixin, ConfigTemplateRenderMixin
1918
from ipam.models import Prefix, VLAN
2019
from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired
2120
from netbox.api.metadata import ContentTypeMetadata
2221
from netbox.api.pagination import StripCountAnnotationsPaginator
2322
from netbox.api.renderers import TextRenderer
2423
from netbox.api.viewsets import NetBoxModelViewSet
24+
from netbox.api.viewsets.mixins import SequentialBulkCreatesMixin
2525
from netbox.constants import NESTED_SERIALIZER_PREFIX
2626
from utilities.api import get_serializer_for_model
2727
from utilities.utils import count_related
@@ -386,7 +386,12 @@ class PlatformViewSet(NetBoxModelViewSet):
386386
# Devices/modules
387387
#
388388

389-
class DeviceViewSet(ConfigContextQuerySetMixin, ConfigTemplateRenderMixin, NetBoxModelViewSet):
389+
class DeviceViewSet(
390+
SequentialBulkCreatesMixin,
391+
ConfigContextQuerySetMixin,
392+
ConfigTemplateRenderMixin,
393+
NetBoxModelViewSet
394+
):
390395
queryset = Device.objects.prefetch_related(
391396
'device_type__manufacturer', 'device_role', 'tenant', 'platform', 'site', 'location', 'rack', 'parent_bay',
392397
'virtual_chassis__master', 'primary_ip4__nat_outside', 'primary_ip6__nat_outside', 'config_template', 'tags',

netbox/dcim/filtersets.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,28 @@ class DeviceComponentFilterSet(django_filters.FilterSet):
12191219
to_field_name='name',
12201220
label=_('Device (name)'),
12211221
)
1222+
device_type_id = django_filters.ModelMultipleChoiceFilter(
1223+
field_name='device__device_type',
1224+
queryset=DeviceType.objects.all(),
1225+
label=_('Device type (ID)'),
1226+
)
1227+
device_type = django_filters.ModelMultipleChoiceFilter(
1228+
field_name='device__device_type__model',
1229+
queryset=DeviceType.objects.all(),
1230+
to_field_name='model',
1231+
label=_('Device type (model)'),
1232+
)
1233+
device_role_id = django_filters.ModelMultipleChoiceFilter(
1234+
field_name='device__device_role',
1235+
queryset=DeviceRole.objects.all(),
1236+
label=_('Device role (ID)'),
1237+
)
1238+
device_role = django_filters.ModelMultipleChoiceFilter(
1239+
field_name='device__device_role__slug',
1240+
queryset=DeviceRole.objects.all(),
1241+
to_field_name='slug',
1242+
label=_('Device role (slug)'),
1243+
)
12221244
virtual_chassis_id = django_filters.ModelMultipleChoiceFilter(
12231245
field_name='device__virtual_chassis',
12241246
queryset=VirtualChassis.objects.all(),

netbox/dcim/forms/filtersets.py

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,25 @@ class DeviceComponentFilterForm(NetBoxModelFilterSetForm):
102102
required=False,
103103
label=_('Virtual Chassis')
104104
)
105+
device_type_id = DynamicModelMultipleChoiceField(
106+
queryset=DeviceType.objects.all(),
107+
required=False,
108+
label=_('Device type')
109+
)
110+
device_role_id = DynamicModelMultipleChoiceField(
111+
queryset=DeviceRole.objects.all(),
112+
required=False,
113+
label=_('Device role')
114+
)
105115
device_id = DynamicModelMultipleChoiceField(
106116
queryset=Device.objects.all(),
107117
required=False,
108118
query_params={
109119
'site_id': '$site_id',
110120
'location_id': '$location_id',
111-
'virtual_chassis_id': '$virtual_chassis_id'
121+
'virtual_chassis_id': '$virtual_chassis_id',
122+
'device_type_id': '$device_type_id',
123+
'role_id': '$device_role_id'
112124
},
113125
label=_('Device')
114126
)
@@ -1070,7 +1082,8 @@ class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
10701082
fieldsets = (
10711083
(None, ('q', 'filter_id', 'tag')),
10721084
('Attributes', ('name', 'label', 'type', 'speed')),
1073-
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
1085+
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
1086+
('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')),
10741087
('Connection', ('cabled', 'connected', 'occupied')),
10751088
)
10761089
type = forms.MultipleChoiceField(
@@ -1089,7 +1102,8 @@ class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterF
10891102
fieldsets = (
10901103
(None, ('q', 'filter_id', 'tag')),
10911104
('Attributes', ('name', 'label', 'type', 'speed')),
1092-
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
1105+
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
1106+
('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')),
10931107
('Connection', ('cabled', 'connected', 'occupied')),
10941108
)
10951109
type = forms.MultipleChoiceField(
@@ -1108,7 +1122,8 @@ class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
11081122
fieldsets = (
11091123
(None, ('q', 'filter_id', 'tag')),
11101124
('Attributes', ('name', 'label', 'type')),
1111-
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
1125+
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
1126+
('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')),
11121127
('Connection', ('cabled', 'connected', 'occupied')),
11131128
)
11141129
type = forms.MultipleChoiceField(
@@ -1123,7 +1138,8 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
11231138
fieldsets = (
11241139
(None, ('q', 'filter_id', 'tag')),
11251140
('Attributes', ('name', 'label', 'type')),
1126-
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
1141+
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
1142+
('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')),
11271143
('Connection', ('cabled', 'connected', 'occupied')),
11281144
)
11291145
type = forms.MultipleChoiceField(
@@ -1141,8 +1157,8 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
11411157
('Addressing', ('vrf_id', 'l2vpn_id', 'mac_address', 'wwn')),
11421158
('PoE', ('poe_mode', 'poe_type')),
11431159
('Wireless', ('rf_role', 'rf_channel', 'rf_channel_width', 'tx_power')),
1144-
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id',
1145-
'device_id', 'vdc_id')),
1160+
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
1161+
('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id', 'vdc_id')),
11461162
('Connection', ('cabled', 'connected', 'occupied')),
11471163
)
11481164
vdc_id = DynamicModelMultipleChoiceField(
@@ -1242,7 +1258,8 @@ class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
12421258
fieldsets = (
12431259
(None, ('q', 'filter_id', 'tag')),
12441260
('Attributes', ('name', 'label', 'type', 'color')),
1245-
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
1261+
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
1262+
('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')),
12461263
('Cable', ('cabled', 'occupied')),
12471264
)
12481265
model = FrontPort
@@ -1261,7 +1278,8 @@ class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
12611278
fieldsets = (
12621279
(None, ('q', 'filter_id', 'tag')),
12631280
('Attributes', ('name', 'label', 'type', 'color')),
1264-
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
1281+
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
1282+
('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')),
12651283
('Cable', ('cabled', 'occupied')),
12661284
)
12671285
type = forms.MultipleChoiceField(
@@ -1279,7 +1297,8 @@ class ModuleBayFilterForm(DeviceComponentFilterForm):
12791297
fieldsets = (
12801298
(None, ('q', 'filter_id', 'tag')),
12811299
('Attributes', ('name', 'label', 'position')),
1282-
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
1300+
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
1301+
('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')),
12831302
)
12841303
tag = TagFilterField(model)
12851304
position = forms.CharField(
@@ -1292,7 +1311,8 @@ class DeviceBayFilterForm(DeviceComponentFilterForm):
12921311
fieldsets = (
12931312
(None, ('q', 'filter_id', 'tag')),
12941313
('Attributes', ('name', 'label')),
1295-
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
1314+
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
1315+
('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')),
12961316
)
12971317
tag = TagFilterField(model)
12981318

@@ -1302,7 +1322,8 @@ class InventoryItemFilterForm(DeviceComponentFilterForm):
13021322
fieldsets = (
13031323
(None, ('q', 'filter_id', 'tag')),
13041324
('Attributes', ('name', 'label', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered')),
1305-
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
1325+
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
1326+
('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')),
13061327
)
13071328
role_id = DynamicModelMultipleChoiceField(
13081329
queryset=InventoryItemRole.objects.all(),

0 commit comments

Comments
 (0)