add support for single-dashboard views
[plstackapi.git] / planetstack / core / plus / views.py
index 4e58508..37165c0 100644 (file)
@@ -7,8 +7,11 @@ from django.views.generic import TemplateView, View
 import datetime
 from pprint import pprint
 import json
+from syndicate.models import *
 from core.models import *
+from hpc.models import ContentProvider
 from operator import attrgetter
+from django import template
 from django.views.decorators.csrf import csrf_exempt
 from django.http import HttpResponse, HttpResponseServerError
 from django.core import urlresolvers
@@ -36,16 +39,39 @@ class DashboardWelcomeView(TemplateView):
 
         context['userSliceInfo'] = userDetails['userSliceInfo']
         context['cdnData'] = userDetails['cdnData']
+        context['cdnContentProviders'] = userDetails['cdnContentProviders']
         return self.render_to_response(context=context)
 
+class DashboardView(TemplateView):
+    head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
+       {% load admin_static %}
+       {% block content %}
+    """
+
+    tail_template = r"{% endblock %}"
+
+    def get(self, request, name="hpc_historical", *args, **kwargs):
+        context = self.get_context_data(**kwargs)
+
+        t = template.Template(self.head_template + open("/opt/planetstack/templates/admin/dashboard/%s.html" % name, "r").read() + self.tail_template)
+
+        userDetails = getUserSliceInfo(request.user)
+        #context['site'] = userDetails['site']
+
+        context['userSliceInfo'] = userDetails['userSliceInfo']
+        context['cdnData'] = userDetails['cdnData']
+        context['cdnContentProviders'] = userDetails['cdnContentProviders']
+
+        response_kwargs = {}
+        response_kwargs.setdefault('content_type', self.content_type)
+        return self.response_class(\r
+            request = request,\r
+            template = t,\r
+            context = context,\r
+            **response_kwargs)
+
 def getUserSliceInfo(user, tableFormat = False):
         userDetails = {}
-#        try:
-# //           site = Site.objects.filter(id=user.site.id)
-#  //      except:
-#   //         site = Site.objects.filter(name="Princeton")
-#    //    userDetails['sitename'] = site[0].name
-#     //   userDetails['siteid'] = site[0].id
 
         userSliceData = getSliceInfo(user)
         if (tableFormat):
@@ -53,8 +79,8 @@ def getUserSliceInfo(user, tableFormat = False):
             userDetails['userSliceInfo'] = userSliceTableFormatter(userSliceData)
         else:
             userDetails['userSliceInfo'] = userSliceData
-        userDetails['cdnData'] = getCDNOperatorData(wait=False);
-#        pprint( userDetails)
+        userDetails['cdnData'] = getCDNOperatorData(wait=False)
+        userDetails['cdnContentProviders'] = getCDNContentProviderData()
         return userDetails
 
 class TenantCreateSlice(View):
@@ -63,15 +89,15 @@ class TenantCreateSlice(View):
         serviceClass = request.POST.get("serviceClass", "0")
         imageName = request.POST.get("imageName", "0")
         actionToDo = request.POST.get("actionToDo", "0")
-        network = request.POST.get("network","0")
+        #network = request.POST.get("network","0")
         mountDataSets = request.POST.get("mountDataSets","0")
         if (actionToDo == "add"):
            serviceClass = ServiceClass.objects.get(name=serviceClass)
            site = request.user.site
-           #image = Image.objects.get(name=imageName)
-           newSlice = Slice(name=sliceName,serviceClass=serviceClass,site=site,imagePreference=imageName,mountDataSets=mountDataSets,network=network)
+           image = Image.objects.get(name=imageName)
+           newSlice = Slice(name=sliceName,serviceClass=serviceClass,site=site,imagePreference=image,mountDataSets=mountDataSets)
            newSlice.save()
-        return newSlice
+        return HttpResponse("Slice created")
 
 class TenantUpdateSlice(View):
     def post(self, request, *args, **kwargs):\r
@@ -79,26 +105,21 @@ class TenantUpdateSlice(View):
         serviceClass = request.POST.get("serviceClass", "0")\r
         imageName = request.POST.get("imageName", "0")\r
         actionToDo = request.POST.get("actionToDo", "0")\r
-        network = request.POST.get("network","0")\r
-        slice = Slice.objects.filter(name = sliceName)\r
-        abc = ServiceClass.objects.get(name=serviceClass)\r
-        if (actionToDo == "update"):\r
-        #       print getattr(slice,'serviceClass',abc)\r
-                setattr(slice,'serviceClass',abc)\r
-        #fields = {'serviceClass':ServiceClass.objects.get(name=serviceClass),\r
-         #         'imagePreference':imageName,\r
-          #        'network':network\r
-           #      }\r
-        #update_slice(sliceName,**fields)\r
-        return HttpResponse("Slice updated")
-
-def  update_slice(sliceName,**fields):
-         slice = Slice.objects.filter(name = sliceName)\r
-         for (k,v) in fields.items():\r
-                setattr(slice, k, v)\r
-                slice.save()\r
-         return slice
-
+        #network = request.POST.get("network","0")\r
+        dataSet = request.POST.get("dataSet","0")\r
+        slice = Slice.objects.all()\r
+        for entry in slice:\r
+                serviceClass = ServiceClass.objects.get(name=serviceClass)\r
+                if(entry.name==sliceName):\r
+                         if (actionToDo == "update"):\r
+                                setattr(entry,'serviceClass',serviceClass)\r
+                                setattr(entry,'imagePreference',imageName)\r
+                                #setattr(entry,'network',network)\r
+                                setattr(entry,'mountDataSets',dataSet)\r
+                                entry.save()\r
+                                break\r
+        return HttpResponse("Slice updated")\r
+\r
 def getTenantSliceInfo(user, tableFormat = False):
     tenantSliceDetails = {}
     tenantSliceData = getTenantInfo(user)
@@ -110,13 +131,13 @@ def getTenantSliceInfo(user, tableFormat = False):
        tenantSliceDetails['userSliceInfo'] = tenantSliceData
     tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData)
     tenantSliceDetails['image']=userSliceTableFormatter(getImageInfo(user))
-    tenantSliceDetails['network']=userSliceTableFormatter(getNetworkInfo(user))
+    #tenantSliceDetails['network']=userSliceTableFormatter(getNetworkInfo(user))
     tenantSliceDetails['deploymentSites']=userSliceTableFormatter(getDeploymentSites())
     tenantSliceDetails['sites'] = userSliceTableFormatter(getTenantSitesInfo())
     tenantSliceDetails['mountDataSets'] = userSliceTableFormatter(getMountDataSets())
+    tenantSliceDetails['publicKey'] = getPublicKey(user)
     return tenantSliceDetails
 
-
 def getTenantInfo(user):
     slices =Slice.objects.all()
     userSliceInfo = []
@@ -126,7 +147,7 @@ def getTenantInfo(user):
        sliceServiceClass = entry.serviceClass.name
        preferredImage =  entry.imagePreference
        sliceDataSet = entry.mountDataSets
-       sliceNetwork = entry.network
+       #sliceNetwork = entry.network
        numSliver = 0
        sliceImage=""
        sliceSite = {}
@@ -136,10 +157,10 @@ def getTenantInfo(user):
            if sliver.node.site.name in BLESSED_SITES:
                 sliceSite[sliver.node.site.name] = sliceSite.get(sliver.node.site.name,0) + 1
                 sliceImage = sliver.image.name
-                sliceNode[sliver.instance_name] = sliver.name
+                sliceNode[str(sliver)] = sliver.node.name
        numSliver = sum(sliceSite.values())
        numSites = len(sliceSite)
-       userSliceInfo.append({'sliceName': sliceName,'sliceServiceClass': sliceServiceClass,'preferredImage':preferredImage,'numOfSites':numSites, 'sliceSite':sliceSite,'sliceImage':sliceImage,'numOfSlivers':numSliver,'sliceDataSet':sliceDataSet,'sliceNetwork':sliceNetwork, 'instanceNodePair':sliceNode})
+       userSliceInfo.append({'sliceName': sliceName,'sliceServiceClass': sliceServiceClass,'preferredImage':preferredImage,'numOfSites':numSites, 'sliceSite':sliceSite,'sliceImage':sliceImage,'numOfSlivers':numSliver,'sliceDataSet':sliceDataSet,'instanceNodePair':sliceNode})
     return userSliceInfo
 
 def getTenantSitesInfo():
@@ -156,6 +177,13 @@ def userSliceTableFormatter(data):
                     }
     return formattedData
 
+def getPublicKey(user):
+       users=User.objects.all()\r
+        for key in users:\r
+               if (str(key.email)==str(user)):\r
+                       sshKey = key.public_key\r
+        return sshKey
+
 def getServiceClassInfo(user):
     serviceClassList = ServiceClass.objects.all()
     sliceInfo = []
@@ -164,19 +192,66 @@ def getServiceClassInfo(user):
     return sliceInfo
 
 def getImageInfo(user):
-    #imageList = Image.objects.all()
-    imageList = ['Fedora 16 LXC rev 1.3','Hadoop','MPI']
+    imageList = Image.objects.all()
+    #imageList = ['Fedora 16 LXC rev 1.3','Hadoop','MPI']
     imageInfo = []
     for imageEntry in imageList:
-          #imageInfo.append({'Image':imageEntry.name})
-          imageInfo.append({'Image':imageEntry})
+          imageInfo.append({'Image':imageEntry.name})
+          #imageInfo.append({'Image':imageEntry})
     return imageInfo
 
+def createPrivateVolume(user, sliceName):
+    caps = Volume.CAP_READ_DATA | Volume.CAP_WRITE_DATA | Volume.CAP_HOST_DATA
+    getattr(Volume.default_gateway_caps,"read data") | \
+           getattr(Volume.default_gateway_caps,"write data") | \
+           getattr(Volume.default_gateway_caps,"host files")
+    v = Volume(name="private_" + sliceName, owner_id=user, description="private volume for %s" % sliceName, blocksize=61440, private=True, archive=False, default_gateway_caps = caps)
+    v.save()
+
+SYNDICATE_REPLICATE_PORTNUM = 1025
+
+def get_free_port():
+    inuse={}
+    inuse[SYNDICATE_REPLICATE_PORTNUM] = True
+    for vs in VolumeSlice.objects.all():
+        inuse[vs.peer_portnum]=True
+        inuse[vs.replicate_portnum]=True
+    for network in Network.objects.all():
+        network_ports = [x.strip() for x in network.ports.split(",")]
+        for network_port in network_ports:
+            try:
+                inuse[int(network_port)] = True
+            except:
+                # in case someone has put a malformed port number in the list
+                pass
+    for i in range(1025, 65535):
+        if not inuse.get(i,False):
+            return i
+    return False
+
+def mountVolume(sliceName, volumeName, readWrite):
+    slice = Slice.objects.get(name=sliceName)
+    volume = Volume.objects.get(name=volumeName)
+    # choose some unused port numbers
+    flags = Volume.CAP_READ_DATA
+    if readWrite:
+        flags = flags | Volume.CAP_WRITE_DATA
+    vs = VolumeSlice(volume_id = volume, slice_id = slice, gateway_caps=flags, peer_portnum = get_free_port(), replicate_portnum = SYNDICATE_REPLICATE_PORTNUM)
+    vs.save()
+
+def hasPrivateVolume(sliceName):
+     slice = Slice.objects.get(name=sliceName)
+     for vs in VolumeSlice.objects.filter(slice_id=slice):
+         if vs.volume_id.private:
+             return True
+     return False
+
 def getMountDataSets():
-        dataSetList = ['------','GenBank','LSST','LHC','NOAA','Measurement Lab','Common Crawl']\r
-        dataSetInfo = []\r
-        for entry in dataSetList:\r
-                dataSetInfo.append({'DataSet':entry})\r
+        dataSetInfo=[]\r
+        for volume in Volume.objects.all():\r
+            if not volume.private:\r
+                dataSetInfo.append({'DataSet': volume.name})\r
+\r
         return dataSetInfo
 
 def getNetworkInfo(user):
@@ -231,19 +306,28 @@ def getSliceInfo(user):
 
     return userSliceInfo
 
+def getCDNContentProviderData():
+    cps = []
+    for dm_cp in ContentProvider.objects.all():
+        cp = {"name": dm_cp.name,
+              "account": dm_cp.account}
+        cps.append(cp)
+
+    return cps
+
 def getCDNOperatorData(randomizeData = False, wait=True):
     HPC_SLICE_NAME = "HyperCache"
 
     bq = PlanetStackAnalytics()
 
-    rows = bq.get_cached_query_results(bq.compose_latest_query(groupByFields=["%hostname", "event", "%slice"]), wait)
+    rows = bq.get_cached_query_results(bq.compose_cached_query(), wait)
 
     # wait=False on the first time the Dashboard is opened. This means we might
     # not have any rows yet. The dashboard code polls every 30 seconds, so it
     # will eventually pick them up.
 
     if rows:
-        rows = bq.postprocess_results(rows, filter={"slice": HPC_SLICE_NAME}, maxi=["cpu"], count=["hostname"], computed=["bytes_sent/elapsed"], groupBy=["Time","site"], maxDeltaTime=80)
+        rows = bq.postprocess_results(rows, filter={"event": "hpc_heartbeat"}, maxi=["cpu"], count=["hostname"], computed=["bytes_sent/elapsed"], groupBy=["Time","site"], maxDeltaTime=80)
 
         # dictionaryize the statistics rows by site name
         stats_rows = {}
@@ -252,8 +336,11 @@ def getCDNOperatorData(randomizeData = False, wait=True):
     else:
         stats_rows = {}
 
-    slice = Slice.objects.get(name=HPC_SLICE_NAME)
-    slice_slivers = list(slice.slivers.all())
+    slice = Slice.objects.filter(name=HPC_SLICE_NAME)
+    if slice:
+        slice_slivers = list(slice[0].slivers.all())
+    else:
+        slice_slivers = []
 
     new_rows = {}
     for site in Site.objects.all():
@@ -275,7 +362,7 @@ def getCDNOperatorData(randomizeData = False, wait=True):
                "lat": float(site.location.latitude),
                "health": 0,
                "numNodes": int(site.nodes.count()),
-               "activeHPCSlivers": int(stats_row.get("count_hostname", 0)),         # measured number of slivers, from bigquery statistics
+               "activeHPCSlivers": int(stats_row.get("count_hostname", 0)),     # measured number of slivers, from bigquery statistics
                "numHPCSlivers": allocated_slivers,                              # allocated number of slivers, from data model
                "siteUrl": str(site.site_url),
                "bandwidth": stats_row.get("sum_computed_bytes_sent_div_elapsed",0),
@@ -297,6 +384,11 @@ def getCDNOperatorData(randomizeData = False, wait=True):
 
     return new_rows
 
+def getPageSummary(request):
+    slice = request.GET.get('slice', None)
+    site = request.GET.get('site', None)
+    node = request.GET.get('node', None)
+
 class SimulatorView(View):
     def get(self, request, **kwargs):
         sim = json.loads(file("/tmp/simulator.json","r").read())
@@ -323,12 +415,12 @@ class TenantViewData(View):
         return HttpResponse(json.dumps(getTenantSliceInfo(request.user, True)), mimetype='application/javascript')
 
 def haversine(site_lat, site_lon, lat, lon):
-    site_lat = float(site_lat)
-    site_lon = float(site_lon)
-    lat = float(lat)
-    lon = float(lon)
     d=0
     if lat and lon and site_lat and site_lon:
+        site_lat = float(site_lat)
+        site_lon = float(site_lon)
+        lat = float(lat)
+        lon = float(lon)
         R = 6378.1
         a = math.sin( math.radians((lat - site_lat)/2.0) )**2 + math.cos( math.radians(lat) )*math.cos( math.radians(site_lat) )*(math.sin( math.radians((lon - site_lon)/2.0 ) )**2)
         c = 2 * math.atan2( math.sqrt(a), math.sqrt(1 - a) )
@@ -436,9 +528,10 @@ class TenantDeleteSliceView(View):
         def post(self,request):\r
                 sliceName = request.POST.get("sliceName",None)\r
                 slice = Slice.objects.get(name=sliceName)\r
-                print slice, slice.id\r
+                #print slice, slice.id\r
                 sliceToDel=Slice(name=sliceName, id=slice.id)\r
                 sliceToDel.delete()
+                return HttpResponse("Slice deleted")
 
 class TenantAddOrRemoveSliverView(View):
     """ Add or remove slivers from a Slice
@@ -506,6 +599,8 @@ class TenantPickSitesView(View):
 class DashboardSummaryAjaxView(View):
     def get(self, request, **kwargs):
         def avg(x):
+            if len(x)==0:
+                return 0
             return float(sum(x))/len(x)
 
         sites = getCDNOperatorData().values()