mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-11 22:32:17 -06:00
Add profile for 4x4 MPO8 shuffle cable
This commit is contained in:
@@ -44,7 +44,12 @@ class BaseCableProfile:
|
||||
)
|
||||
})
|
||||
|
||||
def get_mapped_position(self, position):
|
||||
def get_mapped_position(self, side, position):
|
||||
"""
|
||||
Return the mapped position for a given cable end and position.
|
||||
|
||||
By default, assume all positions are symmetrical.
|
||||
"""
|
||||
return position
|
||||
|
||||
def get_peer_terminations(self, terminations, position_stack):
|
||||
@@ -65,7 +70,7 @@ class BaseCableProfile:
|
||||
cable_end=terminations[0].opposite_cable_end
|
||||
)
|
||||
if position is not None:
|
||||
qs = qs.filter(position=self.get_mapped_position(position))
|
||||
qs = qs.filter(position=self.get_mapped_position(local_end, position))
|
||||
return qs
|
||||
|
||||
|
||||
@@ -93,11 +98,11 @@ class BToManyCableProfile(BaseCableProfile):
|
||||
b_side_numbered = False
|
||||
|
||||
|
||||
class Shuffle2x2MPOCableProfile(BaseCableProfile):
|
||||
class Shuffle2x2MPO8CableProfile(BaseCableProfile):
|
||||
a_max_connections = 8
|
||||
b_max_connections = 8
|
||||
|
||||
def get_mapped_position(self, position):
|
||||
def get_mapped_position(self, side, position):
|
||||
return {
|
||||
1: 1,
|
||||
2: 2,
|
||||
@@ -108,3 +113,26 @@ class Shuffle2x2MPOCableProfile(BaseCableProfile):
|
||||
7: 7,
|
||||
8: 8,
|
||||
}.get(position)
|
||||
|
||||
|
||||
class Shuffle4x4MPO8CableProfile(BaseCableProfile):
|
||||
a_max_connections = 8
|
||||
b_max_connections = 8
|
||||
# A side to B side position mapping
|
||||
_a_mapping = {
|
||||
1: 1,
|
||||
2: 3,
|
||||
3: 5,
|
||||
4: 7,
|
||||
5: 2,
|
||||
6: 4,
|
||||
7: 6,
|
||||
8: 8,
|
||||
}
|
||||
# B side to A side position mapping
|
||||
_b_mapping = {v: k for k, v in _a_mapping.items()}
|
||||
|
||||
def get_mapped_position(self, side, position):
|
||||
if side.lower() == 'b':
|
||||
return self._b_mapping.get(position)
|
||||
return self._a_mapping.get(position)
|
||||
|
||||
@@ -1722,7 +1722,8 @@ class CableProfileChoices(ChoiceSet):
|
||||
STRAIGHT_MULTI = 'straight-multi'
|
||||
A_TO_MANY = 'a-to-many'
|
||||
B_TO_MANY = 'b-to-many'
|
||||
SHUFFLE_2X2_MPO = 'shuffle-2x2-mpo'
|
||||
SHUFFLE_2X2_MPO8 = 'shuffle-2x2-mpo8'
|
||||
SHUFFLE_4X4_MPO8 = 'shuffle-4x4-mpo8'
|
||||
|
||||
CHOICES = (
|
||||
(STRAIGHT_SINGLE, _('Straight (single position)')),
|
||||
@@ -1730,7 +1731,8 @@ class CableProfileChoices(ChoiceSet):
|
||||
# TODO: Better names for many-to-one profiles?
|
||||
(A_TO_MANY, _('A to many')),
|
||||
(B_TO_MANY, _('B to many')),
|
||||
(SHUFFLE_2X2_MPO, _('Shuffle (2x2 MPO)')),
|
||||
(SHUFFLE_2X2_MPO8, _('Shuffle (2x2 MPO8)')),
|
||||
(SHUFFLE_4X4_MPO8, _('Shuffle (4x4 MPO8)')),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -138,7 +138,8 @@ class Cable(PrimaryModel):
|
||||
CableProfileChoices.STRAIGHT_MULTI: cable_profiles.StraightMultiCableProfile,
|
||||
CableProfileChoices.A_TO_MANY: cable_profiles.AToManyCableProfile,
|
||||
CableProfileChoices.B_TO_MANY: cable_profiles.BToManyCableProfile,
|
||||
CableProfileChoices.SHUFFLE_2X2_MPO: cable_profiles.Shuffle2x2MPOCableProfile,
|
||||
CableProfileChoices.SHUFFLE_2X2_MPO8: cable_profiles.Shuffle2x2MPO8CableProfile,
|
||||
CableProfileChoices.SHUFFLE_4X4_MPO8: cable_profiles.Shuffle4x4MPO8CableProfile,
|
||||
}.get(self.profile)
|
||||
|
||||
def _get_x_terminations(self, side):
|
||||
|
||||
@@ -262,7 +262,7 @@ class CablePathTests(CablePathTestCase):
|
||||
# Check that all CablePaths have been deleted
|
||||
self.assertEqual(CablePath.objects.count(), 0)
|
||||
|
||||
def test_105_cable_profile_2x2_mpo(self):
|
||||
def test_105_cable_profile_2x2_mpo8(self):
|
||||
"""
|
||||
[IF1:1] --C1-- [IF3:1]
|
||||
[IF1:2] [IF3:2]
|
||||
@@ -273,9 +273,10 @@ class CablePathTests(CablePathTestCase):
|
||||
[IF2:3] [IF4:3]
|
||||
[IF2:4] [IF4:4]
|
||||
|
||||
Cable profile: Shuffle (2x2 MPO)
|
||||
Cable profile: Shuffle (2x2 MPO8)
|
||||
"""
|
||||
interfaces = [
|
||||
# A side
|
||||
Interface.objects.create(device=self.device, name='Interface 1:1'),
|
||||
Interface.objects.create(device=self.device, name='Interface 1:2'),
|
||||
Interface.objects.create(device=self.device, name='Interface 1:3'),
|
||||
@@ -284,6 +285,7 @@ class CablePathTests(CablePathTestCase):
|
||||
Interface.objects.create(device=self.device, name='Interface 2:2'),
|
||||
Interface.objects.create(device=self.device, name='Interface 2:3'),
|
||||
Interface.objects.create(device=self.device, name='Interface 2:4'),
|
||||
# B side
|
||||
Interface.objects.create(device=self.device, name='Interface 3:1'),
|
||||
Interface.objects.create(device=self.device, name='Interface 3:2'),
|
||||
Interface.objects.create(device=self.device, name='Interface 3:3'),
|
||||
@@ -296,7 +298,7 @@ class CablePathTests(CablePathTestCase):
|
||||
|
||||
# Create cable 1
|
||||
cable1 = Cable(
|
||||
profile=CableProfileChoices.SHUFFLE_2X2_MPO,
|
||||
profile=CableProfileChoices.SHUFFLE_2X2_MPO8,
|
||||
a_terminations=interfaces[0:8],
|
||||
b_terminations=interfaces[8:16],
|
||||
)
|
||||
@@ -372,6 +374,118 @@ class CablePathTests(CablePathTestCase):
|
||||
# Check that all CablePaths have been deleted
|
||||
self.assertEqual(CablePath.objects.count(), 0)
|
||||
|
||||
def test_106_cable_profile_4x4_mpo8(self):
|
||||
"""
|
||||
[IF1:1] --C1-- [IF3:1]
|
||||
[IF1:2] [IF3:2]
|
||||
[IF1:3] [IF3:3]
|
||||
[IF1:4] [IF3:4]
|
||||
[IF2:1] [IF4:1]
|
||||
[IF2:2] [IF4:2]
|
||||
[IF2:3] [IF4:3]
|
||||
[IF2:4] [IF4:4]
|
||||
|
||||
Cable profile: Shuffle (4x4 MPO8)
|
||||
"""
|
||||
interfaces = [
|
||||
# A side
|
||||
Interface.objects.create(device=self.device, name='Interface 1:1'),
|
||||
Interface.objects.create(device=self.device, name='Interface 1:2'),
|
||||
Interface.objects.create(device=self.device, name='Interface 2:1'),
|
||||
Interface.objects.create(device=self.device, name='Interface 2:2'),
|
||||
Interface.objects.create(device=self.device, name='Interface 3:1'),
|
||||
Interface.objects.create(device=self.device, name='Interface 3:2'),
|
||||
Interface.objects.create(device=self.device, name='Interface 4:1'),
|
||||
Interface.objects.create(device=self.device, name='Interface 4:2'),
|
||||
# B side
|
||||
Interface.objects.create(device=self.device, name='Interface 5:1'),
|
||||
Interface.objects.create(device=self.device, name='Interface 5:2'),
|
||||
Interface.objects.create(device=self.device, name='Interface 6:1'),
|
||||
Interface.objects.create(device=self.device, name='Interface 6:2'),
|
||||
Interface.objects.create(device=self.device, name='Interface 7:1'),
|
||||
Interface.objects.create(device=self.device, name='Interface 7:2'),
|
||||
Interface.objects.create(device=self.device, name='Interface 8:1'),
|
||||
Interface.objects.create(device=self.device, name='Interface 8:2'),
|
||||
]
|
||||
|
||||
# Create cable 1
|
||||
cable1 = Cable(
|
||||
profile=CableProfileChoices.SHUFFLE_4X4_MPO8,
|
||||
a_terminations=interfaces[0:8],
|
||||
b_terminations=interfaces[8:16],
|
||||
)
|
||||
cable1.clean()
|
||||
cable1.save()
|
||||
|
||||
paths = [
|
||||
# A-to-B paths
|
||||
self.assertPathExists(
|
||||
(interfaces[0], cable1, interfaces[8]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[1], cable1, interfaces[10]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[2], cable1, interfaces[12]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[3], cable1, interfaces[14]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[4], cable1, interfaces[9]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[5], cable1, interfaces[11]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[6], cable1, interfaces[13]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[7], cable1, interfaces[15]), is_complete=True, is_active=True
|
||||
),
|
||||
# B-to-A paths
|
||||
self.assertPathExists(
|
||||
(interfaces[8], cable1, interfaces[0]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[9], cable1, interfaces[4]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[10], cable1, interfaces[1]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[11], cable1, interfaces[5]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[12], cable1, interfaces[2]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[13], cable1, interfaces[6]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[14], cable1, interfaces[3]), is_complete=True, is_active=True
|
||||
),
|
||||
self.assertPathExists(
|
||||
(interfaces[15], cable1, interfaces[7]), is_complete=True, is_active=True
|
||||
),
|
||||
]
|
||||
self.assertEqual(CablePath.objects.count(), len(paths))
|
||||
|
||||
for i, (interface, path) in enumerate(zip(interfaces, paths)):
|
||||
interface.refresh_from_db()
|
||||
self.assertPathIsSet(interface, path)
|
||||
self.assertEqual(interface.cable_end, 'A' if i < 8 else 'B')
|
||||
self.assertEqual(interface.cable_position, (i % 8) + 1)
|
||||
|
||||
# Test SVG generation
|
||||
CableTraceSVG(interfaces[0]).render()
|
||||
|
||||
# Delete cable 1
|
||||
cable1.delete()
|
||||
|
||||
# Check that all CablePaths have been deleted
|
||||
self.assertEqual(CablePath.objects.count(), 0)
|
||||
|
||||
def test_202_single_path_via_pass_through_with_breakouts(self):
|
||||
"""
|
||||
[IF1] --C1-- [FP1] [RP1] --C2-- [IF3]
|
||||
|
||||
Reference in New Issue
Block a user