diff --git a/docs/release-notes/version-2.8.md b/docs/release-notes/version-2.8.md index a1756be7b..348a6fa36 100644 --- a/docs/release-notes/version-2.8.md +++ b/docs/release-notes/version-2.8.md @@ -12,6 +12,7 @@ * [#4702](https://github.com/netbox-community/netbox/issues/4702) - Catch IntegrityError exception when adding a non-unique secret * [#4707](https://github.com/netbox-community/netbox/issues/4707) - Fix `prefix_count` population on VLAN API serializer * [#4725](https://github.com/netbox-community/netbox/issues/4725) - Fix "brief" rendering of various REST API endpoints +* [#4736](https://github.com/netbox-community/netbox/issues/4736) - Add cable trace endpoints for pass-through ports --- diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 9c8fe12de..f70193903 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -502,13 +502,13 @@ class InterfaceViewSet(CableTraceMixin, ModelViewSet): return Response(serializer.data) -class FrontPortViewSet(ModelViewSet): +class FrontPortViewSet(CableTraceMixin, ModelViewSet): queryset = FrontPort.objects.prefetch_related('device__device_type__manufacturer', 'rear_port', 'cable', 'tags') serializer_class = serializers.FrontPortSerializer filterset_class = filters.FrontPortFilterSet -class RearPortViewSet(ModelViewSet): +class RearPortViewSet(CableTraceMixin, ModelViewSet): queryset = RearPort.objects.prefetch_related('device__device_type__manufacturer', 'cable', 'tags') serializer_class = serializers.RearPortSerializer filterset_class = filters.RearPortFilterSet diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index b2d348843..4af82170a 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -1336,6 +1336,34 @@ class FrontPortTest(APIViewTestCases.APIViewTestCase): }, ] + def test_trace_frontport(self): + """ + Test tracing a FrontPort cable. + """ + frontport = FrontPort.objects.first() + peer_device = Device.objects.create( + site=Site.objects.first(), + device_type=DeviceType.objects.first(), + device_role=DeviceRole.objects.first(), + name='Peer Device' + ) + interface = Interface.objects.create( + device=peer_device, + name='Interface X' + ) + cable = Cable(termination_a=frontport, termination_b=interface, label='Cable 1') + cable.save() + + url = reverse('dcim-api:frontport-trace', kwargs={'pk': frontport.pk}) + response = self.client.get(url, **self.header) + + self.assertHttpStatus(response, status.HTTP_200_OK) + self.assertEqual(len(response.data), 1) + segment1 = response.data[0] + self.assertEqual(segment1[0]['name'], frontport.name) + self.assertEqual(segment1[1]['label'], cable.label) + self.assertEqual(segment1[2]['name'], interface.name) + class RearPortTest(APIViewTestCases.APIViewTestCase): model = RearPort @@ -1374,6 +1402,34 @@ class RearPortTest(APIViewTestCases.APIViewTestCase): }, ] + def test_trace_rearport(self): + """ + Test tracing a RearPort cable. + """ + rearport = RearPort.objects.first() + peer_device = Device.objects.create( + site=Site.objects.first(), + device_type=DeviceType.objects.first(), + device_role=DeviceRole.objects.first(), + name='Peer Device' + ) + interface = Interface.objects.create( + device=peer_device, + name='Interface X' + ) + cable = Cable(termination_a=rearport, termination_b=interface, label='Cable 1') + cable.save() + + url = reverse('dcim-api:rearport-trace', kwargs={'pk': rearport.pk}) + response = self.client.get(url, **self.header) + + self.assertHttpStatus(response, status.HTTP_200_OK) + self.assertEqual(len(response.data), 1) + segment1 = response.data[0] + self.assertEqual(segment1[0]['name'], rearport.name) + self.assertEqual(segment1[1]['label'], cable.label) + self.assertEqual(segment1[2]['name'], interface.name) + class DeviceBayTest(APIViewTestCases.APIViewTestCase): model = DeviceBay