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

Add cable paths API detail view for pass-through ports

Jeremy Stretch 5 лет назад
Родитель
Сommit
aa0ee2720b
2 измененных файлов с 63 добавлено и 4 удалено
  1. 46 1
      netbox/dcim/api/serializers.py
  2. 17 3
      netbox/dcim/api/views.py

+ 46 - 1
netbox/dcim/api/serializers.py

@@ -7,12 +7,13 @@ from rest_framework.validators import UniqueTogetherValidator
 from dcim.choices import *
 from dcim.constants import *
 from dcim.models import (
-    Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
+    Cable, CablePath, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
     DeviceBayTemplate, DeviceType, DeviceRole, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
     Manufacturer, InventoryItem, Platform, PowerFeed, PowerOutlet, PowerOutletTemplate, PowerPanel, PowerPort,
     PowerPortTemplate, Rack, RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site,
     VirtualChassis,
 )
+from dcim.utils import decompile_path_node
 from extras.api.customfields import CustomFieldModelSerializer
 from extras.api.serializers import TaggedObjectSerializer
 from ipam.api.nested_serializers import NestedIPAddressSerializer, NestedVLANSerializer
@@ -734,6 +735,50 @@ class TracedCableSerializer(serializers.ModelSerializer):
         ]
 
 
+class CablePathSerializer(serializers.ModelSerializer):
+    origin_type = ContentTypeField(read_only=True)
+    origin = serializers.SerializerMethodField(read_only=True)
+    destination_type = ContentTypeField(read_only=True)
+    destination = serializers.SerializerMethodField(read_only=True)
+    path = serializers.SerializerMethodField(read_only=True)
+
+    class Meta:
+        model = CablePath
+        fields = [
+            'id', 'origin_type', 'origin', 'destination_type', 'destination', 'path', 'is_active',
+        ]
+
+    @swagger_serializer_method(serializer_or_field=serializers.DictField)
+    def get_origin(self, obj):
+        """
+        Return the appropriate serializer for the origin.
+        """
+        serializer = get_serializer_for_model(obj.origin, prefix='Nested')
+        context = {'request': self.context['request']}
+        return serializer(obj.origin, context=context).data
+
+    @swagger_serializer_method(serializer_or_field=serializers.DictField)
+    def get_destination(self, obj):
+        """
+        Return the appropriate serializer for the destination, if any.
+        """
+        if obj.destination_id is not None:
+            serializer = get_serializer_for_model(obj.destination, prefix='Nested')
+            context = {'request': self.context['request']}
+            return serializer(obj.destination, context=context).data
+        return None
+
+    @swagger_serializer_method(serializer_or_field=serializers.ListField)
+    def get_path(self, obj):
+        ret = []
+        for node in obj.path:
+            ct_id, object_id = decompile_path_node(node)
+            ct = ContentType.objects.get_for_id(ct_id)
+            # TODO: Return the object URL
+            ret.append(f'{ct.app_label}.{ct.model}:{object_id}')
+        return ret
+
+
 #
 # Interface connections
 #

+ 17 - 3
netbox/dcim/api/views.py

@@ -17,7 +17,7 @@ from rest_framework.viewsets import GenericViewSet, ViewSet
 from circuits.models import Circuit
 from dcim import filters
 from dcim.models import (
-    Cable, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
+    Cable, CablePath, ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay,
     DeviceBayTemplate, DeviceRole, DeviceType, FrontPort, FrontPortTemplate, Interface, InterfaceTemplate,
     Manufacturer, InventoryItem, Platform, PowerFeed, PowerOutlet, PowerOutletTemplate, PowerPanel, PowerPort,
     PowerPortTemplate, Rack, RackGroup, RackReservation, RackRole, RearPort, RearPortTemplate, Region, Site,
@@ -77,6 +77,20 @@ class PathEndpointMixin(object):
         return Response(path)
 
 
+class PassThroughPortMixin(object):
+
+    @action(detail=True, url_path='paths')
+    def paths(self, request, pk):
+        """
+        Return all CablePaths which traverse a given pass-through port.
+        """
+        obj = get_object_or_404(self.queryset, pk=pk)
+        cablepaths = CablePath.objects.filter(path__contains=obj).prefetch_related('origin', 'destination')
+        serializer = serializers.CablePathSerializer(cablepaths, context={'request': request}, many=True)
+
+        return Response(serializer.data)
+
+
 #
 # Regions
 #
@@ -503,13 +517,13 @@ class InterfaceViewSet(PathEndpointMixin, ModelViewSet):
     filterset_class = filters.InterfaceFilterSet
 
 
-class FrontPortViewSet(ModelViewSet):
+class FrontPortViewSet(PassThroughPortMixin, 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(PassThroughPortMixin, ModelViewSet):
     queryset = RearPort.objects.prefetch_related('device__device_type__manufacturer', 'cable', 'tags')
     serializer_class = serializers.RearPortSerializer
     filterset_class = filters.RearPortFilterSet