From a65be7708165a01078263f9f2c0c5e4d7b548c1f Mon Sep 17 00:00:00 2001 From: Scott Baker Date: Sun, 11 Jan 2015 13:45:19 -0800 Subject: [PATCH] sliceplus support for site_allocation and network_ports for tenant view --- planetstack/core/xoslib/methods/plus.py | 53 ++++++++++++++++++++ planetstack/core/xoslib/methods/sliceplus.py | 17 +++++-- planetstack/core/xoslib/objects/sliceplus.py | 8 +++ 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/planetstack/core/xoslib/methods/plus.py b/planetstack/core/xoslib/methods/plus.py index 9ace688..ca89c79 100644 --- a/planetstack/core/xoslib/methods/plus.py +++ b/planetstack/core/xoslib/methods/plus.py @@ -1,4 +1,7 @@ +from rest_framework import generics from rest_framework import serializers +from rest_framework.response import Response +from rest_framework import status """ PlusSerializerMixin @@ -22,3 +25,53 @@ class PlusSerializerMixin(): def getBackendHtml(self, obj): return obj.getBackendHtml() +# XXX this is taken from genapi.py +# XXX find a better way to re-use the code +class PlusRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView): + + # To handle fine-grained field permissions, we have to check can_update + # the object has been updated but before it has been saved. + + def update(self, request, *args, **kwargs): + partial = kwargs.pop('partial', False) + self.object = self.get_object_or_none() + + serializer = self.get_serializer(self.object, data=request.DATA, + files=request.FILES, partial=partial) + + if not serializer.is_valid(): + response = {"error": "validation", + "specific_error": "not serializer.is_valid()", + "reasons": serializer.errors} + return Response(response, status=status.HTTP_400_BAD_REQUEST) + + try: + self.pre_save(serializer.object) + except ValidationError as err: + # full_clean on model instance may be called in pre_save, + # so we have to handle eventual errors. + response = {"error": "validation", + "specific_error": "ValidationError in pre_save", + "reasons": err.message_dict} + return Response(response, status=status.HTTP_400_BAD_REQUEST) + + if serializer.object is not None: + if not serializer.object.can_update(request.user): + return Response(status=status.HTTP_400_BAD_REQUEST) + + if self.object is None: + self.object = serializer.save(force_insert=True) + self.post_save(self.object, created=True) + return Response(serializer.data, status=status.HTTP_201_CREATED) + + self.object = serializer.save(force_update=True) + self.post_save(self.object, created=False) + return Response(serializer.data, status=status.HTTP_200_OK) + + def destroy(self, request, *args, **kwargs): + obj = self.get_object() + if obj.can_update(request.user): + return super(generics.RetrieveUpdateDestroyAPIView, self).destroy(request, *args, **kwargs) + else: + return Response(status=status.HTTP_400_BAD_REQUEST) + diff --git a/planetstack/core/xoslib/methods/sliceplus.py b/planetstack/core/xoslib/methods/sliceplus.py index 25e4d1e..f29e200 100644 --- a/planetstack/core/xoslib/methods/sliceplus.py +++ b/planetstack/core/xoslib/methods/sliceplus.py @@ -6,7 +6,7 @@ from rest_framework import generics from core.models import * from django.forms import widgets from core.xoslib.objects.sliceplus import SlicePlus -from plus import PlusSerializerMixin +from plus import PlusSerializerMixin, PlusRetrieveUpdateDestroyAPIView if hasattr(serializers, "ReadOnlyField"): # rest_framework 3.x @@ -22,12 +22,20 @@ class NetworkPortsField(serializers.WritableField): # note: maybe just Field i def to_internal_value(self, data): return data +class SiteAllocationField(serializers.WritableField): # note: maybe just Field in rest_framework 3.x instead of WritableField + def to_representation(self, obj): + return json.dumps(obj) + + def to_internal_value(self, data): + return json.loads(data) + class SlicePlusIdSerializer(serializers.ModelSerializer, PlusSerializerMixin): id = IdField() sliceInfo = serializers.SerializerMethodField("getSliceInfo") humanReadableName = serializers.SerializerMethodField("getHumanReadableName") - network_ports = NetworkPortsField() + network_ports = NetworkPortsField(required=False) + site_allocation = SiteAllocationField(required=False) def getSliceInfo(self, slice): return slice.getSliceInfo(user=self.context['request'].user) @@ -40,7 +48,8 @@ class SlicePlusIdSerializer(serializers.ModelSerializer, PlusSerializerMixin): class Meta: model = SlicePlus - fields = ('humanReadableName', 'id','created','updated','enacted','name','enabled','omf_friendly','description','slice_url','site','max_slivers','image_preference','service','network','mount_data_sets','serviceClass','creator','networks','sliceInfo','network_ports','backendIcon','backendHtml') + fields = ('humanReadableName', 'id','created','updated','enacted','name','enabled','omf_friendly','description','slice_url','site','max_slivers','image_preference','service','network','mount_data_sets', + 'serviceClass','creator','networks','sliceInfo','network_ports','backendIcon','backendHtml','site_allocation') class SlicePlusList(generics.ListCreateAPIView): queryset = SlicePlus.objects.select_related().all() @@ -60,7 +69,7 @@ class SlicePlusList(generics.ListCreateAPIView): else: return Response(status=status.HTTP_400_BAD_REQUEST) -class SlicePlusDetail(generics.RetrieveUpdateDestroyAPIView): +class SlicePlusDetail(PlusRetrieveUpdateDestroyAPIView): queryset = SlicePlus.objects.select_related().all() serializer_class = SlicePlusIdSerializer diff --git a/planetstack/core/xoslib/objects/sliceplus.py b/planetstack/core/xoslib/objects/sliceplus.py index efb6b2a..7ec8e27 100644 --- a/planetstack/core/xoslib/objects/sliceplus.py +++ b/planetstack/core/xoslib/objects/sliceplus.py @@ -26,6 +26,14 @@ class SlicePlus(Slice, PlusObjectMixin): "siteCount": len(used_sites.keys()), "roles": roles} + @property + def site_allocation(self): + return self.getSliceInfo()["sitesUsed"] + + @site_allocation.setter + def site_allocation(self, value): + print "XXX set sitesUsed to", value + @property def network_ports(self): # XXX this assumes there is only one network that can have ports bound -- 2.43.0