From 06d2c03f5287505bdc5ad7ff3726fdeebf10dda8 Mon Sep 17 00:00:00 2001 From: Siobhan Tully <stully@verivue.com> Date: Sun, 23 Feb 2014 23:48:52 -0500 Subject: [PATCH] Added in ajax support for refreshing hpcdashboard view based on polling - without having to redraw/refresh page. --- planetstack/core/plus/sites.py | 6 +- planetstack/core/plus/views.py | 331 +++++++++--------- .../templates/admin/dashboard/welcome.html | 106 ++++-- 3 files changed, 262 insertions(+), 181 deletions(-) diff --git a/planetstack/core/plus/sites.py b/planetstack/core/plus/sites.py index da86a10..27ae352 100644 --- a/planetstack/core/plus/sites.py +++ b/planetstack/core/plus/sites.py @@ -12,13 +12,15 @@ class AdminMixin(object): def get_urls(self): """Add our dashboard view to the admin urlconf. Deleted the default index.""" from django.conf.urls import patterns, url - from views import DashboardWelcomeView + from views import DashboardWelcomeView, DashboardAjaxView urls = super(AdminMixin, self).get_urls() del urls[0] custom_url = patterns('', url(r'^$', self.admin_view(DashboardWelcomeView.as_view()), - name="index") + name="index"), + url(r'^hpcdashboard/', self.admin_view(DashboardAjaxView.as_view()), + name="hpcdashboard") ) return custom_url + urls diff --git a/planetstack/core/plus/views.py b/planetstack/core/plus/views.py index b49e3a3..653ee95 100644 --- a/planetstack/core/plus/views.py +++ b/planetstack/core/plus/views.py @@ -1,177 +1,196 @@ #views.py -from django.views.generic import TemplateView +from django.views.generic import TemplateView, View +import datetime +import json from core.models import Slice,SliceRole,SlicePrivilege,Site,Reservation +from django.http import HttpResponse + class DashboardWelcomeView(TemplateView): template_name = 'admin/dashboard/welcome.html' def get(self, request, *args, **kwargs): context = self.get_context_data(**kwargs) - sliceList = Slice.objects.all() try: site = Site.objects.filter(id=request.user.site.id) except: site = Site.objects.filter(name="Princeton") context['site'] = site[0] - slicePrivs = SlicePrivilege.objects.filter(user=request.user) - userSliceInfo = [] - for entry in slicePrivs: + context['userSliceInfo'] = getSliceInfo(request, context) + context['cdnData'] = getCDNOperatorData(); + return self.render_to_response(context=context) - try: - reservationList = Reservation.objects.filter(slice=entry.slice) - reservations = (True,reservationList) +def getSliceInfo(request, context): + sliceList = Slice.objects.all() + slicePrivs = SlicePrivilege.objects.filter(user=request.user) + userSliceInfo = [] + for entry in slicePrivs: - except: - reservations = None + try: + reservationList = Reservation.objects.filter(slice=entry.slice) + reservations = (True,reservationList) - userSliceInfo.append({'slice': Slice.objects.get(id=entry.slice.id), - 'role': SliceRole.objects.get(id=entry.role.id).role, - 'reservations': reservations}) + except: + reservations = None + + userSliceInfo.append({'slice': Slice.objects.get(id=entry.slice.id), + 'role': SliceRole.objects.get(id=entry.role.id).role, + 'reservations': reservations}) + return userSliceInfo + + +def getCDNOperatorData(randomizeData = False): + cdnData = { + "Arizona": { + "lat": 32.2333, + "long": -110.94799999999998, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 2, + "siteUrl": "http://www.cs.arizona.edu/" + }, + "I2 Singapore": { + "lat": 1.33544, + "long": 103.88999999999999, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 5, + "siteUrl": "http://www.internet2.edu/" + }, + "ON.Lab": { + "lat": 37.452955, + "long": -122.18176599999998, + "health": 0, + "numNodes": 45, + "numHPCSlivers": 12, + "siteUrl": "http://www.onlab.us/" + }, + "I2 Washington DC": { + "lat": 38.009, + "long": -77.00029999999998, + "health": 0, + "numNodes": 50, + "numHPCSlivers": 7, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Seattle": { + "lat": 47.6531, + "long": -122.31299999999999, + "health": 0, + "numNodes": 100, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Salt Lake City": { + "lat": 40.7659, + "long": -111.844, + "health": 0, + "numNodes": 35, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 New York": { + "lat": 40.72, + "long": -73.99000000000001, + "health": 0, + "numNodes": 25, + "numHPCSlivers": 4, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Los Angeles": { + "lat": 33.2505, + "long": -117.50299999999999, + "health": 0, + "numNodes": 20, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Kansas City": { + "lat": 39.0012, + "long": -94.00630000000001, + "health": 0, + "numNodes": 17, + "numHPCSlivers": 8, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Houston": { + "lat": 29.0077, + "long": -95.00369999999998, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Chicago": { + "lat": 41.0085, + "long": -87.00650000000002, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "I2 Atlanta": { + "lat": 33.0075, + "long": -84.00380000000001, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.internet2.edu/" + }, + "MaxPlanck": { + "lat": 49.14, + "long": 6.588999999999942, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.mpi-sws.mpg.de/" + }, + "GeorgiaTech": { + "lat": 33.7772, + "long": -84.39760000000001, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.gatech.edu/" + }, + "Princeton": { + "lat": 40.3502, + "long": -74.6524, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://princeton.edu/" + }, + "Washington": { + "lat": 47.6531, + "long": -122.31299999999999, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "https://www.washington.edu/" + }, + "Stanford": { + "lat": 37.4294, + "long": -122.17200000000003, + "health": 0, + "numNodes": 15, + "numHPCSlivers": 10, + "siteUrl": "http://www.stanford.edu/" + }, + } + + if randomizeData: + cdnData["Siobhan"] = { "lat": 43.34203, "long": -70.56351, "health": 10, "numNodes": 5, "numHPCSlivers": 3, "siteUrl": "https:devonrexes"} + del cdnData["Princeton"] + cdnData["I2 Seattle"]['siteUrl'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + cdnData["I2 Salt Lake City"]["numHPCSlivers"] = 34 - context['userSliceInfo'] = userSliceInfo - context['cdnData'] = self.getCDNOperatorData(); - return self.render_to_response(context=context) - def getCDNOperatorData(self): - cdnData = { - "Arizona": { - "lat": 32.2333, - "long": -110.94799999999998, - "health": 0, - "numNodes": 15, - "numHPCSlivers": 2, - "siteUrl": "http://www.cs.arizona.edu/" - }, - "I2 Singapore": { - "lat": 1.33544, - "long": 103.88999999999999, - "health": 0, - "numNodes": 15, - "numHPCSlivers": 5, - "siteUrl": "http://www.internet2.edu/" - }, - "ON.Lab": { - "lat": 37.452955, - "long": -122.18176599999998, - "health": 0, - "numNodes": 45, - "numHPCSlivers": 12, - "siteUrl": "http://www.onlab.us/" - }, - "I2 Washington DC": { - "lat": 38.009, - "long": -77.00029999999998, - "health": 0, - "numNodes": 50, - "numHPCSlivers": 7, - "siteUrl": "http://www.internet2.edu/" - }, - "I2 Seattle": { - "lat": 47.6531, - "long": -122.31299999999999, - "health": 0, - "numNodes": 100, - "numHPCSlivers": 10, - "siteUrl": "http://www.internet2.edu/" - }, - "I2 Salt Lake City": { - "lat": 40.7659, - "long": -111.844, - "health": 0, - "numNodes": 35, - "numHPCSlivers": 10, - "siteUrl": "http://www.internet2.edu/" - }, - "I2 New York": { - "lat": 40.72, - "long": -73.99000000000001, - "health": 0, - "numNodes": 25, - "numHPCSlivers": 4, - "siteUrl": "http://www.internet2.edu/" - }, - "I2 Los Angeles": { - "lat": 33.2505, - "long": -117.50299999999999, - "health": 0, - "numNodes": 20, - "numHPCSlivers": 10, - "siteUrl": "http://www.internet2.edu/" - }, - "I2 Kansas City": { - "lat": 39.0012, - "long": -94.00630000000001, - "health": 0, - "numNodes": 17, - "numHPCSlivers": 8, - "siteUrl": "http://www.internet2.edu/" - }, - "I2 Houston": { - "lat": 29.0077, - "long": -95.00369999999998, - "health": 0, - "numNodes": 15, - "numHPCSlivers": 10, - "siteUrl": "http://www.internet2.edu/" - }, - "I2 Chicago": { - "lat": 41.0085, - "long": -87.00650000000002, - "health": 0, - "numNodes": 15, - "numHPCSlivers": 10, - "siteUrl": "http://www.internet2.edu/" - }, - "I2 Atlanta": { - "lat": 33.0075, - "long": -84.00380000000001, - "health": 0, - "numNodes": 15, - "numHPCSlivers": 10, - "siteUrl": "http://www.internet2.edu/" - }, - "MaxPlanck": { - "lat": 49.14, - "long": 6.588999999999942, - "health": 0, - "numNodes": 15, - "numHPCSlivers": 10, - "siteUrl": "http://www.mpi-sws.mpg.de/" - }, - "GeorgiaTech": { - "lat": 33.7772, - "long": -84.39760000000001, - "health": 0, - "numNodes": 15, - "numHPCSlivers": 10, - "siteUrl": "http://www.gatech.edu/" - }, - "Princeton": { - "lat": 40.3502, - "long": -74.6524, - "health": 0, - "numNodes": 15, - "numHPCSlivers": 10, - "siteUrl": "http://princeton.edu/" - }, - "Washington": { - "lat": 47.6531, - "long": -122.31299999999999, - "health": 0, - "numNodes": 15, - "numHPCSlivers": 10, - "siteUrl": "https://www.washington.edu/" - }, - "Stanford": { - "lat": 37.4294, - "long": -122.17200000000003, - "health": 0, - "numNodes": 15, - "numHPCSlivers": 10, - "siteUrl": "http://www.stanford.edu/" - }, - } - return cdnData + return cdnData +class DashboardAjaxView(View): + def get(self, request, **kwargs): + return HttpResponse(json.dumps(getCDNOperatorData(True)), mimetype='application/javascript') + diff --git a/planetstack/templates/admin/dashboard/welcome.html b/planetstack/templates/admin/dashboard/welcome.html index bec703d..8df5f10 100644 --- a/planetstack/templates/admin/dashboard/welcome.html +++ b/planetstack/templates/admin/dashboard/welcome.html @@ -23,6 +23,7 @@ {% endfor %} </table> <script type="text/javascript" src="{% static 'log4javascript-1.4.6/log4javascript.js' %}"></script> +<div id="HPCDashboard"> <h1>HPC Dashboard</h1> <span id="hpcSummary"> <span class="summary-attr"><b>Active Slivers:</b> 78 </span> @@ -31,12 +32,14 @@ </span> <div id="map-us" ></div> +</div> <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" /> <script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script> <script src="{% static 'js/Leaflet.MakiMarkers.js' %}" > </script> <script> + var consoleAppender = new log4javascript.BrowserConsoleAppender(); var patternLayout = new log4javascript.PatternLayout("%d{HH:mm:ss,SSS} %l{s:l} %-5p - %m{1}%n"); consoleAppender.setLayout(patternLayout); @@ -45,7 +48,6 @@ var log = log4javascript.getRootLogger(); log.addAppender(consoleAppender); log.setLevel(log4javascript.Level.ALL); - L.Map = L.Map.extend({ openPopup: function(popup) { this._popup = popup; @@ -72,43 +74,99 @@ log.info( data ); for ( var key in data ) { arrayOfLatLngs.push([data[key]['lat'],data[key]['long']]); log.info( arrayOfLatLngs ); + + data[key]['marker'] = L.marker([data[key]['lat'], data[key]['long']], {icon: getIcon(data[key]['numNodes'], data[key]['numHPCSlivers']) }); + data[key]['marker'].addTo(map).bindPopup(setPopupVals(key, data[key])); + +} +var bounds = new L.LatLngBounds(arrayOfLatLngs); +map.fitBounds(bounds); + +var popup = L.popup(); + + +function setPopupVals (site, siteData) { + var retVal = '<span class="SiteDetail"><b>' + site + '</b></span>' + + '</br><a href="' + siteData['siteUrl'] + '">' + siteData['siteUrl'] + '</a>' + + '</br><b>Available Nodes: </b>' + siteData['numNodes'] + + '</br><b>Active HPC Slivers: </b>' + siteData['numHPCSlivers'] + + '</br><span id="addSlivers">Add HPC Slivers</span>' + + '<span id="remSlivers">Remove HPC Slivers</span>' ; + + return retVal; +} +function getIcon(numNodes, numHPCSlivers, currentBW) { var colorChoices = ["#007FFF", "#0000FF", "#7f00ff", "#FF00FF", "#FF007F", "#FF0000"]; - var ratio = data[key]['numHPCSlivers']/data[key]['numNodes'] * 100; + var ratio = (numHPCSlivers/numNodes) * 100; var numColors = colorChoices.length; var colorBands = 100/numColors; - log.info("numColors: " + numColors); - log.info("colorBands: " + colorBands); - log.info("ratio: " + ratio); - - //Algorithm for color tone should consider the number of available nodes + //Algorithm for color tone should consider the number of available nodes // on the site, and then how much the current dedicated nodes are impacted //var iconColor = 0; - var iconColor = 0; - for (;iconColor < numColors; iconColor ++) { - if (ratio < colorBands * iconColor+1) { + var iconColor = 5; + for (colorBand = 0; colorBand < numColors; colorBand ++) { + if (ratio < colorBands * colorBand+1) { + iconColor = colorBand break; } } - + var icon = L.MakiMarkers.icon({icon: "star-stroked", color: colorChoices[iconColor] , size: "s"}); + return icon; +} - L.marker([data[key]['lat'], data[key]['long']], {icon: icon}).addTo(map) - .bindPopup( '<span class="SiteDetail"><b>' + key + '</b></span>' + - '</br><a href="' + data[key]['siteUrl'] + '">' + data[key]['siteUrl'] + '</a>' + - '</br><b>Available Nodes: </b>' + data[key]['numNodes'] + - '</br><b>Active HPC Slivers: </b>' + data[key]['numHPCSlivers'] + - '</br><span id="addSlivers">Add HPC Slivers</span>' + - '<span id="remSlivers">Remove HPC Slivers</span>' + - - '');//.openPopup(); +function updateMaps() { + log.info("Attempting to update Maps"); + $.ajax({ + url : '/hpcdashboard', + dataType : 'json', + type : 'GET', + success: function(newData) + { + log.info("Successfully got data back..."); + log.info(newData); + log.info("Still have old data too"); + log.info(data); + updateMapData(newData); + } +}); + setTimeout(updateMaps, 45000) } -var bounds = new L.LatLngBounds(arrayOfLatLngs); -map.fitBounds(bounds); -var popup = L.popup(); +function updateMapData(newData) { + for ( site in newData ) { + var isNewSite = false; + //check to see if the site is new or not + if (site in data) { + log.info("Site " + site + " already mapped"); + //take ownership of marker + newData[site]['marker'] = data[site]['marker']; + delete data[site]; + newData[site]['marker'].setIcon(getIcon(newData[site]['numNodes'], newData[site]['numHPCSlivers'])); + // workaround, markers currently don't have a setPopup Content method -- so have to grab object directly + newData[site]['marker']._popup.setContent(setPopupVals(site, newData[site])); + } + else { + isNewSite = true; + log.info("New Site detected: " + site); + newData[site]['marker'] = L.marker([newData[site]['lat'], newData[site]['long']], + {icon: getIcon(newData[site]['numNodes'], newData[site]['numHPCSlivers']) }); + newData[site]['marker'].addTo(map).bindPopup(setPopupVals(site, newData[site])); //.openPopup(); + log.info("Should have added the new site"); + + } + } + + // Anything still in data needs to be removed since it is no longer a valid site + for (remSite in data) { + log.warn("Site: " + remSite + " is no longer valid, removing from map"); + map.removeLayer(data[remSite]['marker']); + } + data = newData; +} function onMapClick(e) { popup @@ -117,5 +175,7 @@ function onMapClick(e) { .openOn(map); } +setTimeout(updateMaps, 5000) + </script> {% endblock %} -- 2.47.0