# any local dbfile
*.sqlite3
-# here is a mode to 'record' the backend answers and replay them offline
-offline-*
# the usual useless crap
TAGS
*.pyc
--install-scripts=$(DESTDIR)/$(datadir)/unfold \
--install-data=$(DESTDIR)/$(datadir)/unfold
-#################### third-party layout is managed as art of collectstatic
+#################### third-party layout is managed as part of collectstatic
static: force
./manage.py collectstatic --noinput
rsync -a $(RPMTARBALL) $(DEBTARBALL)
debian.package:
- debuild -uc -us -b
+ debuild --set-envvar PREFIX=/usr -uc -us -b
debian.clean:
$(MAKE) -f debian/rules clean
LOCAL_RSYNC_EXCLUDES := --exclude '*.pyc'
LOCAL_RSYNC_EXCLUDES += --exclude '*.sqlite3' --exclude myslice.ini
LOCAL_RSYNC_EXCLUDES += --exclude static --exclude templates --exclude build
-LOCAL_RSYNC_EXCLUDES += --exclude to-be-integrated --exclude third-party --exclude 'offline*'
+LOCAL_RSYNC_EXCLUDES += --exclude to-be-integrated --exclude third-party
# usual excludes
RSYNC_EXCLUDES := --exclude .git --exclude '*~' --exclude TAGS --exclude .DS_Store $(LOCAL_RSYNC_EXCLUDES)
# make -n will propagate as rsync -n
#################### minimal convenience for pushing work-in-progress in an apache-based depl.
# xxx until we come up with a packaging this is going to be a wild guess
# on debian04 I have stuff in /usr/share/myslice and a symlink in /root/myslice
-INSTALLED_MAIN =/usr/share/unfold
+INSTALLED_MAIN =/usr/share/pyshared
# this is for a debian box
INSTALLED_APACHE =/etc/apache2/sites-available/
@exit 1
else
+$(RSYNC) ./apache/myslice.conf $(SSHURL)/$(INSTALLED_APACHE)/
- +$(RSYNC) ./apache/init-ssl.sh ./apache/init-ssl.py $(SSHURL)/$(bindir)/
+ +$(RSYNC) ./apache/unfold-init-ssl.sh $(SSHURL)/$(bindir)/
endif
restart:
+# xxx it might be smarter to install wsgi.py in some other location
+# so we don't have to hard-wire these paths here
<VirtualHost *:80>
- WSGIScriptAlias / /usr/share/unfold/myslice/wsgi.py
+ WSGIScriptAlias / /usr/lib/python2.7/dist-packages/myslice/wsgi.py
<Directory /usr/share/unfold/myslice>
<Files wsgi.py>
Order deny,allow
# this to be optional on that port
<VirtualHost *:443>
- WSGIScriptAlias / /usr/share/unfold/myslice/wsgi.py
+ WSGIScriptAlias / /usr/lib/python2.7/dist-packages/myslice/wsgi.py
<Directory /usr/share/unfold/apache>
<Files myslice.wsgi>
Order deny,allow
Priority: optional
Standards-Version: 3.9.2
Build-Depends: devscripts, debhelper (>=7.0.50~), debconf, dpatch, python-setuptools, make, python-django
+X-Python-Version: >= 2.7
Package: myslice
Architecture: any
-usr/share/unfold/portal
+usr/lib*/python*/dist-packages/portal
# -*- makefile -*-
%:
- dh $@
+ dh $@ --with python2 --buildsystem=python_distutils
+usr/lib*/python*/dist-packages/auth
+usr/lib*/python*/dist-packages/insert_above
+usr/lib*/python*/dist-packages/manifold
+usr/lib*/python*/dist-packages/plugins
+usr/lib*/python*/dist-packages/unfold
+usr/lib*/python*/dist-packages/ui
+usr/lib*/python*/dist-packages/myslice
+usr/lib*/python*/dist-packages/sample
usr/share/unfold/static
usr/share/unfold/templates
-usr/share/unfold/auth
-usr/share/unfold/insert_above
-usr/share/unfold/manifold
-usr/share/unfold/plugins
-usr/share/unfold/unfold
-usr/share/unfold/ui
-usr/share/unfold/myslice
-usr/share/unfold/sample
manage.py usr/share/unfold/
apache/myslice.conf /etc/apache2/sites-available
print "====> ManifoldAPI.%s"%repr(),"url",self.url
# No password in the logs
logAuth = copy.copy(self.auth)
- if 'AuthString' in logAuth:
- logAuth['AuthString']="XXX"
+ for obfuscate in ['Authring','session']:
+ if obfuscate in logAuth: logAuth[obfuscate]="XXX"
print "=> auth",logAuth
print "=> args",args,"kwds",kwds
annotations = {
debug_empty=False
#debug_empty=True
-# Historically we had a feature for developing without an Internet connection
-# However this won't work anymore as the python layer itself does manifold calls
-# before javascript has a chance to do so.
-# Might still come in handy if you want the fastest possible (locally cached) feedback
-# beware that this is very rough though...
-work_offline=False
-#work_offline=True
-
# this view is what the javascript talks to when it sends a query
# see also
# myslice/urls.py
manifold_query = Query()
#manifold_query = ManifoldQuery()
manifold_query.fill_from_POST(request.POST)
- offline_filename="%s/../offline-%s-%s.json"%(os.path.dirname(__file__),manifold_query.action,manifold_query.object)
# retrieve session for request
# We allow some requests to use the ADMIN user account
json_answer=json.dumps({'code':0,'value':[]})
print "By-passing : debug_empty & 'get' request : returning a fake empty list"
return HttpResponse (json_answer, mimetype="application/json")
- ### patch : return the latest one..
- if work_offline:
- # if that won't work then we'll try to update anyways
- try:
- with (file(offline_filename,"r")) as f:
- json_answer=f.read()
- print "By-passing : using contents from %s"%offline_filename
- return HttpResponse (json_answer, mimetype="application/json")
- except:
- import traceback
- traceback.print_exc()
- print "Could not run in offline mode, PROCEEDING"
- pass
# actually forward
manifold_api= ManifoldAPI(auth=manifold_api_session_auth)
result [ 'description' ] = [ ResultValue.to_html (x) for x in result['description'] ]
json_answer=json.dumps(result)
- # if in debug mode we save this so we can use offline mode later
- if debug:
- with (file(offline_filename,"w")) as f:
- f.write(json_answer)
# this is an artificial delay added for debugging purposes only
if debug_spin>0:
debug=False
debug=True
-# turn this on if you want to work offline
-work_offline=False
-#work_offline=True
-
class MetaData:
def __init__ (self, auth):
self.hash_by_object={}
def fetch (self, request):
- offline_filename="%s/../offline-metadata.json"%os.path.dirname(__file__)
- if work_offline:
- try:
- with file(offline_metadata) as f:
- self.hash_by_object=json.loads(f.read())
- return
- except:
- print "metadata.work_offline: failed to decode %s"%offline_filename
manifold_api = ManifoldAPI(self.auth)
fields = ['table', 'column.name', 'column.qualifier', 'column.type',
'column.is_array', 'column.description', 'column.default', 'key', 'capability']
# print "Failed to retrieve metadata",rows_result.error()
# rows=[]
self.hash_by_object = dict ( [ (row['table'], row) for row in rows ] )
- # save for next time we use offline mode
- if debug and rows:
- with file(offline_filename,'w') as f:
- f.write(json.dumps(self.hash_by_object))
def to_json(self):
return json.dumps(self.hash_by_object)
parser.set ('manifold', 'url', Config.default_manifold_url)
parser.set ('manifold', 'admin_user', Config.default_manifold_admin_user)
parser.set ('manifold', 'admin_password', Config.default_manifold_admin_password)
+ parser.add_section('googlemap')
+ parser.set ('googlemap','api_key', None)
parser.read (os.path.join(ROOT,'myslice/myslice.ini'))
self.config_parser=parser
return (self.config_parser.get('manifold','admin_user'),
self.config_parser.get('manifold','admin_password'))
+ def googlemap_api_key (self):
+ return self.config_parser.get('googlemap','api_key')
+
# exporting these details to js
def manifold_js_export (self):
return "var MANIFOLD_URL = '%s';\n"%self.manifold_url();
import traceback
traceback.print_exc()
-if not ROOT:
- raise Exception,"Cannot find ROOT for myslice"
+if os.path.isdir(os.path.join(ROOT,"static")):
+ DATAROOT=ROOT
+else:
+ DATAROOT="/usr/share/unfold"
+ if not os.path.isdir(os.path.join(DATAROOT,"static")):
+ DATAROOT=None
+
+if not ROOT: raise Exception,"Cannot find ROOT for myslice"
+if not DATAROOT: raise Exception,"Cannot find DATAROOT for myslice"
####################
ADMINS = (
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
- 'NAME': os.path.join(ROOT,'myslice.sqlite3'), # Or path to database file if using sqlite3.
+ 'NAME': os.path.join(DATAROOT,'myslice.sqlite3'), # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
-STATIC_ROOT = os.path.join(ROOT,'static')
+STATIC_ROOT = os.path.join(DATAROOT,'static')
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
- os.path.join(ROOT,"templates"),
+ os.path.join(DATAROOT,"templates"),
)
INSTALLED_APPS = (
# 'django.contrib.admindocs',
'portal',
# temporary - not packaged
- 'trash',
+ # 'trash',
'sample',
# DEPRECATED # 'django.contrib.formtools',
# DEPRECATED ## 'crispy_forms',
#
# various trash views - bound to go away
#
- url(r'^trash/', include('trash.urls')),
+# url(r'^trash/', include('trash.urls')),
)
import os
import sys
-path = '/usr/share/unfold'
-if path not in sys.path:
- sys.path.append(path)
-
os.environ['DJANGO_SETTINGS_MODULE'] = 'myslice.settings'
import django.core.handlers.wsgi
class GoogleMap (Plugin):
- # set checkboxes if a final column with checkboxes is desired
- # pass columns as the initial set of columns
- # if None then this is taken from the query's fields
+ # expcted input are
+ # query : query about the slice
+ # query_all : query about all resources
+ # googlemap_key : mandatory googlemap API v3 key
# latitude,longitude, zoom : the starting point
- def __init__ (self, query, query_all = None, latitude=43., longitude=7., zoom=4, **settings):
+ # apparently at some point there has been support for a boolean 'checkboxes' input arg but seems dropped
+ def __init__ (self, query, query_all, googlemap_api_key=None, latitude=43., longitude=7., zoom=4, **settings):
Plugin.__init__ (self, **settings)
self.query=query
self.query_all = query_all
+ self.googlemap_api_key=googlemap_api_key
self.query_all_uuid = query_all.query_uuid if query_all else None
self.latitude=latitude
self.longitude=longitude
return env
def requirements (self):
+ googlemap_api_url = "https://maps.googleapis.com/maps/api/js?"
+ if self.googlemap_api_key: googlemap_api_url+="key=%s&"%self.googlemap_api_key
+ googlemap_api_url += "sensor=false"
reqs = {
- 'js_files' : [ "https://maps.googleapis.com/maps/api/js?sensor=false",
+ # let users configure their googlemap API key in production deployements
+ 'js_files' : [ googlemap_api_url,
"/js/googlemap.js",
"/js/markerclusterer.js",
"js/manifold.js", "js/manifold-query.js",
"js/spin.presets.js", "js/spin.min.js", "js/jquery.spin.js",
"js/three.min.js", "js/jquery-mousewheel.min.js", "js/map.js",
],
- 'css_files': [ "css/map.css",
+ 'css_files': [ "css/senslabmap.css",
],
}
return reqs
+++ /dev/null
-canvas {
- border:1px gray solid;
- background-color: #202020;
- margin: 10px;
-}
\ No newline at end of file
-.senslabmap {
- margin: 10px;
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
- font-size: 13px;
- line-height: 18px;
- color: #333333;
- background-color: #ffffff;
-}
-
-#div3d {
- height: 500px;
+#maps-container canvas {
+ border:1px gray solid;
background-color: #202020;
- z-index:-1
-}
-
-#selectionbox {
- text-align: center;
- padding:2px
-}
-
-#infobox {
- text-align: center
-}
-
-#node_alive {
- background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAFRQAABUUBbA3bdwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAFHSURBVDiNtdSxSkJxFMfx7znVtZS2wFdIaLHBpcUl4UYPkRQNCU7hQ0RTYiAk9RDRhRpqaXHIJbBXEJwErXuj/2lJK60ovP3G/+F8/mf6iZkxnnIgib4ubIKsmpAFsm+jlhgtsLuUezw/8i0c35VxcOsquabGCcjyxE+fYg9O2DlbH9x+CRZvZJ4weSjCHiA/Y++qGcckBvuneXsCmB1ONEoemFD6JTQ6SISSREkHlEcXbl+mfIOLP2KfZdhoFPqB7F4vLj1HL/dAehoQ6Mx5Mysahc6PAQNIR6HzVdRyMWAAiFpOzYgNNCOngmXiAgXLqCHtuEBD2ipCMy5QhKaak9hAc9JUL6EB0InB63gJDbSe73UFitNqAsV6vtdVgEahHwhUp8CqjUI/ANDho/MGFTNqwGRBfh8zo+a8QWWE/1sffsw0jf0KmsOTrB0wIw8AAAAASUVORK5CYII=');
-
-}
-
-#node_down {
- background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAFRQAABUUBbA3bdwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAEqSURBVDiNtdSxSkJxFMfx7zkGtQgKgU8gJLRcBZcmxxu9hNCU0BQ9RLSJTT1GdEenFrn87xIY+AQXhCu41OA9DdZNNMLy3288f87n/5uOmBkbqdf3KZfPMGsCAWYBACIJkCDimM8fmEze1ldlAwyCE8zuETna/GklZi+InJMkT9+Dnc4Bs9ktcAHIj9gKC9xRqVwxHL4C7BVPWXaDSG9LqCgE9MiyHLj8athshpg9/hJbo+UU5yKxVuuQxeIZqO0EQkqpdKzkeegBA6iR56ECbQ/YZ9qKmT/QrK1AwxsIDQXGHsGxIjLyxomMFPAHwkhRjYDUA5aiGilxPEWkuzMn0iWOpwqAcxFm/T9jZn2ciwC0GFar18CA5QXZmgIGH7vLov93D1ezw8V+B8jhfgJI7kYcAAAAAElFTkSuQmCC');
-}
-
-#node_selected {
- background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAFRQAABUUBbA3bdwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAE0SURBVDiNtdS/SoJxFMbx7zn0xyGhIfAGGhJaTHFpaTW6iISUSGqKLiLaxChq6CKid21pEcklsKEbEBqCGizhfRrMF9SiP+/bM57D+fzO8OOYJMZj9YdZUk8biBXwHCj30WlD2Ma4pTd/qd3F14nZcdBOWqu4nQNLEy+N5p5QW9ou3HwK2sV1ire5I7AdwL7BhhHomJmXfW2u9QCmolY/fQjUfghFC4HV6KdDYC/a0M5aJWRXv8TGaK2rUgiM09YCcAdkYoHQBZYdUykBDCCDqeTIiwlgg8iLjik50FR0RDYxUGQdo5MYaHQcWTMxUNZ0LEwOtLDpyAIGfyhuusgCVzX/iKkcmzOVVc0/OoAqhQCj/neMuiqFAMCj4vTzAagBTB7IryNQYzA7XPS/7uFIMcbFfgcJcoL5SKOsjQAAAABJRU5ErkJggg==');
-}
-
-#node_used {
- background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAABHNCSVQICAgIfAhkiAAAAZJJREFUOI2t1D1LQlEcx/Hf+R/NTMKsawldqRZ7JDBIhyAIpwu9A6egpmrsbUQQ1FDQJL2B4E49LC0OuUQPToUKehFTosy6x9OQF8qiQu93Ohw4n7P9WDQaxQ+53Kx70Uv9MwEaDg85JsIAcG9epfL1u1SlblxU5eMRgFrzQ9YMOtAxt+CK7wedobGffrLKvKVvTmuJZROv55/vuaqq1rlzmE9tLXpWd33c7/8NAwAv71MmO+aXKsLwl6VxAsD8Ag7xqc2YO75GIPYXZkUgNuKcjpREwVuRhv5xB8DFurSYO77+X6i5mDu+7mJdmgUqWufKQauYVcNQyMN6tF4eGGgX7OWBAQ/r0UghNdIuZqWQGqGgY9Q2MOgYjdAgD43bBQ7y0DjlRPraLjAn0teUMW+TdoEZ8zZJxXrWNrBYzybpSZb1ksgX2sVKIl94kmWdABT1l72ldsGGUSQAqMln/bia2G4VO64mtmvyWQc+jUNFGqcPouALOidn/zsQJoQ8qx7u3IvLDTTWxvY9/AY2anmx3wGj5aLJgOrlPgAAAABJRU5ErkJggg==');
-}
+ margin: 10px;
+}
\ No newline at end of file
if (info && info[2] == "iot-lab" && info[3] == "info") {
node.arch = info[0].split("-")[0];
- node.id = info[0].split("-")[1];
+ node.id = parseInt(info[0].split("-")[1]);
node.site = info[1];
node.normalized = true;
}
},
createMaps: function($container, sites, nodes) {
var maps = {};
+ var $menu = $("<ul id='sites-tabs' class='nav nav-tabs' data-tabs='sites-tabs'/>").appendTo($container);
+ var $maps = $("<div id='maps' class='tab-content' />").appendTo($container);
+
$.each(sites, function(i, site) {
- var $div = $("<div />").appendTo($container);
- maps[site] = new Senslab.Map($div);
+ var entry = $("<li><a href='#" + site + "' data-toggle='tab'>" + site + "</a></li>").appendTo($menu);
+ var $tab = $("<div class='tab-pane' id='" + site + "' />").appendTo($maps);
+ maps[site] = new Senslab.Map($tab);
maps[site].addNodes(nodes[site]);
});
+
+ $menu.find("li").eq(0).addClass("active");
+ $maps.find("div").eq(0).addClass("active");
+
+ if (!sites.length) {
+ $container.text("No nodes to display.");
+ }
}
};
},
on_all_new_record: function(node) {
- Senslab.normalize(node, this.key);
+ Senslab.normalize(node);
if (node.normalized) {
var site = node.site;
if ($.inArray(site, this.sites) == -1) {
-<div id="maps-container" oncontextmenu="return false;"></div>
-<script>
-$(function() {
- $.getJSON("nodes.json", function(all_nodes) {
- var sites = [], maps = {}, nodes = {};
-
- $.each(all_nodes, function(i, node) {
- Senslab.normalize(node);
- var site = node.site;
- if (site) {
- if ($.inArray(site, sites) == -1) {
- sites.push(site);
- nodes[site] = [];
- }
- nodes[site].push(node);
- } else {
- console.warn("Node " + node + " has no site");
- }
- });
-
- $container = $('#maps-container');
-
- $.each(sites, function(i, site) {
- var $div = $("<div />").appendTo($container);
- maps[site] = new Senslab.Map($div);
- maps[site].addNodes(nodes[site]);
- });
- });
-});
-</script>
\ No newline at end of file
+<div id="maps-container" oncontextmenu="return false;"></div>
\ No newline at end of file
-from manifold.core.query import Query
-from unfold.page import Page
+from manifold.core.query import Query
+from unfold.page import Page
-from unfold.loginrequired import FreeAccessView
-from ui.topmenu import topmenu_items, the_user
+from unfold.loginrequired import FreeAccessView
+from ui.topmenu import topmenu_items, the_user
-from plugins.googlemap import GoogleMap
-from plugins.querytable import QueryTable
-from plugins.lists.simplelist import SimpleList
-from plugins.slicestat import SliceStat
+from plugins.googlemap import GoogleMap
+from plugins.querytable import QueryTable
+from plugins.lists.simplelist import SimpleList
+from plugins.slicestat import SliceStat
+
+from myslice.config import Config
# View for 1 platform and its details
class ResourceView(FreeAccessView):
togglable = True,
query = resource_query,
query_all = resource_query,
+ googlemap_api_key = Config().googlemap_api_key(),
checkboxes = False,
# center on Paris
#latitude = 49.,
togglable = False,
query = sq_resource,
query_all = query_resource_all,
+ googlemap_api_key = Config().googlemap_api_key(),
checkboxes = True,
# center on Paris
latitude = 49.,
packages= [ os.path.dirname(init) for init in (glob("*/__init__.py")+glob("*/*/__init__.py")) ]
setup(packages = packages,
+ # xxx somehow this does not seem to show up in debian packaging
scripts = [ 'apache/unfold-init-ssl.sh' ],
data_files = [
- ( 'static/js', glob ('static/js/*')),
- ( 'static/css', glob ('static/css/*')),
- ( 'static/img', glob ('static/img/*')),
- ( 'static/fonts', glob ('static/fonts/*')),
- ( 'templates', glob ('templates/*')),
+ ( '/usr/share/unfold/static/js', glob ('static/js/*')),
+ ( '/usr/share/unfold/static/css', glob ('static/css/*')),
+ ( '/usr/share/unfold/static/img', glob ('static/img/*')),
+ ( '/usr/share/unfold/static/fonts', glob ('static/fonts/*')),
+ ( '/usr/share/unfold/templates', glob ('templates/*')),
( 'apache', [ 'apache/myslice.conf' ]),
])