Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v3.6.5 #14238

Merged
merged 30 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7efbfab
PRVB
jeremystretch Oct 17, 2023
2a0a7d4
Add GitHub issue template for translations
jeremystretch Oct 18, 2023
809b049
YAML fix
jeremystretch Oct 18, 2023
5b2f294
Tweak translation issue form
jeremystretch Oct 18, 2023
b3fb393
14033 raise validation error if A and B term go to same object (#14050)
arthanson Nov 1, 2023
22e474f
Update attr in conditions example
kenny-y-dev Nov 1, 2023
66b9cdf
adds import button on the contact assignment table #13669
abhi1693 Nov 8, 2023
60e9832
adds inventory items to interface #13723
abhi1693 Nov 8, 2023
b0f2de5
order available columns #14219
abhi1693 Nov 8, 2023
94858ac
adds parent to inventory item table #14113
abhi1693 Nov 8, 2023
6e8ee9d
review changes #14113
abhi1693 Nov 8, 2023
ac4b46b
adds site column to power feeds #13743
abhi1693 Nov 8, 2023
d2c727c
review changes #13743
abhi1693 Nov 8, 2023
1203d76
Adds mask length filters on ipaddress (#14218)
abhi1693 Nov 9, 2023
0603dd1
Adds inventory item children view (#14217)
abhi1693 Nov 9, 2023
dfef89a
Fix ordering on JobTable. #14223
cpmills1975 Nov 9, 2023
95519b4
Adds device and vm to service filter form (#14215)
abhi1693 Nov 9, 2023
5000564
Changelog for #13669, #13723, #13743, #13951, #14033, #14101, #14112,…
jeremystretch Nov 9, 2023
6900097
Fixes #14117: Validate the number of front ports to be created
jeremystretch Nov 1, 2023
092f2b0
Enhance Virtual Machine and Device Platform Filter with Manufacturer …
kprince28 Nov 9, 2023
6b89da2
Closes #13936: Add primary_ip4 and primary_ip6 filters to VirtualMach…
miaow2 Nov 9, 2023
e5c38e0
Closes #13022: Add IP assignment support when bulk importing services…
jeremystretch Nov 9, 2023
57bf2a2
fix asn view under asn range #14195
abhi1693 Nov 9, 2023
ad95760
adds contact group on contact assignment table #14221
abhi1693 Nov 9, 2023
217a9ed
handles the port in the ip #14085
abhi1693 Nov 9, 2023
dd5e20a
allow login and logout in maintenance mode #14166
abhi1693 Nov 9, 2023
e1bedb8
restores config revision during cache clear #14182
abhi1693 Nov 9, 2023
5c27d29
Adds unit to the power port draw (#14208)
abhi1693 Nov 9, 2023
351aaf8
Changelog for #12741, #13022, #13587, #13936, #14085, #14117, #14166,…
jeremystretch Nov 9, 2023
41eae1b
Release v3.6.5
jeremystretch Nov 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ body:
attributes:
label: NetBox version
description: What version of NetBox are you currently running?
placeholder: v3.6.4
placeholder: v3.6.5
validations:
required: true
- type: dropdown
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ body:
attributes:
label: NetBox version
description: What version of NetBox are you currently running?
placeholder: v3.6.4
placeholder: v3.6.5
validations:
required: true
- type: dropdown
Expand Down
37 changes: 37 additions & 0 deletions .github/ISSUE_TEMPLATE/translation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
name: 🌍 Translation
description: Request support for a new language in the user interface
labels: ["type: translation"]
body:
- type: markdown
attributes:
value: >
**NOTE:** This template is used only for proposing the addition of *new* languages. Please do
not use it to request changes to existing translations.
- type: input
attributes:
label: Language
description: What is the name of the language in English?
validations:
required: true
- type: input
attributes:
label: ISO 639-1 code
description: >
What is the two-letter [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)
assigned to the language?
validations:
required: true
- type: dropdown
attributes:
label: Volunteer
description: Are you a fluent speaker of this language **and** willing to contribute a translation map?
options:
- "Yes"
- "No"
validations:
required: true
- type: textarea
attributes:
label: Comments
description: Any other notes you would like to share
3 changes: 2 additions & 1 deletion base_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ django-tables2

# User-defined tags for objects
# https://github.com/jazzband/django-taggit/blob/master/CHANGELOG.rst
django-taggit
# TODO: Upgrade to v5.0 for NetBox v3.7 beta
django-taggit<5.0

# A Django field for representing time zones
# https://github.com/mfogel/django-timezone-field/
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/conditions.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ Multiple conditions can be combined into nested sets using AND or OR logic. This
]
},
{
"attr": "tags",
"attr": "tags.slug",
"value": "exempt",
"op": "contains"
}
Expand Down
30 changes: 30 additions & 0 deletions docs/release-notes/version-3.6.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
# NetBox v3.6

## v3.6.5 (2023-11-09)

### Enhancements

* [#12741](https://github.com/netbox-community/netbox/issues/12741) - Add selector widget to platform field on device & virtual machine forms
* [#13022](https://github.com/netbox-community/netbox/issues/13022) - Introduce support for assigning IP addresses when bulk importing services
* [#13587](https://github.com/netbox-community/netbox/issues/13587) - Annotate units of measurement on power port table columns
* [#13669](https://github.com/netbox-community/netbox/issues/13669) - Add bulk import button to contact assignments list view
* [#13723](https://github.com/netbox-community/netbox/issues/13723) - Add inventory items column to interfaces table
* [#13743](https://github.com/netbox-community/netbox/issues/13743) - Add site column to power feeds table
* [#13936](https://github.com/netbox-community/netbox/issues/13936) - Add primary IPv4 and IPv6 filters for virtual machines and VDCs
* [#13951](https://github.com/netbox-community/netbox/issues/13951) - Add device & virtual machine fields to service filter form
* [#14085](https://github.com/netbox-community/netbox/issues/14085) - Strip trailing port number from value returned by `get_client_ip()`
* [#14101](https://github.com/netbox-community/netbox/issues/14101) - Add greater/less than mask length filters for IP addresses
* [#14112](https://github.com/netbox-community/netbox/issues/14112) - Add tab listing child items under inventory item view
* [#14113](https://github.com/netbox-community/netbox/issues/14113) - Add optional parent column to inventory items table
* [#14220](https://github.com/netbox-community/netbox/issues/14220) - Order available columns alphabetically in table configuration form
* [#14221](https://github.com/netbox-community/netbox/issues/14221) - Add contact group column on contact assignments table

### Bug Fixes

* [#14033](https://github.com/netbox-community/netbox/issues/14033) - Avoid exception when attempting to connect both ends of a cable to the same object
* [#14117](https://github.com/netbox-community/netbox/issues/14117) - Check that enough rear port positions have been selected to accommodate the number of front ports being created
* [#14166](https://github.com/netbox-community/netbox/issues/14166) - Permit user login when maintenance mode is enabled
* [#14182](https://github.com/netbox-community/netbox/issues/14182) - Ensure the active configuration is restored upon clearing cache
* [#14195](https://github.com/netbox-community/netbox/issues/14195) - Correct permissions evaluation for ASN range child ASNs view
* [#14223](https://github.com/netbox-community/netbox/issues/14223) - Disable ordering of jobs by assigned object

---

## v3.6.4 (2023-10-17)

### Enhancements
Expand Down
9 changes: 9 additions & 0 deletions netbox/core/management/commands/clearcache.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
from django.core.cache import cache
from django.core.management.base import BaseCommand

from extras.models import ConfigRevision


class Command(BaseCommand):
"""Command to clear the entire cache."""
help = 'Clears the cache.'

def handle(self, *args, **kwargs):
# Fetch the current config revision from the cache
config_version = cache.get('config_version')
# Clear the cache
cache.clear()
self.stdout.write('Cache has been cleared.', ending="\n")
if config_version:
# Activate the current config revision
ConfigRevision.objects.get(id=config_version).activate()
self.stdout.write(f'Config revision ({config_version}) has been restored.', ending="\n")
3 changes: 2 additions & 1 deletion netbox/core/tables/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class JobTable(NetBoxTable):
)
object = tables.Column(
verbose_name=_('Object'),
linkify=True
linkify=True,
orderable=False
)
status = columns.ChoiceFieldColumn(
verbose_name=_('Status'),
Expand Down
21 changes: 9 additions & 12 deletions netbox/dcim/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from extras.filtersets import LocalConfigContextFilterSet
from extras.models import ConfigTemplate
from ipam.filtersets import PrimaryIPFilterSet
from ipam.models import ASN, L2VPN, IPAddress, VRF
from netbox.filtersets import (
BaseFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet,
Expand Down Expand Up @@ -817,7 +818,13 @@ class Meta:
fields = ['id', 'name', 'slug', 'description']


class DeviceFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet, LocalConfigContextFilterSet):
class DeviceFilterSet(
NetBoxModelFilterSet,
TenancyFilterSet,
ContactModelFilterSet,
LocalConfigContextFilterSet,
PrimaryIPFilterSet,
):
manufacturer_id = django_filters.ModelMultipleChoiceFilter(
field_name='device_type__manufacturer',
queryset=Manufacturer.objects.all(),
Expand Down Expand Up @@ -993,16 +1000,6 @@ class DeviceFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilter
method='_device_bays',
label=_('Has device bays'),
)
primary_ip4_id = django_filters.ModelMultipleChoiceFilter(
field_name='primary_ip4',
queryset=IPAddress.objects.all(),
label=_('Primary IPv4 (ID)'),
)
primary_ip6_id = django_filters.ModelMultipleChoiceFilter(
field_name='primary_ip6',
queryset=IPAddress.objects.all(),
label=_('Primary IPv6 (ID)'),
)
oob_ip_id = django_filters.ModelMultipleChoiceFilter(
field_name='oob_ip',
queryset=IPAddress.objects.all(),
Expand Down Expand Up @@ -1069,7 +1066,7 @@ def _device_bays(self, queryset, name, value):
return queryset.exclude(devicebays__isnull=value)


class VirtualDeviceContextFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
class VirtualDeviceContextFilterSet(NetBoxModelFilterSet, TenancyFilterSet, PrimaryIPFilterSet):
device_id = django_filters.ModelMultipleChoiceFilter(
field_name='device',
queryset=Device.objects.all(),
Expand Down
3 changes: 2 additions & 1 deletion netbox/dcim/forms/model_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,8 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
platform = DynamicModelChoiceField(
label=_('Platform'),
queryset=Platform.objects.all(),
required=False
required=False,
selector=True
)
cluster = DynamicModelChoiceField(
label=_('Cluster'),
Expand Down
33 changes: 33 additions & 0 deletions netbox/dcim/forms/object_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,23 @@ def __init__(self, *args, **kwargs):
)
self.fields['rear_port'].choices = choices

def clean(self):

# Check that the number of FrontPortTemplates to be created matches the selected number of RearPortTemplate
# positions
frontport_count = len(self.cleaned_data['name'])
rearport_count = len(self.cleaned_data['rear_port'])
if frontport_count != rearport_count:
raise forms.ValidationError({
'rear_port': _(
"The number of front port templates to be created ({frontport_count}) must match the selected "
"number of rear port positions ({rearport_count})."
).format(
frontport_count=frontport_count,
rearport_count=rearport_count
)
})

def get_iterative_data(self, iteration):

# Assign rear port and position from selected set
Expand Down Expand Up @@ -291,6 +308,22 @@ def __init__(self, *args, **kwargs):
)
self.fields['rear_port'].choices = choices

def clean(self):

# Check that the number of FrontPorts to be created matches the selected number of RearPort positions
frontport_count = len(self.cleaned_data['name'])
rearport_count = len(self.cleaned_data['rear_port'])
if frontport_count != rearport_count:
raise forms.ValidationError({
'rear_port': _(
"The number of front ports to be created ({frontport_count}) must match the selected number of "
"rear port positions ({rearport_count})."
).format(
frontport_count=frontport_count,
rearport_count=rearport_count
)
})

def get_iterative_data(self, iteration):

# Assign rear port and position from selected set
Expand Down
11 changes: 11 additions & 0 deletions netbox/dcim/models/cables.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,17 @@ def clean(self):
if b_type not in COMPATIBLE_TERMINATION_TYPES.get(a_type):
raise ValidationError(f"Incompatible termination types: {a_type} and {b_type}")

if a_type == b_type:
# can't directly use self.a_terminations here as possible they
# don't have pk yet
a_pks = set(obj.pk for obj in self.a_terminations if obj.pk)
b_pks = set(obj.pk for obj in self.b_terminations if obj.pk)

if (a_pks & b_pks):
raise ValidationError(
_("A and B terminations cannot connect to the same object.")
)

# Run clean() on any new CableTerminations
for termination in self.a_terminations:
CableTermination(cable=self, cable_end='A', termination=termination).clean()
Expand Down
18 changes: 16 additions & 2 deletions netbox/dcim/tables/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,12 @@ class PowerPortTable(ModularDeviceComponentTable, PathEndpointTable):
'args': [Accessor('device_id')],
}
)
maximum_draw = tables.Column(
verbose_name=_('Maximum draw (W)')
)
allocated_draw = tables.Column(
verbose_name=_('Allocated draw (W)')
)
tags = columns.TagColumn(
url_name='dcim:powerport_list'
)
Expand Down Expand Up @@ -625,6 +631,10 @@ class InterfaceTable(ModularDeviceComponentTable, BaseInterfaceTable, PathEndpoi
verbose_name=_('VRF'),
linkify=True
)
inventory_items = tables.ManyToManyColumn(
linkify_item=True,
verbose_name=_('Inventory Items'),
)
tags = columns.TagColumn(
url_name='dcim:interface_list'
)
Expand All @@ -636,7 +646,7 @@ class Meta(DeviceComponentTable.Meta):
'speed', 'speed_formatted', 'duplex', 'mode', 'mac_address', 'wwn', 'poe_mode', 'poe_type', 'rf_role', 'rf_channel',
'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'description', 'mark_connected', 'cable',
'cable_color', 'wireless_link', 'wireless_lans', 'link_peer', 'connection', 'tags', 'vdcs', 'vrf', 'l2vpn',
'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'created', 'last_updated',
'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'inventory_items', 'created', 'last_updated',
)
default_columns = ('pk', 'name', 'device', 'label', 'enabled', 'type', 'description')

Expand Down Expand Up @@ -933,6 +943,10 @@ class InventoryItemTable(DeviceComponentTable):
discovered = columns.BooleanColumn(
verbose_name=_('Discovered'),
)
parent = tables.Column(
linkify=True,
verbose_name=_('Parent'),
)
tags = columns.TagColumn(
url_name='dcim:inventoryitem_list'
)
Expand All @@ -941,7 +955,7 @@ class InventoryItemTable(DeviceComponentTable):
class Meta(NetBoxTable.Meta):
model = models.InventoryItem
fields = (
'pk', 'id', 'name', 'device', 'component', 'label', 'role', 'manufacturer', 'part_id', 'serial',
'pk', 'id', 'name', 'device', 'parent', 'component', 'label', 'role', 'manufacturer', 'part_id', 'serial',
'asset_tag', 'description', 'discovered', 'tags', 'created', 'last_updated',
)
default_columns = (
Expand Down
11 changes: 8 additions & 3 deletions netbox/dcim/tables/power.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ class PowerFeedTable(TenancyColumnsMixin, CableTerminationTable):
linkify=True,
verbose_name=_('Tenant')
)
site = tables.Column(
accessor='rack__site',
linkify=True,
verbose_name=_('Site'),
)
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
Expand All @@ -97,9 +102,9 @@ class PowerFeedTable(TenancyColumnsMixin, CableTerminationTable):
class Meta(NetBoxTable.Meta):
model = PowerFeed
fields = (
'pk', 'id', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase',
'max_utilization', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'available_power', 'tenant',
'tenant_group', 'description', 'comments', 'tags', 'created', 'last_updated',
'pk', 'id', 'name', 'power_panel', 'site', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage',
'phase', 'max_utilization', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'available_power',
'tenant', 'tenant_group', 'description', 'comments', 'tags', 'created', 'last_updated',
)
default_columns = (
'pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase', 'cable',
Expand Down
20 changes: 20 additions & 0 deletions netbox/dcim/tests/test_filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -4712,12 +4712,18 @@ def setUpTestData(cls):
addresses = (
IPAddress(assigned_object=interfaces[0], address='10.1.1.1/24'),
IPAddress(assigned_object=interfaces[1], address='10.1.1.2/24'),
IPAddress(assigned_object=None, address='10.1.1.3/24'),
IPAddress(assigned_object=interfaces[0], address='2001:db8::1/64'),
IPAddress(assigned_object=interfaces[1], address='2001:db8::2/64'),
IPAddress(assigned_object=None, address='2001:db8::3/64'),
)
IPAddress.objects.bulk_create(addresses)

vdcs[0].primary_ip4 = addresses[0]
vdcs[0].primary_ip6 = addresses[3]
vdcs[0].save()
vdcs[1].primary_ip4 = addresses[1]
vdcs[1].primary_ip6 = addresses[4]
vdcs[1].save()

def test_device(self):
Expand All @@ -4738,3 +4744,17 @@ def test_has_primary_ip(self):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'has_primary_ip': False}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)

def test_primary_ip4(self):
addresses = IPAddress.objects.filter(address__family=4)
params = {'primary_ip4_id': [addresses[0].pk, addresses[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'primary_ip4_id': [addresses[2].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)

def test_primary_ip6(self):
addresses = IPAddress.objects.filter(address__family=6)
params = {'primary_ip6_id': [addresses[0].pk, addresses[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'primary_ip6_id': [addresses[2].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
Loading