6 from django.views.generic import TemplateView, View
8 from pprint import pprint
10 from syndicate.models import *
11 from core.models import *
12 from hpc.models import ContentProvider
13 from operator import attrgetter
14 from django import template
15 from django.views.decorators.csrf import csrf_exempt
16 from django.http import HttpResponse, HttpResponseServerError, HttpResponseForbidden
17 from django.core import urlresolvers
18 from django.contrib.gis.geoip import GeoIP
19 from ipware.ip import get_ip
20 from operator import itemgetter, attrgetter
24 BLESSED_SITES = ["Stanford", "Washington", "Princeton", "GeorgiaTech", "MaxPlanck"]
26 if os.path.exists("/home/smbaker/projects/vicci/cdn/bigquery"):
27 sys.path.append("/home/smbaker/projects/vicci/cdn/bigquery")
29 sys.path.append("/opt/planetstack/hpc_wizard")
31 from planetstack_analytics import DoPlanetStackAnalytics, PlanetStackAnalytics, RED_LOAD, BLUE_LOAD
33 class DashboardWelcomeView(TemplateView):
34 template_name = 'admin/dashboard/welcome.html'
36 def get(self, request, *args, **kwargs):
37 context = self.get_context_data(**kwargs)
38 context = getDashboardContext(request.user, context)
39 return self.render_to_response(context=context)
41 class DashboardDynamicView(TemplateView):
42 head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
43 {% load admin_static %}
47 tail_template = r"{% endblock %}"
49 def get(self, request, name="root", *args, **kwargs):
50 context = self.get_context_data(**kwargs)
51 context = getDashboardContext(request.user, context)
54 return self.multiDashboardView(request, context)
56 return self.singleDashboardView(request, name, context)
58 def readDashboard(self, fn):
60 template= open("/opt/planetstack/templates/admin/dashboard/%s.html" % fn, "r").read()
62 # fix for tenant view - it writes html to a div called tabs-5
63 template = '<div id="tabs-5"></div>' + template
64 if (fn=="slice_interactions"):
65 # fix for slice_interactions - it gives its container div a 40px
66 # margin, and then positions it's header at -40px
67 template = '<div id="tabs-4">' + template + '</div>'
70 return "failed to open %s" % fn
72 def multiDashboardView(self, request, context):
73 head_template = self.head_template
74 tail_template = self.tail_template
78 <ul id="suit_form_tabs" class="nav nav-tabs nav-tabs-suit" data-tab-prefix="suit-tab">
81 dashboards = request.user.get_dashboards()
83 # customize is a special dashboard they always get
84 customize = DashboardView.objects.filter(name="Customize")
86 dashboards.append(customize[0])
88 for i,view in enumerate(dashboards):
89 body = body + '<li><a href="#dashtab-%d">%s</a></li>\n' % (i, view.name)
91 body = body + "</ul>\n"
93 for i,view in enumerate(dashboards):
95 body = body + '<div id="dashtab-%d">\n' % i
96 if url.startswith("template:"):
98 body = body + self.readDashboard(fn)
99 body = body + '</div>\n'
103 t = template.Template(head_template + body + self.tail_template)
106 response_kwargs.setdefault('content_type', self.content_type)
107 return self.response_class(
\r
113 def singleDashboardView(self, request, name, context):
114 head_template = self.head_template
115 tail_template = self.tail_template
117 t = template.Template(head_template + self.readDashboard(fn) + self.tail_template)
120 response_kwargs.setdefault('content_type', self.content_type)
121 return self.response_class(
\r
127 def getDashboardContext(user, context={}, tableFormat = False):
130 userSliceData = getSliceInfo(user)
132 context['userSliceInfo'] = userSliceTableFormatter(userSliceData)
134 context['userSliceInfo'] = userSliceData
135 context['cdnData'] = getCDNOperatorData(wait=False)
136 context['cdnContentProviders'] = getCDNContentProviderData()
138 (dashboards, unusedDashboards)= getDashboards(user)
139 unusedDashboards=[x for x in unusedDashboards if x!="Customize"]
140 context['dashboards'] = dashboards
141 context['unusedDashboards'] = unusedDashboards
145 def getDashboards(user):
146 #dashboards = sorted(list(user.dashboardViews.all()), key=attrgetter('order'))
147 dashboards = user.get_dashboards()
149 dashboard_names = [d.name for d in dashboards]
151 unused_dashboard_names = []
152 for dashboardView in DashboardView.objects.all():
153 if not dashboardView.name in dashboard_names:
154 unused_dashboard_names.append(dashboardView.name)
156 return (dashboard_names, unused_dashboard_names)
158 class TenantCreateSlice(View):
159 def post(self, request, *args, **kwargs):
160 if request.user.isReadOnlyUser():
161 return HttpResponseForbidden("User is in read-only mode")
163 sliceName = request.POST.get("sliceName", "0")
164 serviceClass = request.POST.get("serviceClass", "0")
165 imageName = request.POST.get("imageName", "0")
166 actionToDo = request.POST.get("actionToDo", "0")
167 networkPorts = request.POST.get("network","0")
168 mountDataSets = request.POST.get("mountDataSets","0")
169 privateVolume = request.POST.get("privateVolume","0")
170 if (actionToDo == "add"):
171 serviceClass = ServiceClass.objects.get(name=serviceClass)
172 site = request.user.site
173 image = Image.objects.get(name=imageName)
174 newSlice = Slice(name=sliceName,serviceClass=serviceClass,site=site,imagePreference=image,mountDataSets=mountDataSets)
176 privateTemplate="Private"
177 publicTemplate="Public shared IPv4"
\r
178 privateNetworkName = sliceName+"-"+privateTemplate
\r
179 publicNetworkName = sliceName+"-"+publicTemplate
\r
180 slice=Slice.objects.get(name=sliceName)
\r
181 addNetwork(privateNetworkName,privateTemplate,slice)
\r
182 addNetwork(publicNetworkName,publicTemplate,slice)
\r
183 addOrModifyPorts(networkPorts,sliceName)
\r
184 if privateVolume=="true":
\r
185 privateVolForSlice(request.user,sliceName)
186 return HttpResponse("Slice created")
188 def privateVolForSlice(user,sliceName):
189 if not hasPrivateVolume(sliceName):
\r
190 volumeName=createPrivateVolume(user,sliceName)
\r
192 mountVolume(sliceName,volumeName,readWrite)
194 class TenantUpdateSlice(View):
195 def post(self, request, *args, **kwargs):
\r
196 if request.user.isReadOnlyUser():
\r
197 return HttpResponseForbidden("User is in read-only mode")
\r
199 sliceName = request.POST.get("sliceName", "0")
\r
200 serviceClass = request.POST.get("serviceClass", "0")
\r
201 imageName = request.POST.get("imageName", "0")
\r
202 actionToDo = request.POST.get("actionToDo", "0")
\r
203 networkPorts = request.POST.get("networkPorts","0")
\r
204 dataSet = request.POST.get("dataSet","0")
\r
205 privateVolume = request.POST.get("privateVolume","0")
\r
206 slice = Slice.objects.all()
\r
207 for entry in slice:
\r
208 serviceClass = ServiceClass.objects.get(name=serviceClass)
\r
209 if(entry.name==sliceName):
\r
210 if (actionToDo == "update"):
\r
211 setattr(entry,'serviceClass',serviceClass)
\r
212 setattr(entry,'imagePreference',imageName)
\r
213 setattr(entry,'mountDataSets',dataSet)
\r
216 addOrModifyPorts(networkPorts,sliceName)
\r
217 if privateVolume=="true":
\r
218 privateVolForSlice(request.user,sliceName)
\r
219 return HttpResponse("Slice updated")
\r
221 def addNetwork(name,template,sliceName):
\r
222 networkTemplate=NetworkTemplate.objects.get(name=template)
\r
223 newNetwork = Network(name = name,
\r
224 template = networkTemplate,
\r
227 addNetworkSlice(newNetwork,sliceName)
\r
229 def addNetworkSlice(networkSlice,sliceName):
\r
230 newNetworkSlice=NetworkSlice(network =networkSlice,
\r
232 newNetworkSlice.save()
\r
234 def addOrModifyPorts(networkPorts,sliceName):
\r
235 networkList = Network.objects.all()
\r
238 for networkEntry in networkList:
\r
239 networkSlices = networkEntry.slices.all()
\r
240 for slice in networkSlices:
\r
241 if slice.name==sliceName:
\r
242 if networkEntry.template.name=="Public shared IPv4":
\r
243 setattr(networkEntry,'ports',networkPorts)
\r
244 networkEntry.save()
\r
246 def getTenantSliceInfo(user, tableFormat = False):
247 tenantSliceDetails = {}
248 tenantSliceData = getTenantInfo(user)
249 tenantServiceClassData = getServiceClassInfo(user)
251 tenantSliceDetails['userSliceInfo'] = userSliceTableFormatter(tenantSliceData)
252 tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData)
254 tenantSliceDetails['userSliceInfo'] = tenantSliceData
255 tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData)
256 tenantSliceDetails['image']=userSliceTableFormatter(getImageInfo(user))
257 tenantSliceDetails['deploymentSites']=userSliceTableFormatter(getDeploymentSites())
258 tenantSliceDetails['sites'] = userSliceTableFormatter(getTenantSitesInfo())
259 tenantSliceDetails['mountDataSets'] = userSliceTableFormatter(getMountDataSets())
260 tenantSliceDetails['publicKey'] = getPublicKey(user)
261 return tenantSliceDetails
263 def getTenantInfo(user):
264 slices =Slice.objects.all()
267 sliceName = Slice.objects.get(id=entry.id).name
268 slice = Slice.objects.get(name=Slice.objects.get(id=entry.id).name)
269 sliceServiceClass = entry.serviceClass.name
270 preferredImage = entry.imagePreference
271 #sliceDataSet = entry.mountDataSets
278 #createPrivateVolume(user,sliceName)
279 for sliver in slice.slivers.all():
280 if sliver.node.site.name in BLESSED_SITES:
281 sliceSite[sliver.node.site.name] = sliceSite.get(sliver.node.site.name,0) + 1
282 sliceImage = sliver.image.name
283 sliceNode[str(sliver)] = sliver.node.name
284 numSliver = sum(sliceSite.values())
285 numSites = len(sliceSite)
286 userSliceInfo.append({'sliceName': sliceName,'sliceServiceClass': sliceServiceClass,'preferredImage':preferredImage,'numOfSites':numSites, 'sliceSite':sliceSite,'sliceImage':sliceImage,'numOfSlivers':numSliver,'instanceNodePair':sliceNode})
289 def getTenantSitesInfo():
291 for entry in Site.objects.all():
292 if entry.name in BLESSED_SITES:
293 tenantSiteInfo.append({'siteName':entry.name})
294 return tenantSiteInfo
296 def userSliceTableFormatter(data):
303 def getPublicKey(user):
304 users=User.objects.all()
\r
306 if (str(key.email)==str(user)):
\r
307 sshKey = key.public_key
\r
310 def getServiceClassInfo(user):
311 serviceClassList = ServiceClass.objects.all()
313 for entry in serviceClassList:
314 sliceInfo.append({'serviceClass':entry.name})
317 def getImageInfo(user):
318 imageList = Image.objects.all()
319 #imageList = ['Fedora 16 LXC rev 1.3','Hadoop','MPI']
321 for imageEntry in imageList:
322 imageInfo.append({'Image':imageEntry.name})
323 #imageInfo.append({'Image':imageEntry})
326 def createPrivateVolume(user, sliceName):
327 caps = Volume.CAP_READ_DATA | Volume.CAP_WRITE_DATA | Volume.CAP_HOST_DATA
328 getattr(Volume.default_gateway_caps,"read data") | \
329 getattr(Volume.default_gateway_caps,"write data") | \
330 getattr(Volume.default_gateway_caps,"host files")
331 v = Volume(name="private_" + sliceName, owner_id=user, description="private volume for %s" % sliceName, blocksize=61440, private=True, archive=False, default_gateway_caps = caps)
335 SYNDICATE_REPLICATE_PORTNUM = 1025
339 inuse[SYNDICATE_REPLICATE_PORTNUM] = True
340 for vs in VolumeSlice.objects.all():
341 inuse[vs.peer_portnum]=True
342 inuse[vs.replicate_portnum]=True
343 for network in Network.objects.all():
344 if not network_ports:
346 network_ports = [x.strip() for x in network.ports.split(",")]
347 for network_port in network_ports:
349 inuse[int(network_port)] = True
351 # in case someone has put a malformed port number in the list
353 for i in range(1025, 65535):
354 if not inuse.get(i,False):
358 def mountVolume(sliceName, volumeName, readWrite):
359 slice = Slice.objects.get(name=sliceName)
360 volume = Volume.objects.get(name=volumeName)
361 # choose some unused port numbers
362 flags = Volume.CAP_READ_DATA
364 flags = flags | Volume.CAP_WRITE_DATA
365 vs = VolumeSlice(volume_id = volume, slice_id = slice, gateway_caps=flags, peer_portnum = get_free_port(), replicate_portnum = SYNDICATE_REPLICATE_PORTNUM)
368 def hasPrivateVolume(sliceName):
369 slice = Slice.objects.get(name=sliceName)
370 for vs in VolumeSlice.objects.filter(slice_id=slice):
371 if vs.volume_id.private:
375 def getMountDataSets():
377 for volume in Volume.objects.all():
\r
378 if not volume.private:
\r
379 dataSetInfo.append({'DataSet': volume.name})
\r
383 def getDeploymentSites():
384 deploymentList = Deployment.objects.all()
386 for entry in deploymentList:
387 deploymentInfo.append({'DeploymentSite':entry.name})
388 return deploymentInfo
390 def getSliceInfo(user):
391 sliceList = Slice.objects.all()
392 slicePrivs = SlicePrivilege.objects.filter(user=user)
394 for entry in slicePrivs:
396 slicename = Slice.objects.get(id=entry.slice.id).name
397 slice = Slice.objects.get(name=Slice.objects.get(id=entry.slice.id).name)
398 sliverList=Sliver.objects.all()
400 for sliver in slice.slivers.all():
401 #sites_used['deploymentSites'] = sliver.node.deployment.name
402 # sites_used[sliver.image.name] = sliver.image.name
403 sites_used[sliver.node.site.name] = sliver.numberCores
404 sliceid = Slice.objects.get(id=entry.slice.id).id
406 sliverList = Sliver.objects.filter(slice=entry.slice.id)
409 if x.node.site not in siteList:
410 siteList[x.node.site] = 1
411 slivercount = len(sliverList)
412 sitecount = len(siteList)
414 traceback.print_exc()
418 userSliceInfo.append({'slicename': slicename, 'sliceid':sliceid,
419 'sitesUsed':sites_used,
420 'role': SliceRole.objects.get(id=entry.role.id).role,
421 'slivercount': slivercount,
422 'sitecount':sitecount})
426 def getCDNContentProviderData():
428 for dm_cp in ContentProvider.objects.all():
429 cp = {"name": dm_cp.name,
430 "account": dm_cp.account}
435 def getCDNOperatorData(randomizeData = False, wait=True):
436 HPC_SLICE_NAME = "HyperCache"
438 bq = PlanetStackAnalytics()
440 rows = bq.get_cached_query_results(bq.compose_cached_query(), wait)
442 # wait=False on the first time the Dashboard is opened. This means we might
443 # not have any rows yet. The dashboard code polls every 30 seconds, so it
444 # will eventually pick them up.
447 rows = bq.postprocess_results(rows, filter={"event": "hpc_heartbeat"}, maxi=["cpu"], count=["hostname"], computed=["bytes_sent/elapsed"], groupBy=["Time","site"], maxDeltaTime=80)
449 # dictionaryize the statistics rows by site name
452 stats_rows[row["site"]] = row
456 slice = Slice.objects.filter(name=HPC_SLICE_NAME)
458 slice_slivers = list(slice[0].slivers.all())
463 for site in Site.objects.all():
464 # compute number of slivers allocated in the data model
465 allocated_slivers = 0
466 for sliver in slice_slivers:
467 if sliver.node.site == site:
468 allocated_slivers = allocated_slivers + 1
470 stats_row = stats_rows.get(site.name,{})
472 max_cpu = stats_row.get("max_avg_cpu", stats_row.get("max_cpu",0))
473 cpu=float(max_cpu)/100.0
474 hotness = max(0.0, ((cpu*RED_LOAD) - BLUE_LOAD)/(RED_LOAD-BLUE_LOAD))
476 # format it to what that CDN Operations View is expecting
477 new_row = {"lat": float(site.location.longitude),
478 "long": float(site.location.longitude),
479 "lat": float(site.location.latitude),
481 "numNodes": int(site.nodes.count()),
482 "activeHPCSlivers": int(stats_row.get("count_hostname", 0)), # measured number of slivers, from bigquery statistics
483 "numHPCSlivers": allocated_slivers, # allocated number of slivers, from data model
484 "siteUrl": str(site.site_url),
485 "bandwidth": stats_row.get("sum_computed_bytes_sent_div_elapsed",0),
487 "hot": float(hotness)}
488 new_rows[str(site.name)] = new_row
490 # get rid of sites with 0 slivers that overlap other sites with >0 slivers
491 for (k,v) in new_rows.items():
493 if v["numHPCSlivers"]==0:
494 for v2 in new_rows.values():
495 if (v!=v2) and (v2["numHPCSlivers"]>=0):
496 d = haversine(v["lat"],v["long"],v2["lat"],v2["long"])
504 def getPageSummary(request):
505 slice = request.GET.get('slice', None)
506 site = request.GET.get('site', None)
507 node = request.GET.get('node', None)
509 class SimulatorView(View):
510 def get(self, request, **kwargs):
511 sim = json.loads(file("/tmp/simulator.json","r").read())
512 text = "<html><head></head><body>"
513 text += "Iteration: %d<br>" % sim["iteration"]
514 text += "Elapsed since report %d<br><br>" % sim["elapsed_since_report"]
515 text += "<table border=1>"
516 text += "<tr><th>site</th><th>trend</th><th>weight</th><th>bytes_sent</th><th>hot</th></tr>"
517 for site in sim["site_load"].values():
519 text += "<td>%s</td><td>%0.2f</td><td>%0.2f</td><td>%d</td><td>%0.2f</td>" % \
520 (site["name"], site["trend"], site["weight"], site["bytes_sent"], site["load_frac"])
523 text += "</body></html>"
524 return HttpResponse(text)
526 class DashboardUserSiteView(View):
527 def get(self, request, **kwargs):
528 return HttpResponse(json.dumps(getDashboardContext(request.user, tableFormat=True)), mimetype='application/javascript')
530 class TenantViewData(View):
531 def get(self, request, **kwargs):
532 return HttpResponse(json.dumps(getTenantSliceInfo(request.user, True)), mimetype='application/javascript')
534 def haversine(site_lat, site_lon, lat, lon):
536 if lat and lon and site_lat and site_lon:
537 site_lat = float(site_lat)
538 site_lon = float(site_lon)
542 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)
543 c = 2 * math.atan2( math.sqrt(a), math.sqrt(1 - a) )
548 def siteSortKey(site, slice=None, count=None, lat=None, lon=None):
549 # try to pick a site we're already using
550 has_slivers_here=False
552 for sliver in slice.slivers.all():
553 if sliver.node.site.name == site.name:
554 has_slivers_here=True
557 d = haversine(site.location.latitude, site.location.longitude, lat, lon)
559 return (-has_slivers_here, d)
561 def tenant_pick_sites(user, user_ip=None, slice=None, count=None):
562 """ Returns list of sites, sorted from most favorable to least favorable """
566 client_geo = GeoIP().city(user_ip)
568 lat=float(client_geo["latitude"])
569 lon=float(client_geo["longitude"])
571 print "exception in geo code"
572 traceback.print_exc()
574 sites = Site.objects.all()
575 sites = [x for x in sites if x.name in BLESSED_SITES]
576 sites = sorted(sites, key=functools.partial(siteSortKey, slice=slice, count=count, lat=lat, lon=lon))
580 def slice_increase_slivers(user, user_ip, siteList, slice, count, noAct=False):
583 # let's compute how many slivers are in use in each node of each site
584 for site in siteList:
585 site.nodeList = list(site.nodes.all())
586 for node in site.nodeList:
588 for sliver in node.slivers.all():
589 if sliver.slice.id == slice.id:
590 node.sliverCount = node.sliverCount + 1
592 # Allocate slivers to nodes
593 # for now, assume we want to allocate all slivers from the same site
594 nodes = siteList[0].nodeList
596 # Sort the node list by number of slivers per node, then pick the
597 # node with the least number of slivers.
598 nodes = sorted(nodes, key=attrgetter("sliverCount"))
601 print "adding sliver at node", node.name, "of site", node.site.name
604 sliver = Sliver(name=node.name,
607 image = Image.objects.all()[0],
608 creator = User.objects.get(email=user),
609 deploymentNetwork=node.deployment,
613 node.sliverCount = node.sliverCount + 1
617 sitesChanged[node.site.name] = sitesChanged.get(node.site.name,0) + 1
621 def slice_decrease_slivers(user, siteList, slice, count, noAct=False):
625 siteNames = [site.name for site in siteList]
629 for sliver in slice.slivers.all():
630 if(not siteNames) or (sliver.node.site.name in siteNames):
\r
632 sliverList[sliver.name]=node.name
634 for key in sliverList:
636 sliver = Sliver.objects.filter(name=key)[0]
\r
638 print "deleting sliver",sliverList[key],"at node",sliver.node.name
\r
640 sitesChanged[sliver.node.site.name] = sitesChanged.get(sliver.node.site.name,0) - 1
\r
644 class TenantDeleteSliceView(View):
645 def post(self,request):
\r
646 if request.user.isReadOnlyUser():
\r
647 return HttpResponseForbidden("User is in read-only mode")
\r
648 sliceName = request.POST.get("sliceName",None)
\r
649 slice = Slice.objects.get(name=sliceName)
\r
650 #print slice, slice.id
\r
651 sliceToDel=Slice(name=sliceName, id=slice.id)
\r
653 return HttpResponse("Slice deleted")
655 class TenantAddOrRemoveSliverView(View):
656 """ Add or remove slivers from a Slice
659 siteName - name of site. If not specified, PlanetStack will pick the
661 actionToDo - [add | rem]
662 count - number of slivers to add or remove
663 sliceName - name of slice
664 noAct - if set, no changes will be made to db, but result will still
665 show which sites would have been modified.
668 Dictionary of sites that were modified, and the count of nodes
669 that were added or removed at each site.
671 def post(self, request, *args, **kwargs):
672 siteName = request.POST.get("siteName", None)
673 actionToDo = request.POST.get("actionToDo", None)
674 count = int(request.POST.get("count","0"))
675 sliceName = request.POST.get("slice", None)
676 noAct = request.POST.get("noAct", False)
679 return HttpResponseServerError("No slice name given")
681 slice = Slice.objects.get(name=sliceName)
684 siteList = [Site.objects.get(name=siteName)]
688 if (actionToDo == "add"):
689 user_ip = request.GET.get("ip", get_ip(request))
690 if (siteList is None):
691 siteList = tenant_pick_sites(user, user_ip, slice, count)
693 sitesChanged = slice_increase_slivers(request.user, user_ip, siteList, slice, count, noAct)
694 elif (actionToDo == "rem"):
695 sitesChanged = slice_decrease_slivers(request.user, siteList, slice, count, noAct)
697 return HttpResponseServerError("Unknown actionToDo %s" % actionToDo)
699 return HttpResponse(json.dumps(sitesChanged), mimetype='application/javascript')
701 def get(self, request, *args, **kwargs):
702 request.POST = request.GET
703 return self.post(request, *args, **kwargs) # for testing REST in browser
704 #return HttpResponseServerError("GET is not supported")
706 class TenantPickSitesView(View):
707 """ primarily just for testing purposes """
708 def get(self, request, *args, **kwargs):
709 count = request.GET.get("count","0")
710 slice = request.GET.get("slice",None)
712 slice = Slice.objects.get(name=slice)
713 ip = request.GET.get("ip", get_ip(request))
714 sites = tenant_pick_sites(request.user, user_ip=ip, count=0, slice=slice)
715 sites = [x.name for x in sites]
716 return HttpResponse(json.dumps(sites), mimetype='application/javascript')
718 class DashboardSummaryAjaxView(View):
719 def get(self, request, **kwargs):
723 return float(sum(x))/len(x)
725 sites = getCDNOperatorData().values()
727 sites = [site for site in sites if site["numHPCSlivers"]>0]
729 total_slivers = sum( [site["numHPCSlivers"] for site in sites] )
730 total_bandwidth = sum( [site["bandwidth"] for site in sites] )
731 average_cpu = int(avg( [site["load"] for site in sites] ))
733 result= {"total_slivers": total_slivers,
734 "total_bandwidth": total_bandwidth,
735 "average_cpu": average_cpu}
737 return HttpResponse(json.dumps(result), mimetype='application/javascript')
739 class DashboardAddOrRemoveSliverView(View):
740 # TODO: deprecate this view in favor of using TenantAddOrRemoveSliverView
742 def post(self, request, *args, **kwargs):
743 siteName = request.POST.get("site", None)
744 actionToDo = request.POST.get("actionToDo", "0")
746 siteList = [Site.objects.get(name=siteName)]
747 slice = Slice.objects.get(name="HyperCache")
749 if request.user.isReadOnlyUser():
750 return HttpResponseForbidden("User is in read-only mode")
752 if (actionToDo == "add"):
753 user_ip = request.GET.get("ip", get_ip(request))
754 slice_increase_slivers(request.user, user_ip, siteList, slice, 1)
755 elif (actionToDo == "rem"):
756 slice_decrease_slivers(request.user, siteList, slice, 1)
759 print 'Ask for site: ' + siteName + ' to ' + actionToDo + ' another HPC Sliver'
760 return HttpResponse(json.dumps("Success"), mimetype='application/javascript')
762 class DashboardAjaxView(View):
763 def get(self, request, **kwargs):
764 return HttpResponse(json.dumps(getCDNOperatorData(True)), mimetype='application/javascript')
766 class DashboardAnalyticsAjaxView(View):
767 def get(self, request, name="hello_world", **kwargs):
768 if (name == "hpcSummary"):
769 return HttpResponse(json.dumps(hpc_wizard.get_hpc_wizard().get_summary_for_view()), mimetype='application/javascript')
770 elif (name == "hpcUserSite"):
771 return HttpResponse(json.dumps(getDashboardContext(request.user, tableFormat=True)), mimetype='application/javascript')
772 elif (name == "hpcMap"):
773 return HttpResponse(json.dumps(getCDNOperatorData(True)), mimetype='application/javascript')
774 elif (name == "bigquery"):
775 (mimetype, data) = DoPlanetStackAnalytics(request)
776 return HttpResponse(data, mimetype=mimetype)
778 return HttpResponse(json.dumps("Unknown"), mimetype='application/javascript')
780 class DashboardCustomize(View):
781 def post(self, request, *args, **kwargs):
\r
782 if request.user.isReadOnlyUser():
\r
783 return HttpResponseForbidden("User is in read-only mode")
\r
785 dashboards = request.POST.get("dashboards", None)
\r
789 dashboards = [x.strip() for x in dashboards.split(",")]
\r
790 dashboards = [DashboardView.objects.get(name=x) for x in dashboards]
\r
792 request.user.dashboardViews.all().delete()
\r
794 for i,dashboard in enumerate(dashboards):
\r
795 udbv = UserDashboardView(user=request.user, dashboardView=dashboard, order=i)
\r
798 return HttpResponse(json.dumps("Success"), mimetype='application/javascript')
\r