mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-24 17:38:37 -06:00
Fixes #4211: Include trailing text when naturalizing interface names
This commit is contained in:
parent
b38eeaebc9
commit
322b328584
@ -1,5 +1,12 @@
|
|||||||
# v2.7.7 (FUTURE)
|
# v2.7.7 (FUTURE)
|
||||||
|
|
||||||
|
**Note:** This release fixes a bug affecting the natural ordering of interfaces. If any interfaces appear unordered in
|
||||||
|
NetBox, run the following management command to recalculate their naturalized values after upgrading:
|
||||||
|
|
||||||
|
```
|
||||||
|
python3 manage.py renaturalize dcim.Interface
|
||||||
|
```
|
||||||
|
|
||||||
## Enhancements
|
## Enhancements
|
||||||
|
|
||||||
* [#2511](https://github.com/netbox-community/netbox/issues/2511) - Compare object change to the previous change
|
* [#2511](https://github.com/netbox-community/netbox/issues/2511) - Compare object change to the previous change
|
||||||
@ -19,6 +26,7 @@
|
|||||||
* [#4196](https://github.com/netbox-community/netbox/issues/4196) - Fix exception when viewing LLDP neighbors page
|
* [#4196](https://github.com/netbox-community/netbox/issues/4196) - Fix exception when viewing LLDP neighbors page
|
||||||
* [#4202](https://github.com/netbox-community/netbox/issues/4202) - Prevent reassignment to master device when bulk editing VC member interfaces
|
* [#4202](https://github.com/netbox-community/netbox/issues/4202) - Prevent reassignment to master device when bulk editing VC member interfaces
|
||||||
* [#4204](https://github.com/netbox-community/netbox/issues/4204) - Fix assignment of mask length when bulk editing prefixes
|
* [#4204](https://github.com/netbox-community/netbox/issues/4204) - Fix assignment of mask length when bulk editing prefixes
|
||||||
|
* [#4211](https://github.com/netbox-community/netbox/issues/4211) - Include trailing text when naturalizing interface names
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -7,7 +7,8 @@ INTERFACE_NAME_REGEX = r'(^(?P<type>[^\d\.:]+)?)' \
|
|||||||
r'((?P<subposition>\d+)/)?' \
|
r'((?P<subposition>\d+)/)?' \
|
||||||
r'((?P<id>\d+))?' \
|
r'((?P<id>\d+))?' \
|
||||||
r'(:(?P<channel>\d+))?' \
|
r'(:(?P<channel>\d+))?' \
|
||||||
r'(.(?P<vc>\d+)$)?'
|
r'(\.(?P<vc>\d+))?' \
|
||||||
|
r'(?P<remainder>.*)$'
|
||||||
|
|
||||||
|
|
||||||
def naturalize(value, max_length, integer_places=8):
|
def naturalize(value, max_length, integer_places=8):
|
||||||
@ -50,7 +51,7 @@ def naturalize_interface(value, max_length):
|
|||||||
:param value: The value to be naturalized
|
:param value: The value to be naturalized
|
||||||
:param max_length: The maximum length of the returned string. Characters beyond this length will be stripped.
|
:param max_length: The maximum length of the returned string. Characters beyond this length will be stripped.
|
||||||
"""
|
"""
|
||||||
output = []
|
output = ''
|
||||||
match = re.search(INTERFACE_NAME_REGEX, value)
|
match = re.search(INTERFACE_NAME_REGEX, value)
|
||||||
if match is None:
|
if match is None:
|
||||||
return value
|
return value
|
||||||
@ -60,21 +61,25 @@ def naturalize_interface(value, max_length):
|
|||||||
for part_name in ('slot', 'subslot', 'position', 'subposition'):
|
for part_name in ('slot', 'subslot', 'position', 'subposition'):
|
||||||
part = match.group(part_name)
|
part = match.group(part_name)
|
||||||
if part is not None:
|
if part is not None:
|
||||||
output.append(part.rjust(4, '0'))
|
output += part.rjust(4, '0')
|
||||||
else:
|
else:
|
||||||
output.append('9999')
|
output += '9999'
|
||||||
|
|
||||||
# Append the type, if any.
|
# Append the type, if any.
|
||||||
if match.group('type') is not None:
|
if match.group('type') is not None:
|
||||||
output.append(match.group('type'))
|
output += match.group('type')
|
||||||
|
|
||||||
# Finally, append any remaining fields, left-padding to six digits each.
|
# Append any remaining fields, left-padding to six digits each.
|
||||||
for part_name in ('id', 'channel', 'vc'):
|
for part_name in ('id', 'channel', 'vc'):
|
||||||
part = match.group(part_name)
|
part = match.group(part_name)
|
||||||
if part is not None:
|
if part is not None:
|
||||||
output.append(part.rjust(6, '0'))
|
output += part.rjust(6, '0')
|
||||||
else:
|
else:
|
||||||
output.append('000000')
|
output += '000000'
|
||||||
|
|
||||||
ret = ''.join(output)
|
# Finally, naturalize any remaining text and append it
|
||||||
return ret[:max_length]
|
if match.group('remainder') is not None and len(output) < max_length:
|
||||||
|
remainder = naturalize(match.group('remainder'), max_length - len(output))
|
||||||
|
output += remainder
|
||||||
|
|
||||||
|
return output[:max_length]
|
||||||
|
@ -9,8 +9,8 @@ class NaturalizationTestCase(TestCase):
|
|||||||
"""
|
"""
|
||||||
def test_naturalize(self):
|
def test_naturalize(self):
|
||||||
|
|
||||||
|
# Original, naturalized
|
||||||
data = (
|
data = (
|
||||||
# Original, naturalized
|
|
||||||
('abc', 'abc'),
|
('abc', 'abc'),
|
||||||
('123', '00000123'),
|
('123', '00000123'),
|
||||||
('abc123', 'abc00000123'),
|
('abc123', 'abc00000123'),
|
||||||
@ -21,15 +21,16 @@ class NaturalizationTestCase(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
for origin, naturalized in data:
|
for origin, naturalized in data:
|
||||||
self.assertEqual(naturalize(origin, max_length=50), naturalized)
|
self.assertEqual(naturalize(origin, max_length=100), naturalized)
|
||||||
|
|
||||||
def test_naturalize_max_length(self):
|
def test_naturalize_max_length(self):
|
||||||
self.assertEqual(naturalize('abc123def456', max_length=10), 'abc0000012')
|
self.assertEqual(naturalize('abc123def456', max_length=10), 'abc0000012')
|
||||||
|
|
||||||
def test_naturalize_interface(self):
|
def test_naturalize_interface(self):
|
||||||
|
|
||||||
|
# Original, naturalized
|
||||||
data = (
|
data = (
|
||||||
# Original, naturalized
|
# IOS/JunOS-style
|
||||||
('Gi', '9999999999999999Gi000000000000000000'),
|
('Gi', '9999999999999999Gi000000000000000000'),
|
||||||
('Gi1', '9999999999999999Gi000001000000000000'),
|
('Gi1', '9999999999999999Gi000001000000000000'),
|
||||||
('Gi1/2', '0001999999999999Gi000002000000000000'),
|
('Gi1/2', '0001999999999999Gi000002000000000000'),
|
||||||
@ -40,10 +41,16 @@ class NaturalizationTestCase(TestCase):
|
|||||||
('Gi1/2/3/4/5:6.7', '0001000200030004Gi000005000006000007'),
|
('Gi1/2/3/4/5:6.7', '0001000200030004Gi000005000006000007'),
|
||||||
('Gi1:2', '9999999999999999Gi000001000002000000'),
|
('Gi1:2', '9999999999999999Gi000001000002000000'),
|
||||||
('Gi1:2.3', '9999999999999999Gi000001000002000003'),
|
('Gi1:2.3', '9999999999999999Gi000001000002000003'),
|
||||||
|
# Generic
|
||||||
|
('Interface 1', '9999999999999999Interface 000001000000000000'),
|
||||||
|
('Interface 1 (other)', '9999999999999999Interface 000001000000000000 (other)'),
|
||||||
|
('Interface 99', '9999999999999999Interface 000099000000000000'),
|
||||||
|
('PCIe1-p1', '9999999999999999PCIe000001000000000000-p00000001'),
|
||||||
|
('PCIe1-p99', '9999999999999999PCIe000001000000000000-p00000099'),
|
||||||
)
|
)
|
||||||
|
|
||||||
for origin, naturalized in data:
|
for origin, naturalized in data:
|
||||||
self.assertEqual(naturalize_interface(origin, max_length=50), naturalized)
|
self.assertEqual(naturalize_interface(origin, max_length=100), naturalized)
|
||||||
|
|
||||||
def test_naturalize_interface_max_length(self):
|
def test_naturalize_interface_max_length(self):
|
||||||
self.assertEqual(naturalize_interface('Gi1/2/3', max_length=20), '0001000299999999Gi00')
|
self.assertEqual(naturalize_interface('Gi1/2/3', max_length=20), '0001000299999999Gi00')
|
||||||
|
Loading…
Reference in New Issue
Block a user