Support for ELAN, ETREE, and VNoD Global Service

Change-Id: Iea1ee5b5b9224404a16bc9b88bc082719f75d10f
diff --git a/xos/api/service/metronetworkservice/metronetworkservice.py b/xos/api/service/metronetworkservice/metronetworkservice.py
index 8e200ce..764205d 100644
--- a/xos/api/service/metronetworkservice/metronetworkservice.py
+++ b/xos/api/service/metronetworkservice/metronetworkservice.py
@@ -1,7 +1,11 @@
+from django.http import HttpResponseBadRequest
 from rest_framework.response import Response
+from rest_framework.views import APIView
 from rest_framework import serializers, filters, status
 from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
 from services.metronetwork.models import *
+from random import randint
+import json
 from django.core.exceptions import ObjectDoesNotExist
 from django.core import serializers as jsonserializer
 
@@ -18,7 +22,7 @@
                       'operationalState')
 
         def getHumanReadableName(self, obj):
-            return obj.__unicode__()
+            return obj.name
 
 class MetroNetworkSystemViewSet(XOSViewSet):
     base_name = "metronetworksystem"
@@ -143,7 +147,8 @@
         ELineConnection.sid = validated_data.data.get('sid')
         ELineConnection.adminstate = validated_data.data.get('adminstate')
         ELineConnection.operstate = validated_data.data.get('operstate')
-        ELineConnection.type = validated_data.data.get('type')
+        ELineConnection.sid = validated_data.data.get('sid')
+        ELineConnection.type = 'Point_To_Point'
 
         uni1 = validated_data.data.get('uni1')
         uni2 = validated_data.data.get('uni2')
@@ -244,7 +249,8 @@
         ETreeConnection.sid = validated_data.data.get('sid')
         ETreeConnection.adminstate = validated_data.data.get('adminstate')
         ETreeConnection.operstate = validated_data.data.get('operstate')
-        ETreeConnection.type = validated_data.data.get('type')
+        ETreeConnection.sid = validated_data.data.get('sid')
+        ETreeConnection.type = 'Root_Multipoint'
 
         root_id = validated_data.data.get('root')
         eps_list = validated_data.data.get('eps')
@@ -349,7 +355,8 @@
         ELanConnection.sid = validated_data.data.get('sid')
         ELanConnection.adminstate = validated_data.data.get('adminstate')
         ELanConnection.operstate = validated_data.data.get('operstate')
-        ELanConnection.type = validated_data.data.get('type')
+        ELanConnection.sid = validated_data.data.get('sid')
+        ELanConnection.type = 'Multipoint_To_Multipoint'
 
         eps_list = validated_data.data.get('eps')
         ELanConnection.save()
@@ -381,3 +388,455 @@
         response_data['eps'] = eps_data
 
         return Response(response_data)
