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 django.db.models import Q
20 from ipware.ip import get_ip
21 from operator import itemgetter, attrgetter
25 BLESSED_SITES = ["Stanford", "Washington", "Princeton", "GeorgiaTech", "MaxPlanck"]
27 if os.path.exists("/home/smbaker/projects/vicci/cdn/bigquery"):
28 sys.path.append("/home/smbaker/projects/vicci/cdn/bigquery")
30 sys.path.append("/opt/planetstack/hpc_wizard")
32 from planetstack_analytics import DoPlanetStackAnalytics, PlanetStackAnalytics, RED_LOAD, BLUE_LOAD
34 class DashboardWelcomeView(TemplateView):
35 template_name = 'admin/dashboard/welcome.html'
37 def get(self, request, *args, **kwargs):
38 context = self.get_context_data(**kwargs)
39 context = getDashboardContext(request.user, context)
40 return self.render_to_response(context=context)
42 class DashboardDynamicView(TemplateView):
43 head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
44 {% load admin_static %}
48 tail_template = r"{% endblock %}"
50 def get(self, request, name="root", *args, **kwargs):
51 context = self.get_context_data(**kwargs)
52 context = getDashboardContext(request.user, context)
55 return self.multiDashboardView(request, context)
57 return self.singleDashboardView(request, name, context)
59 def readDashboard(self, fn):
61 template= open("/opt/planetstack/templates/admin/dashboard/%s.html" % fn, "r").read()
63 # fix for tenant view - it writes html to a div called tabs-5
64 template = '<div id="tabs-5"></div>' + template
67 return "failed to open %s" % fn
69 def multiDashboardView(self, request, context):
70 head_template = self.head_template
71 tail_template = self.tail_template
75 <ul id="suit_form_tabs" class="nav nav-tabs nav-tabs-suit" data-tab-prefix="suit-tab">
78 dashboards = request.user.get_dashboards()
80 # customize is a special dashboard they always get
81 customize = DashboardView.objects.filter(name="Customize")
83 dashboards.append(customize[0])
85 for i,view in enumerate(dashboards):
86 body = body + '<li><a href="#dashtab-%d">%s</a></li>\n' % (i, view.name)
88 body = body + "</ul>\n"
90 for i,view in enumerate(dashboards):
92 body = body + '<div id="dashtab-%d">\n' % i
93 if url.startswith("template:"):
95 body = body + self.readDashboard(fn)
96 body = body + '</div>\n'
100 t = template.Template(head_template + body + self.tail_template)
103 response_kwargs.setdefault('content_type', self.content_type)
104 return self.response_class(
\r
110 def singleDashboardView(self, request, name, context):
111 head_template = self.head_template
112 tail_template = self.tail_template
114 t = template.Template(head_template + self.readDashboard(name) + self.tail_template)
117 response_kwargs.setdefault('content_type', self.content_type)
118 return self.response_class(
\r
124 def getDashboardContext(user, context={}, tableFormat = False):
127 userSliceData = getSliceInfo(user)
129 context['userSliceInfo'] = userSliceTableFormatter(userSliceData)
131 context['userSliceInfo'] = userSliceData
132 context['cdnData'] = getCDNOperatorData(wait=False)
133 context['cdnContentProviders'] = getCDNContentProviderData()
135 (dashboards, unusedDashboards)= getDashboards(user)
136 unusedDashboards=[x for x in unusedDashboards if x!="Customize"]
137 context['dashboards'] = dashboards
138 context['unusedDashboards'] = unusedDashboards
142 def getDashboards(user):
143 #dashboards = sorted(list(user.dashboardViews.all()), key=attrgetter('order'))
144 dashboards = user.get_dashboards()
146 dashboard_names = [d.name for d in dashboards]
148 unused_dashboard_names = []
149 for dashboardView in DashboardView.objects.all():
150 if not dashboardView.name in dashboard_names:
151 unused_dashboard_names.append(dashboardView.name)
153 return (dashboard_names, unused_dashboard_names)
155 class TenantCreateSlice(View):
156 def post(self, request, *args, **kwargs):
157 if request.user.isReadOnlyUser():
158 return HttpResponseForbidden("User is in read-only mode")
160 sliceName = request.POST.get("sliceName", "0")
161 serviceClass = request.POST.get("serviceClass", "0")
162 imageName = request.POST.get("imageName", "0")
163 actionToDo = request.POST.get("actionToDo", "0")
164 networkPorts = request.POST.get("network","0")
165 mountDataSets = request.POST.get("mountDataSets","0")
166 privateVolume = request.POST.get("privateVolume","0")
167 if (actionToDo == "add"):
168 serviceClass = ServiceClass.objects.get(name=serviceClass)
169 site = request.user.site
170 image = Image.objects.get(name=imageName)
171 newSlice = Slice(name=sliceName,serviceClass=serviceClass,site=site,imagePreference=image,mountDataSets=mountDataSets)
173 privateTemplate="Private"
174 publicTemplate="Public shared IPv4"
\r
175 privateNetworkName = sliceName+"-"+privateTemplate
\r
176 publicNetworkName = sliceName+"-"+publicTemplate
\r
177 slice=Slice.objects.get(name=sliceName)
\r
178 addNetwork(privateNetworkName,privateTemplate,slice)
\r
179 addNetwork(publicNetworkName,publicTemplate,slice)
\r
180 addOrModifyPorts(networkPorts,sliceName)
\r
181 if privateVolume=="true":
\r
182 privateVolForSlice(request.user,sliceName)
183 return HttpResponse("Slice created")
185 def privateVolForSlice(user,sliceName):
186 if not hasPrivateVolume(sliceName):
\r
187 volumeName=createPrivateVolume(user,sliceName)
\r
189 mountVolume(sliceName,volumeName,readWrite)
191 class TenantUpdateSlice(View):
192 def post(self, request, *args, **kwargs):
\r
193 if request.user.isReadOnlyUser():
\r
194 return HttpResponseForbidden("User is in read-only mode")
\r
196 sliceName = request.POST.get("sliceName", "0")
\r
197 serviceClass = request.POST.get("serviceClass", "0")
\r
198 imageName = request.POST.get("imageName", "0")
\r
199 actionToDo = request.POST.get("actionToDo", "0")
\r
200 networkPorts = request.POST.get("networkPorts","0")
\r
201 dataSet = request.POST.get("dataSet","0")
\r
202 privateVolume = request.POST.get("privateVolume","0")
\r
203 slice = Slice.objects.all()
\r
204 for entry in slice:
\r
205 serviceClass = ServiceClass.objects.get(name=serviceClass)
\r
206 if(entry.name==sliceName):
\r
207 if (actionToDo == "update"):
\r
208 setattr(entry,'serviceClass',serviceClass)
\r
209 setattr(entry,'imagePreference',imageName)
\r
210 setattr(entry,'mountDataSets',dataSet)
\r
213 addOrModifyPorts(networkPorts,sliceName)
\r
214 if privateVolume=="true":
\r
215 privateVolForSlice(request.user,sliceName)
\r
216 return HttpResponse("Slice updated")
\r
218 def addNetwork(name,template,sliceName):
\r
219 networkTemplate=NetworkTemplate.objects.get(name=template)
\r
220 newNetwork = Network(name = name,
\r
221 template = networkTemplate,
\r
224 addNetworkSlice(newNetwork,sliceName)
\r
226 def addNetworkSlice(networkSlice,sliceName):
\r
227 newNetworkSlice=NetworkSlice(network =networkSlice,
\r
229 newNetworkSlice.save()
\r
231 def addOrModifyPorts(networkPorts,sliceName):
\r
232 networkList = Network.objects.all()
\r
235 for networkEntry in networkList:
\r
236 networkSlices = networkEntry.slices.all()
\r
237 for slice in networkSlices:
\r
238 if slice.name==sliceName:
\r
239 if networkEntry.template.name=="Public shared IPv4":
\r
240 setattr(networkEntry,'ports',networkPorts)
\r
241 networkEntry.save()
\r
243 def getTenantSliceInfo(user, tableFormat = False):
244 tenantSliceDetails = {}
245 tenantSliceData = getTenantInfo(user)
246 tenantServiceClassData = getServiceClassInfo(user)
248 tenantSliceDetails['userSliceInfo'] = userSliceTableFormatter(tenantSliceData)
249 tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData)
251 tenantSliceDetails['userSliceInfo'] = tenantSliceData
252 tenantSliceDetails['sliceServiceClass']=userSliceTableFormatter(tenantServiceClassData)
253 tenantSliceDetails['image']=userSliceTableFormatter(getImageInfo(user))
254 tenantSliceDetails['deploymentSites']=userSliceTableFormatter(getDeploymentSites())
255 tenantSliceDetails['sites'] = userSliceTableFormatter(getTenantSitesInfo())
256 tenantSliceDetails['mountDataSets'] = userSliceTableFormatter(getMountDataSets())
257 tenantSliceDetails['publicKey'] = getPublicKey(user)
258 return tenantSliceDetails
260 def getTenantInfo(user):
261 slices =Slice.objects.all()
264 sliceName = Slice.objects.get(id=entry.id).name
265 slice = Slice.objects.get(name=Slice.objects.get(id=entry.id).name)
266 sliceServiceClass = entry.serviceClass.name
267 preferredImage = entry.imagePreference
268 #sliceDataSet = entry.mountDataSets
275 #createPrivateVolume(user,sliceName)
276 for sliver in slice.slivers.all():
277 if sliver.node.site.name in BLESSED_SITES:
278 sliceSite[sliver.node.site.name] = sliceSite.get(sliver.node.site.name,0) + 1
279 sliceImage = sliver.image.name
280 sliceNode[str(sliver)] = sliver.node.name
281 numSliver = sum(sliceSite.values())
282 numSites = len(sliceSite)
283 userSliceInfo.append({'sliceName': sliceName,'sliceServiceClass': sliceServiceClass,'preferredImage':preferredImage,'numOfSites':numSites, 'sliceSite':sliceSite,'sliceImage':sliceImage,'numOfSlivers':numSliver,'instanceNodePair':sliceNode})
286 def getTenantSitesInfo():
288 for entry in Site.objects.all():
289 if entry.name in BLESSED_SITES:
290 tenantSiteInfo.append({'siteName':entry.name})
291 return tenantSiteInfo
293 def userSliceTableFormatter(data):
300 def getPublicKey(user):
301 users=User.objects.all()
\r
303 if (str(key.email)==str(user)):
\r
304 sshKey = key.public_key
\r
307 def getServiceClassInfo(user):
308 serviceClassList = ServiceClass.objects.all()
310 for entry in serviceClassList:
311 sliceInfo.append({'serviceClass':entry.name})
314 def getImageInfo(user):
315 imageList = Image.objects.all()
316 #imageList = ['Fedora 16 LXC rev 1.3','Hadoop','MPI']
318 for imageEntry in imageList:
319 imageInfo.append({'Image':imageEntry.name})
320 #imageInfo.append({'Image':imageEntry})
323 def createPrivateVolume(user, sliceName):
324 caps = Volume.CAP_READ_DATA | Volume.CAP_WRITE_DATA | Volume.CAP_HOST_DATA
325 getattr(Volume.default_gateway_caps,"read data") | \
326 getattr(Volume.default_gateway_caps,"write data") | \
327 getattr(Volume.default_gateway_caps,"host files")
328 v = Volume(name="private_" + sliceName, owner_id=user, description="private volume for %s" % sliceName, blocksize=61440, private=True, archive=False, default_gateway_caps = caps)
332 SYNDICATE_REPLICATE_PORTNUM = 1025
336 inuse[SYNDICATE_REPLICATE_PORTNUM] = True
337 for vs in VolumeSlice.objects.all():
338 inuse[vs.peer_portnum]=True
339 inuse[vs.replicate_portnum]=True
340 for network in Network.objects.all():
341 if not network.ports:
343 network_ports = [x.strip() for x in network.ports.split(",")]
344 for network_port in network_ports:
346 inuse[int(network_port)] = True
348 # in case someone has put a malformed port number in the list
350 for i in range(1025, 65535):
351 if not inuse.get(i,False):
355 def mountVolume(sliceName, volumeName, readWrite):
356 slice = Slice.objects.get(name=sliceName)
357 volume = Volume.objects.get(name=volumeName)
358 # choose some unused port numbers
359 flags = Volume.CAP_READ_DATA
361 flags = flags | Volume.CAP_WRITE_DATA
362 vs = VolumeSlice(volume_id = volume, slice_id = slice, gateway_caps=flags, peer_portnum = get_free_port(), replicate_portnum = SYNDICATE_REPLICATE_PORTNUM)
365 def hasPrivateVolume(sliceName):
366 slice = Slice.objects.get(name=sliceName)
367 for vs in VolumeSlice.objects.filter(slice_id=slice):
368 if vs.volume_id.private:
372 def getMountDataSets():
374 for volume in Volume.objects.all():
\r
375 if not volume.private:
\r
376 dataSetInfo.append({'DataSet': volume.name})
\r
380 def getDeploymentSites():
381 deploymentList = Deployment.objects.all()
383 for entry in deploymentList:
384 deploymentInfo.append({'DeploymentSite':entry.name})
385 return deploymentInfo
387 def getSliceInfo(user):
388 sliceList = Slice.objects.all()
389 slicePrivs = SlicePrivilege.objects.filter(user=user)
391 for entry in slicePrivs:
393 slicename = Slice.objects.get(id=entry.slice.id).name
394 slice = Slice.objects.get(name=Slice.objects.get(id=entry.slice.id).name)
395 sliverList=Sliver.objects.all()
397 for sliver in slice.slivers.all():
398 #sites_used['deploymentSites'] = sliver.node.deployment.name
399 # sites_used[sliver.image.name] = sliver.image.name
400 sites_used[sliver.node.site.name] = sliver.numberCores
401 sliceid = Slice.objects.get(id=entry.slice.id).id
403 sliverList = Sliver.objects.filter(slice=entry.slice.id)
406 if x.node.site not in siteList:
407 siteList[x.node.site] = 1
408 slivercount = len(sliverList)
409 sitecount = len(siteList)
411 traceback.print_exc()
415 userSliceInfo.append({'slicename': slicename, 'sliceid':sliceid,
416 'sitesUsed':sites_used,
417 'role': SliceRole.objects.get(id=entry.role.id).role,
418 'slivercount': slivercount,
419 'sitecount':sitecount})
423 def getCDNContentProviderData():
425 for dm_cp in ContentProvider.objects.all():
426 cp = {"name": dm_cp.name,
427 "account": dm_cp.account}
432 def getCDNOperatorData(randomizeData = False, wait=True):
433 HPC_SLICE_NAME = "HyperCache"
435 bq = PlanetStackAnalytics()
437 rows = bq.get_cached_query_results(bq.compose_cached_query(), wait)
439 # wait=False on the first time the Dashboard is opened. This means we might
440 # not have any rows yet. The dashboard code polls every 30 seconds, so it
441 # will eventually pick them up.
444 rows = bq.postprocess_results(rows, filter={"event": "hpc_heartbeat"}, maxi=["cpu"], count=["hostname"], computed=["bytes_sent/elapsed"], groupBy=["Time","site"], maxDeltaTime=80)
446 # dictionaryize the statistics rows by site name
449 stats_rows[row["site"]] = row
453 slice = Slice.objects.filter(name=HPC_SLICE_NAME)
455 slice_slivers = list(slice[0].slivers.all())
460 for site in Site.objects.all():
461 # compute number of slivers allocated in the data model
462 allocated_slivers = 0
463 for sliver in slice_slivers:
464 if sliver.node.site == site:
465 allocated_slivers = allocated_slivers + 1
467 stats_row = stats_rows.get(site.name,{})
469 max_cpu = stats_row.get("max_avg_cpu", stats_row.get("max_cpu",0))
470 cpu=float(max_cpu)/100.0
471 hotness = max(0.0, ((cpu*RED_LOAD) - BLUE_LOAD)/(RED_LOAD-BLUE_LOAD))
473 # format it to what that CDN Operations View is expecting
474 new_row = {"lat": float(site.location.longitude),
475 "long": float(site.location.longitude),
476 "lat": float(site.location.latitude),
478 "numNodes": int(site.nodes.count()),
479 "activeHPCSlivers": int(stats_row.get("count_hostname", 0)), # measured number of slivers, from bigquery statistics
480 "numHPCSlivers": allocated_slivers, # allocated number of slivers, from data model
481 "siteUrl": str(site.site_url),
482 "bandwidth": stats_row.get("sum_computed_bytes_sent_div_elapsed",0),
484 "hot": float(hotness)}
485 new_rows[str(site.name)] = new_row
487 # get rid of sites with 0 slivers that overlap other sites with >0 slivers
488 for (k,v) in new_rows.items():
490 if v["numHPCSlivers"]==0:
491 for v2 in new_rows.values():
492 if (v!=v2) and (v2["numHPCSlivers"]>=0):
493 d = haversine(v["lat"],v["long"],v2["lat"],v2["long"])
501 def getPageSummary(request):
502 slice = request.GET.get('slice', None)
503 site = request.GET.get('site', None)
504 node = request.GET.get('node', None)
506 class SimulatorView(View):
507 def get(self, request, **kwargs):
508 sim = json.loads(file("/tmp/simulator.json","r").read())
509 text = "<html><head></head><body>"
510 text += "Iteration: %d<br>" % sim["iteration"]
511 text += "Elapsed since report %d<br><br>" % sim["elapsed_since_report"]
512 text += "<table border=1>"
513 text += "<tr><th>site</th><th>trend</th><th>weight</th><th>bytes_sent</th><th>hot</th></tr>"
514 for site in sim["site_load"].values():
516 text += "<td>%s</td><td>%0.2f</td><td>%0.2f</td><td>%d</td><td>%0.2f</td>" % \
517 (site["name"], site["trend"], site["weight"], site["bytes_sent"], site["load_frac"])
520 text += "</body></html>"
521 return HttpResponse(text)
523 class DashboardUserSiteView(View):
524 def get(self, request, **kwargs):
525 return HttpResponse(json.dumps(getDashboardContext(request.user, tableFormat=True)), mimetype='application/javascript')
527 class TenantViewData(View):
528 def get(self, request, **kwargs):
529 return HttpResponse(json.dumps(getTenantSliceInfo(request.user, True)), mimetype='application/javascript')
531 def haversine(site_lat, site_lon, lat, lon):
533 if lat and lon and site_lat and site_lon:
534 site_lat = float(site_lat)
535 site_lon = float(site_lon)
539 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)
540 c = 2 * math.atan2( math.sqrt(a), math.sqrt(1 - a) )
545 def siteSortKey(site, slice=None, count=None, lat=None, lon=None):
546 # try to pick a site we're already using
547 has_slivers_here=False
549 for sliver in slice.slivers.all():
550 if sliver.node.site.name == site.name:
551 has_slivers_here=True
554 d = haversine(site.location.latitude, site.location.longitude, lat, lon)
556 return (-has_slivers_here, d)
558 def tenant_pick_sites(user, user_ip=None, slice=None, count=None):
559 """ Returns list of sites, sorted from most favorable to least favorable """
563 client_geo = GeoIP().city(user_ip)
565 lat=float(client_geo["latitude"])
566 lon=float(client_geo["longitude"])
568 print "exception in geo code"
569 traceback.print_exc()
571 sites = Site.objects.all()
572 sites = [x for x in sites if x.name in BLESSED_SITES]
573 sites = sorted(sites, key=functools.partial(siteSortKey, slice=slice, count=count, lat=lat, lon=lon))
577 def slice_increase_slivers(user, user_ip, siteList, slice, count, noAct=False):
580 # let's compute how many slivers are in use in each node of each site
581 for site in siteList:
582 site.nodeList = list(site.nodes.all())
583 for node in site.nodeList:
585 for sliver in node.slivers.all():
586 if sliver.slice.id == slice.id:
587 node.sliverCount = node.sliverCount + 1
589 # Allocate slivers to nodes
590 # for now, assume we want to allocate all slivers from the same site
591 nodes = siteList[0].nodeList
593 # Sort the node list by number of slivers per node, then pick the
594 # node with the least number of slivers.
595 nodes = sorted(nodes, key=attrgetter("sliverCount"))
598 print "adding sliver at node", node.name, "of site", node.site.name
601 sliver = Sliver(name=node.name,
604 image = Image.objects.all()[0],
605 creator = User.objects.get(email=user),
606 deploymentNetwork=node.deployment,
610 node.sliverCount = node.sliverCount + 1
614 sitesChanged[node.site.name] = sitesChanged.get(node.site.name,0) + 1
618 def slice_decrease_slivers(user, siteList, slice, count, noAct=False):
622 siteNames = [site.name for site in siteList]
626 for sliver in slice.slivers.all():
627 if(not siteNames) or (sliver.node.site.name in siteNames):
\r
629 sliverList[sliver.name]=node.name
631 for key in sliverList:
633 sliver = Sliver.objects.filter(name=key)[0]
\r
635 print "deleting sliver",sliverList[key],"at node",sliver.node.name
\r
637 sitesChanged[sliver.node.site.name] = sitesChanged.get(sliver.node.site.name,0) - 1
\r
641 class TenantDeleteSliceView(View):
642 def post(self,request):
\r
643 if request.user.isReadOnlyUser():
\r
644 return HttpResponseForbidden("User is in read-only mode")
\r
645 sliceName = request.POST.get("sliceName",None)
\r
646 slice = Slice.objects.get(name=sliceName)
\r
647 #print slice, slice.id
\r
648 sliceToDel=Slice(name=sliceName, id=slice.id)
\r
650 return HttpResponse("Slice deleted")
652 class TenantAddOrRemoveSliverView(View):
653 """ Add or remove slivers from a Slice
656 siteName - name of site. If not specified, PlanetStack will pick the
658 actionToDo - [add | rem]
659 count - number of slivers to add or remove
660 sliceName - name of slice
661 noAct - if set, no changes will be made to db, but result will still
662 show which sites would have been modified.
665 Dictionary of sites that were modified, and the count of nodes
666 that were added or removed at each site.
668 def post(self, request, *args, **kwargs):
669 siteName = request.POST.get("siteName", None)
670 actionToDo = request.POST.get("actionToDo", None)
671 count = int(request.POST.get("count","0"))
672 sliceName = request.POST.get("slice", None)
673 noAct = request.POST.get("noAct", False)
676 return HttpResponseServerError("No slice name given")
678 slice = Slice.objects.get(name=sliceName)
681 siteList = [Site.objects.get(name=siteName)]
685 if (actionToDo == "add"):
686 user_ip = request.GET.get("ip", get_ip(request))
687 if (siteList is None):
688 siteList = tenant_pick_sites(user, user_ip, slice, count)
690 sitesChanged = slice_increase_slivers(request.user, user_ip, siteList, slice, count, noAct)
691 elif (actionToDo == "rem"):
692 sitesChanged = slice_decrease_slivers(request.user, siteList, slice, count, noAct)
694 return HttpResponseServerError("Unknown actionToDo %s" % actionToDo)
696 return HttpResponse(json.dumps(sitesChanged), mimetype='application/javascript')
698 def get(self, request, *args, **kwargs):
699 request.POST = request.GET
700 return self.post(request, *args, **kwargs) # for testing REST in browser
701 #return HttpResponseServerError("GET is not supported")
703 class TenantPickSitesView(View):
704 """ primarily just for testing purposes """
705 def get(self, request, *args, **kwargs):
706 count = request.GET.get("count","0")
707 slice = request.GET.get("slice",None)
709 slice = Slice.objects.get(name=slice)
710 ip = request.GET.get("ip", get_ip(request))
711 sites = tenant_pick_sites(request.user, user_ip=ip, count=0, slice=slice)
712 sites = [x.name for x in sites]
713 return HttpResponse(json.dumps(sites), mimetype='application/javascript')
715 class DashboardSummaryAjaxView(View):
716 def get(self, request, **kwargs):
720 return float(sum(x))/len(x)
722 sites = getCDNOperatorData().values()
724 sites = [site for site in sites if site["numHPCSlivers"]>0]
726 total_slivers = sum( [site["numHPCSlivers"] for site in sites] )
727 total_bandwidth = sum( [site["bandwidth"] for site in sites] )
728 average_cpu = int(avg( [site["load"] for site in sites] ))
730 result= {"total_slivers": total_slivers,
731 "total_bandwidth": total_bandwidth,
732 "average_cpu": average_cpu}
734 return HttpResponse(json.dumps(result), mimetype='application/javascript')
736 class DashboardAddOrRemoveSliverView(View):
737 # TODO: deprecate this view in favor of using TenantAddOrRemoveSliverView
739 def post(self, request, *args, **kwargs):
740 siteName = request.POST.get("site", None)
741 actionToDo = request.POST.get("actionToDo", "0")
743 siteList = [Site.objects.get(name=siteName)]
744 slice = Slice.objects.get(name="HyperCache")
746 if request.user.isReadOnlyUser():
747 return HttpResponseForbidden("User is in read-only mode")
749 if (actionToDo == "add"):
750 user_ip = request.GET.get("ip", get_ip(request))
751 slice_increase_slivers(request.user, user_ip, siteList, slice, 1)
752 elif (actionToDo == "rem"):
753 slice_decrease_slivers(request.user, siteList, slice, 1)
756 print 'Ask for site: ' + siteName + ' to ' + actionToDo + ' another HPC Sliver'
757 return HttpResponse(json.dumps("Success"), mimetype='application/javascript')
759 class DashboardAjaxView(View):
760 def get(self, request, **kwargs):
761 return HttpResponse(json.dumps(getCDNOperatorData(True)), mimetype='application/javascript')
763 class DashboardAnalyticsAjaxView(View):
764 def get(self, request, name="hello_world", **kwargs):
765 if (name == "hpcSummary"):
766 return HttpResponse(json.dumps(hpc_wizard.get_hpc_wizard().get_summary_for_view()), mimetype='application/javascript')
767 elif (name == "hpcUserSite"):
768 return HttpResponse(json.dumps(getDashboardContext(request.user, tableFormat=True)), mimetype='application/javascript')
769 elif (name == "hpcMap"):
770 return HttpResponse(json.dumps(getCDNOperatorData(True)), mimetype='application/javascript')
771 elif (name == "bigquery"):
772 (mimetype, data) = DoPlanetStackAnalytics(request)
773 return HttpResponse(data, mimetype=mimetype)
775 return HttpResponse(json.dumps("Unknown"), mimetype='application/javascript')
777 class DashboardCustomize(View):
778 def post(self, request, *args, **kwargs):
\r
779 if request.user.isReadOnlyUser():
\r
780 return HttpResponseForbidden("User is in read-only mode")
\r
782 dashboards = request.POST.get("dashboards", None)
\r
786 dashboards = [x.strip() for x in dashboards.split(",")]
\r
787 dashboards = [DashboardView.objects.get(name=x) for x in dashboards]
\r
789 request.user.dashboardViews.all().delete()
\r
791 for i,dashboard in enumerate(dashboards):
\r
792 udbv = UserDashboardView(user=request.user, dashboardView=dashboard, order=i)
\r
795 return HttpResponse(json.dumps("Success"), mimetype='application/javascript')
\r
797 class DashboardSliceInteractions(View):
798 def get(self, request, name="users", **kwargs):
799 colors = ["#005586", "#6ebe49", "orange", "#707170", "#00c4b3", "#077767", "dodgerblue", "#a79b94", "#c4e76a", "red"]
803 slices = list(Slice.objects.all())
805 ids_by_slice = self.build_id_list(slices, name)
807 slices = [x for x in slices if (len(ids_by_slice[x])>0)]
809 for i,slice in enumerate(slices):
810 groups.append({"name": slice.name, "color": colors[i%len(colors)]})
811 row=self.buildMatrix(slice, slices, name, ids_by_slice)
814 result = {"groups": groups, "matrix": matrix}
817 result["title"] = "Slice interactions by user privilege"
818 result["objectName"] = "users"
819 elif name=="networks":
820 result["title"] = "Slice interactions by network membership"
821 result["objectName"] = "networks"
823 result["title"] = "Slice interactions by site ownership"
824 result["objectName"] = "sites"
825 elif name=="sliver_sites":
826 result["title"] = "Slice interactions by sliver sites"
827 result["objectName"] = "sites"
828 elif name=="sliver_nodes":
829 result["title"] = "Slice interactions by sliver nodes"
830 result["objectName"] = "nodes"
832 return HttpResponse(json.dumps(result), mimetype='application/javascript')
834 def build_id_list(self, slices, name):
837 # build up a list of object ids that are used by each slice
838 ids_by_slice[slice] = self.getIds(slice, name)
842 def buildMatrix(self, slice, slices, name, ids_by_slice):
845 # build up a list of object ids that are used by other slices
846 for otherSlice in ids_by_slice.keys():
847 if (slice != otherSlice):
848 for id in ids_by_slice[otherSlice]:
849 if not id in not_only_my_ids:
850 not_only_my_ids.append(id)
852 # build up a list of ids that are used only by the slice, and not
853 # shared with any other slice
855 for id in ids_by_slice[slice]:
856 if id not in not_only_my_ids:
857 only_my_ids.append(id)
860 for otherSlice in ids_by_slice.keys():
861 if (otherSlice == slice):
862 row.append(len(only_my_ids))
864 row.append(self.inCommonIds(ids_by_slice[slice], ids_by_slice[otherSlice]))
868 def getIds(self, slice, name):
871 for sp in slice.slice_privileges.all():
872 if sp.user.id not in ids:
873 ids.append(sp.user.id)
874 elif name=="networks":
875 for sp in slice.networkslice_set.all():
876 if sp.network.id not in ids:
877 ids.append(sp.network.id)
879 ids = [slice.site.id]
880 elif name=="sliver_sites":
881 for sp in slice.slivers.all():
882 if sp.node.site.id not in ids:
883 ids.append(sp.node.site.id)
884 elif name=="sliver_nodes":
885 for sp in slice.slivers.all():
886 if sp.node.id not in ids:
887 ids.append(sp.node.id)
890 def inCommonIds(self, ids1, ids2):
897 def isEmpty(self, slice, name):
898 if (name in ["users", "networks", "sites", "sliver_nodes", "sliver_sites"]):
899 return (len(self.getIds(slice,name)) == 0)