From: Javier García Date: Mon, 1 Dec 2014 12:09:54 +0000 (+0100) Subject: Merge branch 'onelab' of ssh://git.onelab.eu/git/myslice into onelab X-Git-Tag: myslice-1.1~26 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=3b39e97b04f9333fd58978120f00c1b4ffffbc41;hp=3aae671a1ca0cef870a268b88ddcde8d520d7621;p=myslice.git Merge branch 'onelab' of ssh://git.onelab.eu/git/myslice into onelab --- diff --git a/README b/README index 4e0b4716..b1f201da 100644 --- a/README +++ b/README @@ -11,7 +11,7 @@ See the devel/ subdir for more devel-oriented doc. ** see devel/django-install.txt in case of trouble $ apt-get install python-django $ apt-get install python-django-south -$ apt-get install python-pip +$ apt-get install python-pip or sudo easy_install pip==1.4.1 $ pip install requests $ pip install djangorestframework * git clone git://git.onelab.eu/myslice.git diff --git a/activity/__init__.py b/activity/__init__.py new file mode 100644 index 00000000..4719a61c --- /dev/null +++ b/activity/__init__.py @@ -0,0 +1,96 @@ +# +# Activity monitor +# +# Client is authenticated with an API key and a secret +# The API key is a 64 chars string (digits and letters) that is passed to the request +# The secret is a 64 chars string that is used to sign the request +# The generated signature is a SHA256 hes digest + +import urllib, urllib2 +import threading +import hmac +import hashlib +import base64 +import time +import datetime +from myslice.configengine import ConfigEngine + +config = ConfigEngine() +if config.activity and config.activity.apikey : + apikey = config.activity.apikey +else : + # apikey will be necessary + apikey = None + +if config.activity and config.activity.secret : + secret = config.activity.secret +else : + # secret will be necessary + secret = None + +if config.activity and config.activity.server : + server = config.activity.server +else : + # default log server + server = "http://athos.ipv6.lip6.fr/activity/push/log" + +def logWrite(request, action, message, objects = None): + + if not apikey : + print "===============>> activity: no apikey" + return + if not secret : + print "===============>> activity: no secret" + return + + timestamp = time.mktime(datetime.datetime.today().timetuple()) + ip = getClientIp(request) + log = { + "timestamp" : timestamp, + "client_ip" : ip, + "host" : request.get_host(), + "referrer" : request.META.get('HTTP_REFERER'), + "user" : request.user, + "action" : action, + "message" : message, + "apikey" : apikey, + "signature" : sign(secret, "%s%s%s%s" % (timestamp, ip, request.user, action)), + "slice" : None, + "resource" : None, + "resource_type" : None, + "facility" : None, + "testbed" : None, + } + + if objects is not None: + for o in objects : + if (o in log) : + log[o] = objects[o] + + try : + result = urllib2.urlopen(server, urllib.urlencode(log)) + print "===============>> activity: %s <%s> %s" % (action, request.user,message) + content = result.read() + except urllib2.URLError as e: + print "===============>> activity: connection to " + server + " impossible, could not log action" + print e.strerror + print "" + +def log(request, action, message, objects = None): + # Create a new thread in Daemon mode to send the log entry + t = threading.Thread(target=logWrite, args=(request, action, message, objects)) + t.setDaemon(True) + t.start() + +def getClientIp(request): + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + if x_forwarded_for: + ip = x_forwarded_for.split(',')[0] + else: + ip = request.META.get('REMOTE_ADDR') + return ip + +# +# sign the request with the secret key +def sign(secret, message): + return hmac.new(secret, msg=message, digestmod=hashlib.sha256).hexdigest() \ No newline at end of file diff --git a/activity/institution.py b/activity/institution.py new file mode 100644 index 00000000..73a23696 --- /dev/null +++ b/activity/institution.py @@ -0,0 +1,11 @@ +# +# log functions for institution activity +# + +import activity + +def joined(request): + activity.log(request, "institution.join", "Institution joined") + +def join(request): + activity.log(request, "institution.join.view", "Institution view join form") \ No newline at end of file diff --git a/activity/slice.py b/activity/slice.py new file mode 100644 index 00000000..f7f1eff4 --- /dev/null +++ b/activity/slice.py @@ -0,0 +1,11 @@ +# +# log functions for slice +# + +import activity + +def validate(request, o): + activity.log(request, "slice.validate", "Slice validation", o) + +def resource(request, o): + activity.log(request, "slice.resource", "Resource reservation", o) \ No newline at end of file diff --git a/activity/user.py b/activity/user.py new file mode 100644 index 00000000..a2790e8a --- /dev/null +++ b/activity/user.py @@ -0,0 +1,29 @@ +# +# log functions for user activity +# + +import activity + +def login(request, state=None): + if state is not None : + activity.log(request, "user.login." + state, "User log in") + else : + activity.log(request, "user.login", "User log in") + +def logout(request): + activity.log(request, "user.logout", "User log out") + +def signup(request): + activity.log(request, "user.signup.view", "User sign up") + +def registered(request): + activity.log(request, "user.signup", "User registered") + +def contact(request): + activity.log(request, "user.contact", "User sent a contact request") + +def slice(request): + activity.log(request, "user.slice", "User requested a slice") + +def resource(request): + activity.log(request, "user.resource", "User added a resource to a slice") \ No newline at end of file diff --git a/auth/views.py b/auth/views.py index 104d11c9..b959e730 100644 --- a/auth/views.py +++ b/auth/views.py @@ -1,12 +1,18 @@ from django.contrib.auth import logout from django.http import HttpResponseRedirect +import activity.user + # hard question : where should we redirect requests to logout if user is not logged in ? def logout_user (request): # check that we're indeed logged in if not request.user.is_authenticated(): return HttpResponseRedirect ('/') print "LOGGING OUT" + + # log user activity + activity.user.logout(request) + logout(request) return HttpResponseRedirect ('/') diff --git a/debian/deb-cheat-sheet b/debian/deb-cheat-sheet index 182c3d3c..3d3f1bc1 100644 --- a/debian/deb-cheat-sheet +++ b/debian/deb-cheat-sheet @@ -21,3 +21,7 @@ dpkg -i foo.deb - or, if this has deps that need to be pulled through apt-get: gdebi foo.deb (install with apt-get install -y gdebi-core) + +--- find which package a file belongs to +apt-file search /path/to/file +(can be installed with : sudo apt-get install apt-file) diff --git a/manifoldapi/manifoldproxy.py b/manifoldapi/manifoldproxy.py index 99959aee..9897b506 100644 --- a/manifoldapi/manifoldproxy.py +++ b/manifoldapi/manifoldproxy.py @@ -13,6 +13,9 @@ from manifoldresult import ManifoldException from manifold.util.log import Log from myslice.configengine import ConfigEngine +# register activity +import activity.slice + debug=False #debug=True @@ -55,9 +58,12 @@ with the query passed using POST""" admin_user, admin_password = ConfigEngine().manifold_admin_user_password() manifold_api_session_auth = {'AuthMethod': 'password', 'Username': admin_user, 'AuthString': admin_password} else: - print request.session['manifold'] - manifold_api_session_auth = request.session['manifold']['auth'] - + if 'manifold' in request.session: + manifold_api_session_auth = request.session['manifold']['auth'] + else: + json_answer=json.dumps({'code':0,'value':[]}) + return HttpResponse (json_answer, mimetype="application/json") + if debug_empty and manifold_query.action.lower()=='get': json_answer=json.dumps({'code':0,'value':[]}) print "By-passing : debug_empty & 'get' request : returning a fake empty list" @@ -75,7 +81,26 @@ with the query passed using POST""" if 'description' in result and result['description'] \ and isinstance(result['description'], (tuple, list, set, frozenset)): result [ 'description' ] = [ ResultValue.to_html (x) for x in result['description'] ] - + + print "=> MANIFOLD PROXY executing: " + manifold_query.action.lower() + # + # register activity + # + # resource reservation + if (manifold_query.action.lower() == 'update') : + print result['value'][0] + if 'resource' in result['value'][0] : + for resource in result['value'][0]['resource'] : + activity.slice.resource(request, + { + 'slice' : result['value'][0]['slice_hrn'], + 'resource' : resource['hostname'], + 'resource_type' : resource['type'], + 'facility' : resource['facility_name'], + 'testbed' : resource['testbed_name'] + } + ) + json_answer=json.dumps(result) return HttpResponse (json_answer, mimetype="application/json") diff --git a/manifoldapi/static/css/manifold.css b/manifoldapi/static/css/manifold.css index 42c034d3..dfb4ab5c 100644 --- a/manifoldapi/static/css/manifold.css +++ b/manifoldapi/static/css/manifold.css @@ -2,3 +2,22 @@ visibility: hidden; position: absolute; } + +.loading { + background-color:white; + color:black; + position:fixed; + top:160px; + left:50%; + width:30%; + margin: 0 0 0 -15%; + padding:25px 50px; + box-shadow: 4px 4px 5px #888; + border:1pt solid #30196D; + display:none; + z-index:100; +} +.loading img { + vertical-align:middle; + margin-right:15px; +} diff --git a/manifoldapi/static/js/manifold.js b/manifoldapi/static/js/manifold.js index e261efeb..ca111de7 100644 --- a/manifoldapi/static/js/manifold.js +++ b/manifoldapi/static/js/manifold.js @@ -17,6 +17,32 @@ function debug_query (msg, query) { else messages.debug ("debug_query: " + msg + " query= " + query); } +// http://stackoverflow.com/questions/7837456/comparing-two-arrays-in-javascript +// attach the .equals method to Array's prototype to call it on any array +Array.prototype.equals = function (array) { + // if the other array is a falsy value, return + if (!array) + return false; + + // compare lengths - can save a lot of time + if (this.length != array.length) + return false; + + for (var i = 0, l=this.length; i < l; i++) { + // Check if we have nested arrays + if (this[i] instanceof Array && array[i] instanceof Array) { + // recurse into the nested arrays + if (!this[i].equals(array[i])) + return false; + } + else if (this[i] != array[i]) { + // Warning - two different object instances will never be equal: {x:20} != {x:20} + return false; + } + } + return true; +} + // http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ Object.toType = (function toType(global) { return function(obj) { @@ -318,12 +344,20 @@ function QueryStore() { default_set = (default_set === undefined) ? STATE_SET_OUT : default_set; var self = this; - var query_ext = this.find_analyzed_query_ext(query_uuid); - var record_key = manifold.metadata.get_key(query_ext.query.object); + var key, object, query_ext, record_key; + + query_ext = this.find_analyzed_query_ext(query_uuid); + object = query_ext.query.object; + if (object.indexOf(':') != -1) { + object = object.split(':')[1]; + } + record_key = manifold.metadata.get_key(object); + + // ["start_time", "resource", "end_time"] + // ["urn"] + $.each(records, function(i, record) { - var key = manifold.metadata.get_key(query_ext.query.object); - // ["start_time", "resource", "end_time"] - // ["urn"] + //var key = manifold.metadata.get_key(query_ext.query.object); var record_key_value = manifold.record_get_value(record, record_key); query_ext.records.put(record_key_value, record); @@ -345,6 +379,18 @@ function QueryStore() { return query_ext.records.get(record_key); } + this.del_record = function(query_uuid, record_key) + { + var query_ext = this.find_analyzed_query_ext(query_uuid); + return query_ext.records.remove(record_key); + } + + this.del_state = function(query_uuid, record_key) + { + var query_ext = this.find_analyzed_query_ext(query_uuid); + return query_ext.state.remove(record_key); + } + this.add_record = function(query_uuid, record, new_state) { var query_ext, key, record_key; @@ -375,8 +421,15 @@ function QueryStore() { } else { record_key = record; } - - manifold.query_store.set_record_state(query_uuid, record_key, STATE_SET, new_state); + + if ((query_ext.query.object == 'lease') && (new_state == STATE_SET_OUT)) { + // Leases that are marked out are in fact leases from other slices + // We need to _remove_ leases that we mark as OUT + manifold.query_store.del_record(query_uuid, record_key); + manifold.query_store.del_state(query_uuid, record_key); + } else { + manifold.query_store.set_record_state(query_uuid, record_key, STATE_SET, new_state); + } } this.iter_records = function(query_uuid, callback) @@ -443,7 +496,7 @@ function QueryStore() { { var query_ext = this.find_analyzed_query_ext(query_uuid); query_ext.filters = $.grep(query_ext.filters, function(x) { - return x == filter; + return !(x.equals(filter)); }); this.apply_filters(query_uuid); @@ -507,6 +560,8 @@ function QueryStore() { this.iter_records(query_uuid, function(record_key, record) { var is_reserved, is_pending, in_set, is_unconfigured; + + /* By default, a record is visible unless a filter says the opposite */ var visible = true; var record_state = manifold.query_store.get_record_state(query_uuid, record_key, STATE_SET); @@ -576,13 +631,16 @@ function QueryStore() { if (op == '=' || op == '==') { if ( col_value != value || col_value==null || col_value=="" || col_value=="n/a") visible = false; + }else if (op == 'included') { + /* By default, the filter returns false unless the record + * field match at least one value of the included statement + */ + visible = false; $.each(value, function(i,x) { if(x == col_value){ visible = true; return false; // ~ break - }else{ - visible = false; } }); }else if (op == '!=') { @@ -613,7 +671,7 @@ function QueryStore() { }); var end = new Date().getTime(); - console.log("APPLY FILTERS took", end - start, "ms"); + console.log("APPLY FILTERS [", filters, "] took", end - start, "ms"); } @@ -704,7 +762,7 @@ var manifold = { { return function() { ret = ""; - for (i=0; i < key_fields.length; i++) + for (var i=0; i < key_fields.length; i++) ret += "@@" + this[key_fields[i]]; return ret; }; @@ -712,7 +770,10 @@ var manifold = { _record_equals: function(self, other, key_fields) { - for (i=0; i < key_fields.length; i++) { + if ((typeof self === "string") && (typeof other === "string")) { + return self == other; + } + for (var i=0; i < key_fields.length; i++) { var this_value = self[key_fields[i]]; var other_value = other[key_fields[i]]; @@ -724,6 +785,7 @@ var manifold = { switch (this_type) { case TYPE_VALUE: case TYPE_LIST_OF_VALUES: + case TYPE_LIST_OF_RECORDS: if (this_value != other_value) return false; break; @@ -731,13 +793,17 @@ var manifold = { if (!(_record_equals(this_value, other_value, key_fields))) return false; break; + /* + XXX WARNING = disabled for OpenFlow plugin !!! + case TYPE_LIST_OF_RECORDS: if (this_value.length != other_value.length) return false; - for (i = 0; i < this_value.length; i++) - if (!(_record_equals(this_value, other_value, key_fields))) + for (var j = 0; j < this_value.length; j++) + if (!(_record_equals(this_value[j], other_value[j], key_fields))) return false; break; + */ } } return true; @@ -753,7 +819,7 @@ var manifold = { _in_array: function(element, array, key_fields) { if (key_fields.length > 1) { - for (i = 0; i < array.length; i++) { + for (var i = 0; i < array.length; i++) { if (manifold._record_equals(element, array[i], key_fields)) return true; } @@ -1018,7 +1084,7 @@ var manifold = { if (query_ext.set_query_ext) { // We have a domain query // The results are stored in the corresponding set_query - manifold.query_store.set_records(query_ext.set_query_ext.query.query_uuid, records) + manifold.query_store.set_records(query_ext.set_query_ext.query.query_uuid, records); } else if (query_ext.domain_query_ext) { // We have a set query, it is only used to determine which objects are in the set, we should only retrieve the key @@ -1153,9 +1219,22 @@ var manifold = { make_record: function(object, record) { // To make an object a record, we just add the hash function - var key = manifold.metadata.get_key(object); - record.hashCode = manifold.record_hashcode(record, key.sort()); - record.equals = manifold.record_equals(record, key); + var key, new_object; + + if (object.indexOf(':') != -1) { + new_object = object.split(':')[1]; + } else { + new_object = object; + } + + key = manifold.metadata.get_key(new_object); + if (!key){ + console.log("object type: " + new_object + " has no key"); + console.log(record); + return; + } + record.hashCode = manifold.record_hashcode(key.sort()); + record.equals = manifold.record_equals(key); // Looking after subrecords for (var field in record) { @@ -1283,7 +1362,7 @@ case TYPE_LIST_OF_VALUES: */ case TYPE_LIST_OF_VALUES: // XXX Until fixed case TYPE_LIST_OF_RECORDS: - var new_state,cur_query_uuid; + var key, new_state, cur_query_uuid; cur_query_uuid = query.analyzed_query.subqueries[field].query_uuid; @@ -1291,7 +1370,15 @@ case TYPE_LIST_OF_VALUES: // - update_query_orig.params.resource = resources in slice before update // - update_query.params.resource = resource requested in slice // - keys from field = resources obtained - var key = manifold.metadata.get_key(field); + + if (field == 'lease') { + // lease_id has been added to be repeated when + // constructing request rspec. We don't want it for + // comparisons + key = ['start_time', 'end_time', 'resource']; + } else { + key = manifold.metadata.get_key(field); + } if (!key) continue; /* @@ -1326,6 +1413,14 @@ case TYPE_LIST_OF_VALUES: data = { state: STATE_SET, key : field, op : new_state, value: added_key } manifold.raise_record_event(query_uuid, FIELD_STATE_CHANGED, data); + + // Inform subquery also + data.key = ''; + manifold.raise_record_event(cur_query_uuid, FIELD_STATE_CHANGED, data); + // XXX Passing no parameters so that they can redraw everything would + // be more efficient but is currently not supported + // XXX We could also need to inform plugins about nodes IN (not pending) that are no more, etc. + // XXX refactor all this when suppressing update_queries, and relying on state instead ! }); $.each(removed_keys, function(i, removed_key) { new_state = (manifold._in_array(removed_key, result_keys, key)) ? STATE_SET_OUT_FAILURE : STATE_SET_OUT_SUCCESS; @@ -1338,6 +1433,10 @@ case TYPE_LIST_OF_VALUES: data = { state: STATE_SET, key : field, op : new_state, value: removed_key } manifold.raise_record_event(query_uuid, FIELD_STATE_CHANGED, data); + + // Inform subquery also + data.key = ''; + manifold.raise_record_event(cur_query_uuid, FIELD_STATE_CHANGED, data); }); break; @@ -1350,6 +1449,7 @@ case TYPE_LIST_OF_VALUES: var query_ext = manifold.query_store.find_query_ext(query.query_uuid); query_ext.query_state = QUERY_STATE_DONE; + // Send DONE message to plugins query.iter_subqueries(function(sq, data, parent_query) { manifold.raise_record_event(sq.query_uuid, DONE); @@ -1540,7 +1640,7 @@ case TYPE_LIST_OF_VALUES: } }, - _enforce_constraints: function(query_ext, record, resource_key, event_type) + _enforce_constraints: function(query_ext, record, record_key, event_type) { var query, data; @@ -1555,14 +1655,14 @@ case TYPE_LIST_OF_VALUES: // XXX Not always a resource var is_reservable = (record.exclusive == true); if (is_reservable) { - var warnings = manifold.query_store.get_record_state(query.query_uuid, resource_key, STATE_WARNINGS); + var warnings = manifold.query_store.get_record_state(query.query_uuid, record_key, STATE_WARNINGS); if (event_type == STATE_SET_ADD) { // We should have a lease_query associated var lease_query = query_ext.parent_query_ext.query.subqueries['lease']; // in options var lease_query_ext = manifold.query_store.find_analyzed_query_ext(lease_query.query_uuid); // Do we have lease records (in) with this resource - var lease_records = $.grep(lease_query_ext.records.entries(), this._grep_active_lease_callback(lease_query, resource_key)); + var lease_records = $.grep(lease_query_ext.records.entries(), this._grep_active_lease_callback(lease_query, record_key)); if (lease_records.length == 0) { // Sets a warning // XXX Need for a better function to manage warnings @@ -1577,7 +1677,7 @@ case TYPE_LIST_OF_VALUES: delete warnings[CONSTRAINT_RESERVABLE_LEASE]; } - manifold.query_store.set_record_state(query.query_uuid, resource_key, STATE_WARNINGS, warnings); + manifold.query_store.set_record_state(query.query_uuid, record_key, STATE_WARNINGS, warnings); } /* This was redundant */ @@ -1586,7 +1686,7 @@ case TYPE_LIST_OF_VALUES: // Signal the change to plugins (even if the constraint does not apply, so that the plugin can display a checkmark) data = { state: STATE_WARNINGS, - key : resource_key, + key : record_key, op : null, value : warnings } @@ -1594,7 +1694,7 @@ case TYPE_LIST_OF_VALUES: break; case 'lease': - var resource_key = record.resource; + var resource_key = record_key.resource; var resource_query = query_ext.parent_query_ext.query.subqueries['resource']; var warnings = manifold.query_store.get_record_state(resource_query.query_uuid, resource_key, STATE_WARNINGS); @@ -1792,6 +1892,7 @@ case TYPE_LIST_OF_VALUES: // FILTERS case FILTER_ADDED: + console.log("FILTER ADDED", data); /* Update internal record state */ manifold.query_store.add_filter(query_uuid, data); @@ -1801,6 +1902,7 @@ case TYPE_LIST_OF_VALUES: break; case FILTER_REMOVED: + console.log("FILTER REMOVED", data); /* Update internal record state */ manifold.query_store.remove_filter(query_uuid, data); diff --git a/manifoldapi/static/js/plugin.js b/manifoldapi/static/js/plugin.js index 76e1cb52..82a3cd03 100644 --- a/manifoldapi/static/js/plugin.js +++ b/manifoldapi/static/js/plugin.js @@ -19,6 +19,108 @@ ManifoldApp.filter('offset', function() { }; }); +// http://stackoverflow.com/questions/19992090/angularjs-group-by-directive +ManifoldApp.filter('groupBy', ['$parse', function ($parse) { + return function (list, group_by) { + + var filtered = []; + var prev_item = null; + var group_changed = false; + // this is a new field which is added to each item where we append "_CHANGED" + // to indicate a field change in the list + //was var new_field = group_by + '_CHANGED'; - JB 12/17/2013 + var new_field = 'group_by_CHANGED'; + + // loop through each item in the list + angular.forEach(list, function (item) { + + group_changed = false; + + // if not the first item + if (prev_item !== null) { + + // check if any of the group by field changed + + //force group_by into Array + group_by = angular.isArray(group_by) ? group_by : [group_by]; + + //check each group by parameter + for (var i = 0, len = group_by.length; i < len; i++) { + if ($parse(group_by[i])(prev_item) !== $parse(group_by[i])(item)) { + group_changed = true; + } + } + + + }// otherwise we have the first item in the list which is new + else { + group_changed = true; + } + + // if the group changed, then add a new field to the item + // to indicate this + if (group_changed) { + item[new_field] = true; + } else { + item[new_field] = false; + } + + filtered.push(item); + prev_item = item; + + }); + + return filtered; + }; +}]); + +// https://github.com/angular-ui/angular-ui-OLDREPO/blob/master/modules/filters/unique/unique.js +/** + * Filters out all duplicate items from an array by checking the specified key + * @param [key] {string} the name of the attribute of each object to compare for uniqueness + if the key is empty, the entire object will be compared + if the key === false then no filtering will be performed + * @return {array} + */ +ManifoldApp.filter('unique', function () { + + return function (items, filterOn) { + + if (filterOn === false) { + return items; + } + + if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) { + var hashCheck = {}, newItems = []; + + var extractValueToCompare = function (item) { + if (angular.isObject(item) && angular.isString(filterOn)) { + return item[filterOn]; + } else { + return item; + } + }; + + angular.forEach(items, function (item) { + var valueToCheck, isDuplicate = false; + + for (var i = 0; i < newItems.length; i++) { + if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) { + isDuplicate = true; + break; + } + } + if (!isDuplicate) { + newItems.push(item); + } + + }); + items = newItems; + } + return items; + }; +}); + // INHERITANCE // http://alexsexton.com/blog/2010/02/using-inheritance-patterns-to-organize-large-jquery-applications/ // We will use John Resig's proposal @@ -316,15 +418,18 @@ var Plugin = Class.extend({ // use spin() to get our default spin settings (called presets) // use spin(true) to get spin's builtin defaults // you can also call spin_presets() yourself and tweak what you need to, like topmenuvalidation does - spin: function (presets) { - var presets = ( presets === undefined ) ? spin_presets() : presets; - try { this.$element.spin(presets); } - catch (err) { messages.debug("Cannot turn on spin " + err); } + spin: function (message) { + if (!message) { + message = 'Please be patient, this operation can take a minute or two.'; + } + $('div.loading').fadeIn('fast'); + $('div.loading').find('.message').text(message); + }, unspin: function() { - try { this.$element.spin(false); } - catch (err) { messages.debug("Cannot turn off spin " + err); } + $('div.loading').fadeOut('fast'); + }, /* TEMPLATE */ diff --git a/myslice/monitor.ini.dist b/myslice/monitor.ini.dist new file mode 100644 index 00000000..4613e1a1 --- /dev/null +++ b/myslice/monitor.ini.dist @@ -0,0 +1,33 @@ +[monitor] +cert = myslice/sfa.cert +pkey = myslice/sfa.pkey + +[onelab] +name = OneLab +url = http://portal.onelab.eu:12345 +type = registry + +[ple] +name=PlanetLab Europe +url = http://sfa3.planet-lab.eu:12346 +type = am + +[nitos] +name = NITOS +url = https://nitlab.inf.uth.gr:8001/RPC2 +type = am + +[iotlab] +name = FIT IoT-Lab +url = http://194.199.16.169:52347 +type = am + +#[virtualwall] +#name = VirtualWall +#url = http://www.wall2.ilabt.iminds.be:12369/protogeni/xmlrpc/am/3.0 +#type = am + +#[w-ilab.t] +#name = w-ilab.t +#url = http://www.wilab2.ilabt.iminds.be:12369/protogeni/xmlrpc/am/3.0 +#type = am diff --git a/myslice/myslice.ini.localhost b/myslice/myslice.ini.localhost index 0467c0ba..524e7be9 100644 --- a/myslice/myslice.ini.localhost +++ b/myslice/myslice.ini.localhost @@ -2,3 +2,6 @@ url = https://localhost:7080 admin_user = admin admin_password = admin + +[myslice] +theme = onelab diff --git a/myslice/theme.py b/myslice/theme.py index d44b854e..e16326b0 100644 --- a/myslice/theme.py +++ b/myslice/theme.py @@ -14,12 +14,12 @@ class ThemeView (object): def template(self): # Load a template from the theme directory if it exists # else load it from the common templates dir - print "THEME = ",self.theme - print "TEMPLATE = ",self.template_name - print "TEMPLATE_DIRS = ",TEMPLATE_DIRS + #print "THEME = ",self.theme + #print "TEMPLATE = ",self.template_name + #print "TEMPLATE_DIRS = ",TEMPLATE_DIRS filename = self.theme + '_' + self.template_name - print any(os.path.exists(os.path.join(d,filename)) for d in TEMPLATE_DIRS) - print (os.path.exists(os.path.join(d,filename)) for d in TEMPLATE_DIRS) + #print any(os.path.exists(os.path.join(d,filename)) for d in TEMPLATE_DIRS) + #print (os.path.exists(os.path.join(d,filename)) for d in TEMPLATE_DIRS) if any(os.path.exists(os.path.join(d,filename)) for d in TEMPLATE_DIRS): return filename else: diff --git a/myslice/urls.py b/myslice/urls.py index 68ec521a..91511b7d 100644 --- a/myslice/urls.py +++ b/myslice/urls.py @@ -16,7 +16,17 @@ import portal.platformsview import portal.dashboardview import portal.homeview import portal.newsview + +from portal.about import AboutView from portal.registrationview import RegistrationView +from portal.accountview import AccountView, account_process +from portal.institution import InstitutionView + +from portal.supportview import SupportView +from portal.contactview import ContactView + +from portal.termsview import TermsView + home_view=portal.homeview.HomeView.as_view() dashboard_view=portal.dashboardview.DashboardView.as_view() platforms_view=portal.platformsview.PlatformsView.as_view() @@ -31,6 +41,7 @@ import portal.slicetabtestbeds import portal.slicetabusers import portal.slicetabmeasurements +import portal.managementtababout import portal.managementtabrequests #### high level choices @@ -76,7 +87,10 @@ urls = [ (r'^update/(?P[^/]+)/(?P[^/]+)?/?$', 'rest.update.dispatch'), (r'^create/(?P[^/]+)/(?P[^/]+)?/?$', 'rest.create.dispatch'), (r'^delete/(?P[^/]+)/(?P[^/]+)?/?$', 'rest.delete.dispatch'), + (r'^credentials/(?P[^/]+)/?$', 'rest.credentials.dispatch'), # + # REST monitoring + (r'^monitor/services/?$', 'rest.monitor.servicesStatus'), # #(r'^view/?', include('view.urls')), #(r'^list/slices', 'view.list.slices') @@ -92,10 +106,20 @@ urls = [ (r'^testbeds/(?P[^/]+)/?$', portal.slicetabtestbeds.SliceTabTestbeds.as_view()), (r'^measurements/(?P[^/]+)/?$', portal.slicetabmeasurements.SliceTabMeasurements.as_view()), (r'^experiment/(?P[^/]+)/?$', portal.slicetabexperiment.ExperimentView.as_view()), - # + + url(r'^about/?$', AboutView.as_view(), name='about'), + + url(r'^institution/?$', InstitutionView.as_view(), name='institution'), (r'^management/requests/?$', portal.managementtabrequests.ManagementRequestsView.as_view()), + (r'^management/about/?$', portal.managementtababout.ManagementAboutView.as_view()), + # + url(r'^register/?$', RegistrationView.as_view(), name='registration'), + url(r'^account/?$', AccountView.as_view(), name='account'), + url(r'^account/account_process/?$', account_process), + url(r'^contact/?$', ContactView.as_view(), name='contact'), + url(r'^terms/?$', TermsView.as_view(), name='terms'), + url(r'^support/?$', SupportView.as_view(), name='support'), # - url(r'^register/?$', RegistrationView.as_view(), name='registration'), url(r'^portal/', include('portal.urls')), # SLA diff --git a/plugins/apply/static/js/apply.js b/plugins/apply/static/js/apply.js index efc93450..236deaf1 100644 --- a/plugins/apply/static/js/apply.js +++ b/plugins/apply/static/js/apply.js @@ -46,10 +46,10 @@ bAutoWidth: true, }); - //this.elmt('update').click(this, this.do_ok); - //this.elmt('refresh').click(this, this.do_cancel); + this.elmt('close').click(this, this.do_close); + //this.elmt('apply_cancel').click(this, this.do_cancel); - this.elmt('apply').on('shown.bs.modal', function() { + this.elmt('apply__window').on('shown.bs.modal', function() { self.do_update(); }) @@ -80,7 +80,6 @@ clear: function() { - }, find_row: function(value) @@ -98,7 +97,7 @@ if (cur_value[0] == '{') { cur_value = JSON.parse(cur_value); - return manifold._record_equals(cur_value, value, object_key);_ + return manifold._record_equals(cur_value, value, object_key); } else { return (cur_value == value); } @@ -121,7 +120,6 @@ var username = this.options.username; - this.spin(); console.log("do_update in progress"); manifold.raise_event(this.options.query_uuid, RUN_UPDATE); @@ -131,11 +129,13 @@ }, - do_ok: function(e) + do_close: function(e) { - throw 'queryupdater.do_reset Not implemented'; + var self = e.data; + self.table.fnClearTable(); }, + // Not used today do_cancel: function(e) { throw 'queryupdater.do_clear_annotations Not implemented'; @@ -214,13 +214,11 @@ on_query_in_progress: function() { - this.spin(); }, on_query_done: function() { this.populate_table(); - this.unspin(); }, // D : Data present @@ -232,12 +230,13 @@ on_clear_records: function() { + $('#applyloading').hide(); this.clear(); }, on_query_done: function() { - this.unspin(); + $('#applyloading').hide(); }, // PC : Pending changes @@ -344,11 +343,12 @@ // XXX how do we handle status reset ? // Jordan : I don't understand this. I added this test otherwise we have string = ""..."" double quoted twice. - if (typeof(data.value) !== "string") - data.value = JSON.stringify(data.value); data.selected_resources = this.selected_resources; row = this.find_row(data.value); - newline = [action, data.key, data.value, msg, button]; + if (typeof(data.value) !== "string") + newline = [action, data.key, JSON.stringify(data.value), msg, button]; + else + newline = [action, data.key, data.value, msg, button]; if (!row) { // XXX second parameter refresh = false can improve performance. todo in querytable also this.table.fnAddData(newline); diff --git a/plugins/apply/templates/apply.html b/plugins/apply/templates/apply.html index 65070128..f05af49d 100644 --- a/plugins/apply/templates/apply.html +++ b/plugins/apply/templates/apply.html @@ -1,11 +1,17 @@
-