+
+############################
+
+class BandwidthProfileSerializer(PlusModelSerializer):
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+
+    class Meta:
+        model = BandwidthProfile
+
+        fields = ('humanReadableName',
+                  'id',
+                  'bwpcfgcbs',
+                  'bwpcfgebs',
+                  'bwpcfgcir',
+                  'bwpcfgeir',
+                  'name'
+                  )
+
+    def getHumanReadableName(self, obj):
+        return obj.name
+
+class BandwidthProfileViewSet(XOSViewSet):
+    base_name = "BANDWIDTH_PROFILE"
+    method_name = "BANDWIDTH_PROFILE"
+    method_kind = "viewset"
+    queryset = BandwidthProfile.objects.all()
+    serializer_class = BandwidthProfileSerializer
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(BandwidthProfileViewSet, self).get_urlpatterns(api_path=api_path)
+
+        return patterns
+
+    def list(self, request):
+
+        object_list = self.filter_queryset(self.get_queryset())
+
+        serializer = self.get_serializer(object_list, many=True)
+
+        return Response(serializer.data)
+
+    def create(self, validated_data):
+
+        bandwidthProfile = BandwidthProfile()
+        bandwidthProfile.name = validated_data.data.get('name')
+        bandwidthProfile.bwpcfgcbs = validated_data.data.get('bwpcfgcbs')
+        bandwidthProfile.bwpcfgebs = validated_data.data.get('bwpcfgebs')
+        bandwidthProfile.bwpcfgcir = validated_data.data.get('bwpcfgcir')
+        bandwidthProfile.bwpcfgeir = validated_data.data.get('bwpcfgeir')
+
+        bandwidthProfile.save()
+
+        response_data = {}
+        response_data['name'] = bandwidthProfile.name
+        response_data['bwpcfgcbs'] = bandwidthProfile.bwpcfgcbs
+        response_data['bwpcfgebs'] = bandwidthProfile.bwpcfgebs
+        response_data['bwpcfgcir'] = bandwidthProfile.bwpcfgeir
+        response_data['bwpcfgcir'] = bandwidthProfile.bwpcfgcir
+        response_data['id'] = bandwidthProfile.id
+
+        return Response(response_data)
+
+class VnodSiteSerializer(PlusModelSerializer):
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+
+    class Meta:
+        model = Site
+
+        fields = ('humanReadableName',
+                  'site_url',
+                  'enabled',
+                  'longitude',
+                  'latitude',
+                  'name'
+                  )
+
+    def getHumanReadableName(self, obj):
+        return obj.name
+
+class RemotePortSerializer(PlusModelSerializer):
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    edgeport = NetworkEdgePortSerializer(read_only=True)
+    remoteportsite = VnodSiteSerializer(read_only=True)
+
+    class Meta:
+        model = RemotePort
+
+        fields = ('humanReadableName',
+                  'name',
+                  'edgeport',
+                  'id',
+                  'remoteportsite'
+                  )
+
+    def getHumanReadableName(self, obj):
+        return obj.name
+
+class ServiceSpokeSerializer(PlusModelSerializer):
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    vnodlocalsite = VnodSiteSerializer(read_only=True)
+    vnodlocalport = RemotePortSerializer(read_only=True)
+
+    class Meta:
+        model = ServiceSpoke
+
+        fields = ('humanReadableName',
+                  'id',
+                  'name',
+                  'remotesubscriber',
+                  'remotevnodid',
+                  'autoattached',
+                  'operstate',
+                  'vnodlocalsite',
+                  'vnodlocalport'
+                  )
+
+    def getHumanReadableName(self, obj):
+        return obj.name
+
+class VnodGlobalServiceSerializer(PlusModelSerializer):
+    humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+    metronetworkroottomultipoint = NetworkEdgeToMultipointConnectionSerializer(read_only=True)
+    metronetworkmultipoint = NetworkMultipointToMultipointConnectionSerializer(read_only=True)
+    metronetworkpointtopoint = NetworkEdgeToEdgePointConnectionSerializer(read_only=True)
+    spokes = ServiceSpokeSerializer(read_only=True, many=True)
+    bandwidthProfile = BandwidthProfileSerializer(read_only=True)
+
+    class Meta:
+        model = VnodGlobalService
+
+        fields = ('humanReadableName',
+                  'servicehandle',
+                  'vlanid',
+                  'id',
+                  'type',
+                  'operstate',
+                  'adminstate',
+                  'metronetworkroottomultipoint',
+                  'metronetworkmultipoint',
+                  'metronetworkpointtopoint',
+                  'spokes',
+                  'bandwidthProfile',
+                  'name'
+                  )
+
+    def getHumanReadableName(self, obj):
+        return obj.name
+
+class VnodGlobalServiceViewSet(XOSViewSet):
+    base_name = "VNOD_GLOBAL_SERVICE"
+    method_name = "VNOD_GLOBAL_SERVICE"
+    method_kind = "viewset"
+    queryset = VnodGlobalService.get_service_objects().all()
+    serializer_class = VnodGlobalServiceSerializer
+
+    @classmethod
+    def get_urlpatterns(self, api_path="^"):
+        patterns = super(VnodGlobalServiceViewSet, self).get_urlpatterns(api_path=api_path)
+
+        return patterns
+
+    def list(self, request):
+
+        object_list = self.filter_queryset(self.get_queryset())
+
+        serializer = self.get_serializer(object_list, many=True)
+
+        return Response(serializer.data)
+
+    def destroy(self, request, pk=None):
+        VnodGlobalServiceToDelete = VnodGlobalService.objects.get(pk=pk)
+
+        if (VnodGlobalServiceToDelete):
+            VnodGlobalServiceToDelete.adminstate = 'deactivationrequested'
+            VnodGlobalServiceToDelete.save()
+        else:
+            return Response(status=status.HTTP_400_BAD_REQUEST)
+
+        return Response(status=status.HTTP_200_OK)
+
+    def create(self, validated_data):
+
+        vnodGlobalService = VnodGlobalService()
+
+        vnodGlobalService.name = validated_data.data.get('name')
+
+        if VnodGlobalService.objects.filter(
+                name=vnodGlobalService.name).exists():
+            return HttpResponseBadRequest('Error: VnodGlobalService name \'' +  vnodGlobalService.name
+                            + '\' already exists.')
+
+        vnodGlobalService.servicehandle = validated_data.data.get('servicehandle')
+        vnodGlobalService.adminstate = 'enabled'
+        vnodGlobalService.operstate = 'inactive'
+        vnodGlobalService.type = validated_data.data.get('type')
+
+        vnodGlobalService.vlanid = self.getUniqueVlandId()
+
+        bandwidth_profile = validated_data.data.get('bandwidthProfile')
+        bandwidthprofile = BandwidthProfile.objects.get(pk=bandwidth_profile['id'])
+        if (bandwidth_profile):
+            vnodGlobalService.bandwidthProfile = bandwidthprofile
+
+        vnodGlobalService.save()
+
+        spokes_list = validated_data.data.get('spokes')
+        if (spokes_list is None):
+            vnodGlobalService.delete()
+            return HttpResponseBadRequest('Error: No spokes found in request.')
+
+        for spoke in spokes_list:
+            vnodlocalsite = Site.objects.get(pk=spoke['vnodlocalsite']['id'])
+            servicespoke = ServiceSpoke()
+            servicespoke.vnodlocalsite = vnodlocalsite
+            servicespoke.vnodlocalport = self.getRandomRemotePort(vnodlocalsite)
+            servicespoke.name = spoke['name']
+            if (spoke.get('autoattached')):
+                servicespoke.autoattached = spoke['autoattached']
+            servicespoke.operstate = 'inactive'
+            servicespoke.adminstate = 'disabled'
+            servicespoke.save()
+            vnodGlobalService.spokes.add(servicespoke)
+
+        serializer = self.get_serializer(vnodGlobalService)
+        return Response(serializer.data)
+
+    def getUniqueVlandId(self):
+        unique = False
+        while not unique:
+            vlanid = randint(1, 4095)
+            vnodglobalservice = VnodGlobalService.get_service_objects().filter(vlanid=vlanid)
+            if (not vnodglobalservice):
+                unique = True
+        return vlanid
+
+    def getRandomRemotePort(self, site):
+        remotePort = RemotePort.objects.get(remoteportsite__name=site.name)
+        if (remotePort):
+            return remotePort
+        return None
+
+    @classmethod
+    def calculateVnodGlobalOperState(self, servicehandle):
+        vnodglobalservice = VnodGlobalService.get_service_objects().filter(servicehandle=servicehandle)
+        if (not vnodglobalservice):
+            HttpResponseBadRequest('Error: Could not find VnodGlobalObject with servicehandle=' + servicehandle)
+
+        vnodglobalservice = vnodglobalservice[0]
+        all_spokes_active_and_enabled = True
+
+        for spoke in vnodglobalservice.spokes.all():
+            if (spoke.operstate != 'active' or spoke.adminstate != 'enabled'):
+                all_spokes_active_and_enabled = False
+                break;
+
+        if (all_spokes_active_and_enabled):
+            vnodglobalservice.operstate = 'active'
+        else:
+            vnodglobalservice.operstate = 'inactive'
+
+        vnodglobalservice.save()
+        return all_spokes_active_and_enabled
+
+    @classmethod
+    def createService(self, servicehandle):
+        vnodglobalservice = VnodGlobalService.get_service_objects().filter(servicehandle=servicehandle)
+        if (not vnodglobalservice):
+            HttpResponseBadRequest('Error: Could not find VnodGlobalObject with servicehandle=' + servicehandle)
+
+        vnodglobalservice = vnodglobalservice[0]
+        if (vnodglobalservice.type == 'eline'):
+
+            spokes = vnodglobalservice.spokes.all()
+            uni1 = spokes[0].vnodlocalport.edgeport
+            uni2 = spokes[1].vnodlocalport.edgeport
+            name = 'ELine-' + str(vnodglobalservice.id)
+            type = 'Point_To_Point'
+            operstate = 'active'
+            adminstate = 'activationrequested'
+
+            eline = NetworkEdgeToEdgePointConnection()
+            eline.name = name
+            eline.type = type
+            eline.operstate = operstate
+            eline.adminstate = adminstate
+            eline.vlanid = vnodglobalservice.vlanid
+            eline.sid = name
+            eline.uni1 = NetworkEdgePort.objects.get(pid=uni1.pid)
+            eline.uni2 = NetworkEdgePort.objects.get(pid=uni2.pid)
+
+            eline.save()
+            vnodglobalservice.metronetworkpointtopoint = eline
+            vnodglobalservice.save()
+
+        elif (vnodglobalservice.type == 'elan'):
+
+            spokes = vnodglobalservice.spokes.all()
+
+            name = 'ELAN-' + str(vnodglobalservice.id)
+            type = 'Multipoint_To_Multipoint'
+            operstate = 'active'
+            adminstate = 'activationrequested'
+
+            elan = NetworkMultipointToMultipointConnection()
+            elan.name = name
+            elan.type = type
+            elan.operstate = 'inactive'
+            elan.adminstate = 'disabled'
+            elan.vlanid = vnodglobalservice.vlanid
+            elan.save()
+
+            for spoke in spokes:
+                uni = NetworkEdgePort.objects.get(pid=spoke.vnodlocalport.edgeport.pid)
+                elan.eps.add(uni)
+
+            elan.operstate = operstate
+            elan.adminstate = adminstate
+            elan.save()
+
+            vnodglobalservice.metronetworkmultipoint = elan
+            vnodglobalservice.save()
+
+        # TODO: elif (vnodglobalservice.type == 'etree'):
+
+class VnodGlobalServiceAutoAttachmentView(APIView):
+    method_kind = "list"
+    method_name = "vnodglobal_api_autoattach"
+
+    def get(self, request, format=None):
+        params = request.query_params
+        sitename = params.get('sitename')
+
+        if ( sitename is None):
+            HttpResponseBadRequest("Error: Request requires] 'sitename' as a query param.")
+
+        vnodglobalservices = VnodGlobalService.get_service_objects().filter(spokes__autoattached=True,
+                                                                            spokes__operstate='inactive',
+                                                                            spokes__vnodlocalsite__name=sitename)
+
+        if (not vnodglobalservices):
+            HttpResponseBadRequest({"handles" : []})
+
+        handles = []
+        for vnodglobalservice in vnodglobalservices:
+            if (vnodglobalservice.adminstate != 'disabled'):
+                handles.append(vnodglobalservice.servicehandle)
+
+        response_data = {'servicehandles' : handles}
+        return Response(response_data)
+
+class VnodGlobalServiceConfigurationView(APIView):
+    method_kind = "list"
+    method_name = "vnodglobal_api_configuration"
+
+    def get(self, request, format=None):
+        params = request.query_params
+        servicehandle = params.get('servicehandle')
+        sitename = params.get('sitename')
+
+        if (servicehandle is None or sitename is None):
+            HttpResponseBadRequest("Error: Request requires 'servicehandle' and 'sitename' as query params.")
+
+        vnodglobalservice = VnodGlobalService.get_service_objects().filter(servicehandle=servicehandle)
+        if (not vnodglobalservice):
+            HttpResponseBadRequest('Error: Could not find VnodGlobalObject with servicehandle=' + servicehandle)
+
+        vnodglobalservice = vnodglobalservice[0]
+        response_data = {}
+        response_data['vlanid'] = vnodglobalservice.vlanid
+
+        for spoke in vnodglobalservice.spokes.all():
+            if (spoke.vnodlocalsite.name == sitename and spoke.adminstate != 'configured'):
+                response_data['port'] = {}
+                response_data['port']['name'] = spoke.vnodlocalport.name
+                break;
+
+        return Response(response_data)
+
+class VnodGlobalServiceActivationView(APIView):
+    method_kind = "list"
+    method_name = "vnodglobal_api_activation"
+
+    def post(self, request, format=None):
+        body_json = request.body
+        body = json.loads(body_json)
+
+        servicehandle=body['servicehandle']
+        sitename=body['sitename']
+        activate = body['activate']
+        vnodlocalid = body['vnodlocalid']
+        portid = body.get('portid')
+
+        if (activate == 'true' or activate == 'True'):
+            isActivate = True
+        else:
+            isActivate = False
+
+        vnodglobalservice = VnodGlobalService.get_service_objects().filter(servicehandle=servicehandle)
+        if (not vnodglobalservice):
+            HttpResponseBadRequest('Error: Could not find VnodGlobalObject with servicehandle=' + servicehandle)
+
+        vnodglobalservice = vnodglobalservice[0]
+
+        for spoke in vnodglobalservice.spokes.all():
+            if (spoke.vnodlocalsite.name == sitename and spoke.vnodlocalport.name == portid):
+                spoke_id = spoke.id
+                servicespoke = ServiceSpoke.objects.get(id=spoke_id)
+                servicespoke.remotevnodid = vnodlocalid
+                servicespoke.save()
+                break;
+
+        return Response()
+
+class VnodGlobalServiceAdminOperationalStateView(APIView):
+    method_kind = "list"
+    method_name = "vnodglobal_api_status"
+
+    def post(self, request, format=None):
+        body_json = request.body
+        body = json.loads(body_json)
+
+        servicehandle = body['servicehandle']
+        sitename = body['sitename']
+        operstate = body.get('operstate')
+        adminstate = body.get('adminstate')
+        portid = body.get('portid')
+
+        vnodglobalservice = VnodGlobalService.get_service_objects().filter(servicehandle=servicehandle)
+        if (not vnodglobalservice):
+            HttpResponseBadRequest('Error: Could not find VnodGlobalObject with servicehandle=' + servicehandle)
+
+        vnodglobalservice = vnodglobalservice[0]
+
+        for spoke in vnodglobalservice.spokes.all():
+            if (spoke.vnodlocalsite.name == sitename and spoke.vnodlocalport.name == portid):
+                spoke_id = spoke.id
+                servicespoke = ServiceSpoke.objects.get(id=spoke_id)
+                if (operstate):
+                    servicespoke.operstate = operstate
+                if (adminstate):
+                    servicespoke.adminstate = adminstate
+                servicespoke.save()
+                break;
+
+        isGlobalActive = VnodGlobalServiceViewSet.calculateVnodGlobalOperState(servicehandle=servicehandle)
+
+        if (vnodglobalservice.metronetworkmultipoint is None and vnodglobalservice.metronetworkpointtopoint is None and
+                    vnodglobalservice.metronetworkroottomultipoint is None and isGlobalActive):
+            VnodGlobalServiceViewSet.createService(servicehandle=servicehandle)
+
+        return Response()