Просмотр исходного кода

Closes #23031: Add 8C1P, 12C1P, and 24C1P trunk cable profiles

Introduce trunk profiles with eight, twelve, and twenty-four single-position
connectors at each end, for multi-strand fiber cables spliced to individual
pigtails within patch panels. Add the profile choices, register the profile
classes, and test link peer resolution for each.
Jeremy Stretch 6 дней назад
Родитель
Сommit
a42007f0a2

+ 24 - 0
netbox/dcim/cable_profiles.py

@@ -332,6 +332,20 @@ class Trunk4C8PCableProfile(BaseCableProfile):
     b_connectors = a_connectors
 
 
+class Trunk8C1PCableProfile(BaseCableProfile):
+    a_connectors = {
+        1: 1,
+        2: 1,
+        3: 1,
+        4: 1,
+        5: 1,
+        6: 1,
+        7: 1,
+        8: 1,
+    }
+    b_connectors = a_connectors
+
+
 class Trunk8C4PCableProfile(BaseCableProfile):
     a_connectors = {
         1: 4,
@@ -346,6 +360,16 @@ class Trunk8C4PCableProfile(BaseCableProfile):
     b_connectors = a_connectors
 
 
+class Trunk12C1PCableProfile(BaseCableProfile):
+    a_connectors = dict.fromkeys(range(1, 13), 1)
+    b_connectors = a_connectors
+
+
+class Trunk24C1PCableProfile(BaseCableProfile):
+    a_connectors = dict.fromkeys(range(1, 25), 1)
+    b_connectors = a_connectors
+
+
 class Breakout1C2Px2C1PCableProfile(BaseCableProfile):
     a_connectors = {
         1: 2,

+ 6 - 0
netbox/dcim/choices.py

@@ -1850,7 +1850,10 @@ class CableProfileChoices(ChoiceSet):
     TRUNK_4C4P_SHUFFLE = 'trunk-4c4p-shuffle'
     TRUNK_4C6P = 'trunk-4c6p'
     TRUNK_4C8P = 'trunk-4c8p'
+    TRUNK_8C1P = 'trunk-8c1p'
     TRUNK_8C4P = 'trunk-8c4p'
+    TRUNK_12C1P = 'trunk-12c1p'
+    TRUNK_24C1P = 'trunk-24c1p'
     # Breakouts
     BREAKOUT_1C2P_2C1P = 'breakout-1c2p-2c1p'
     BREAKOUT_1C4P_4C1P = 'breakout-1c4p-4c1p'
@@ -1887,7 +1890,10 @@ class CableProfileChoices(ChoiceSet):
                 Choice(TRUNK_4C4P_SHUFFLE, _('4C4P trunk (shuffle)')),
                 Choice(TRUNK_4C6P, _('4C6P trunk')),
                 Choice(TRUNK_4C8P, _('4C8P trunk')),
+                Choice(TRUNK_8C1P, _('8C1P trunk')),
                 Choice(TRUNK_8C4P, _('8C4P trunk')),
+                Choice(TRUNK_12C1P, _('12C1P trunk')),
+                Choice(TRUNK_24C1P, _('24C1P trunk')),
             ),
         ),
         (

+ 3 - 0
netbox/dcim/models/cables.py

@@ -224,7 +224,10 @@ class Cable(PrimaryModel):
             CableProfileChoices.TRUNK_4C4P_SHUFFLE: cable_profiles.Trunk4C4PShuffleCableProfile,
             CableProfileChoices.TRUNK_4C6P: cable_profiles.Trunk4C6PCableProfile,
             CableProfileChoices.TRUNK_4C8P: cable_profiles.Trunk4C8PCableProfile,
+            CableProfileChoices.TRUNK_8C1P: cable_profiles.Trunk8C1PCableProfile,
             CableProfileChoices.TRUNK_8C4P: cable_profiles.Trunk8C4PCableProfile,
+            CableProfileChoices.TRUNK_12C1P: cable_profiles.Trunk12C1PCableProfile,
+            CableProfileChoices.TRUNK_24C1P: cable_profiles.Trunk24C1PCableProfile,
             CableProfileChoices.BREAKOUT_1C2P_2C1P: cable_profiles.Breakout1C2Px2C1PCableProfile,
             CableProfileChoices.BREAKOUT_1C4P_4C1P: cable_profiles.Breakout1C4Px4C1PCableProfile,
             CableProfileChoices.BREAKOUT_1C6P_6C1P: cable_profiles.Breakout1C6Px6C1PCableProfile,

+ 30 - 0
netbox/dcim/tests/test_cable_profiles.py

@@ -43,6 +43,36 @@ class CableProfileLinkPeerTestCase(BaseCablePathTestCase):
             self.assertEqual(interface.link_peers, [rear_port])
             self.assertEqual(rear_port.link_peers, [interface])
 
+    def test_trunk_xc1p_link_peers(self):
+        """
+        Link peers for the 8C1P, 12C1P, and 24C1P trunk profiles should map each A connector to its B counterpart.
+        """
+        for profile, count in (
+            (CableProfileChoices.TRUNK_8C1P, 8),
+            (CableProfileChoices.TRUNK_12C1P, 12),
+            (CableProfileChoices.TRUNK_24C1P, 24),
+        ):
+            with self.subTest(profile=profile):
+                a_ports = [
+                    RearPort.objects.create(device=self.device, name=f'{profile} A{i}', positions=1)
+                    for i in range(1, count + 1)
+                ]
+                b_ports = [
+                    RearPort.objects.create(device=self.device, name=f'{profile} B{i}', positions=1)
+                    for i in range(1, count + 1)
+                ]
+
+                cable = Cable(profile=profile, a_terminations=a_ports, b_terminations=b_ports)
+                cable.clean()
+                cable.save()
+
+                for a_port, b_port in zip(a_ports, b_ports):
+                    a_port.refresh_from_db()
+                    b_port.refresh_from_db()
+
+                    self.assertEqual(a_port.link_peers, [b_port])
+                    self.assertEqual(b_port.link_peers, [a_port])
+
     @tag('regression')  # #21917
     def test_breakout_shuffle_link_peers(self):
         """