From: Ciro Scognamiglio Date: Tue, 10 Mar 2015 16:36:07 +0000 (+0100) Subject: allow self signed certificates X-Git-Tag: myslice-1.3~58^2~6 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=6c978327b002ef4b46047ce22ba7e8f61768f652;hp=c87f5c0a32a23075ba4da344da1a4c93095c24e7;p=unfold.git allow self signed certificates --- diff --git a/Makefile b/Makefile index 69725db5..80d49c4c 100644 --- a/Makefile +++ b/Makefile @@ -110,8 +110,9 @@ ftags: force #################### sync : push current code on a box running myslice # this for now targets deployments based on the debian packaging -SSHURL:=root@$(MYSLICEBOX):/ -SSHCOMMAND:=ssh root@$(MYSLICEBOX) +SSHUSER ?= root +SSHURL := $(SSHUSER)@$(MYSLICEBOX): +SSHCOMMAND := ssh $(SSHUSER)@$(MYSLICEBOX) ### rsync options # the config file should probably not be overridden ?? @@ -163,3 +164,14 @@ ifeq (,$(MYSLICEBOX)) else +$(SSHCOMMAND) apachectl restart endif + +#SSHUSER=tparment +#MYSLICEBOX=srv-diana.inria.fr +sync-devel: +ifeq (,$(MYSLICEBOX)) + @echo "you need to set MYSLICEBOX, like in e.g." + @echo " $(MAKE) MYSLICEBOX=srv-diana.inria.fr "$@"" + @exit 1 +else + +$(RSYNC) --relative $$(git ls-files) $(SSHURL)myslice/ +endif diff --git a/README b/README index eae49734..4e4e1955 100644 --- a/README +++ b/README @@ -1,48 +1,66 @@ This file documents the contents of this module change -Last update 4 FEB. 2015 +Last update 20 FEB. 2015 -See the devel/ subdir for more devel-oriented doc. +Installation +================================================================= +Recommended OS +=============== +Debian GNU/Linux 7.5 (wheezy) x64 -==================== 1 minute howto +PYTHON DEPENDENCIES +===================== +sudo apt-get install python-pip or sudo easy_install pip==1.4.1 +sudo apt-get install python-dev (for paramiko and pyOpenSSL) +sudo apt-get install libffi-dev (for pyOpenSSL) -* REQUIREMENTS is to have python + django (1.5.2) installed django -** should be straightforward -** see devel/django-install.txt in case of trouble -$ apt-get install python-pip or sudo easy_install pip==1.4.1 -$ pip install django=="1.5.2 +$ pip install django=="1.5.2" $ apt-get install python-django-south $ pip install requests $ pip install djangorestframework $ pip install django-celery $ pip install geopy $ pip install paramiko +$ pip install pyparsing +$ pip install python-dateutil +$ pip instal pyOpenSSL -* git clone git://git.onelab.eu/myslice.git --- or -- -* git clone ssh://yourlogin@git.onelab.eu/git/myslice.git +MYSLICE +======= +git clone ssh://yourlogin@git.onelab.eu/git/myslice.git +cd myslice +git checkout onelab -* edit/create myslice/myslice.ini and enter the details of your manifold backend +edit/create myslice/myslice.ini and enter the details of your manifold backend + +mkdir /var/unfold +copy unfold.sqlite3 to /var/unfold -$ apt-get install python-django-south -* init django -** when django prompts for creating an admin account, create it and -** keep the username and password safe $ ./manage.py syncdb $ ./manage.py migrate -* gather static files -$ ./manage.py collectstatic --- or -- -$ ./manage.py collectstatic --noinput --- or -- -$ make static (which is a shorthand for cleaning up and run manage collectstatic --noinput) +use the unfold.sqlite3 i gave to u + +$ make redo +$ ./devel/server-loop.sh + +MANIFOLD +========== +git clone git://git.onelab.eu/manifold.git +cd manifold +git checkout devel +make && make install + +SFA +=== +$ git clone -b geni-v3 git://git.onelab.eu/sfa.git +$ cd sfa +$ git checkout geni-v3 -* gather templates files - for now we still seem to rely on a make-based templates-collection process - that creates templates/ -$ make templates [$ make redo (each time when you pull, do that and restart the server)] +$ make version +$ python ./setup.py install +===================================================================== ## Whenever doing a git pull the following operations are recommended: diff --git a/devel/server-loop.sh b/devel/server-loop.sh index c77258fc..78e1da15 100755 --- a/devel/server-loop.sh +++ b/devel/server-loop.sh @@ -2,9 +2,8 @@ DIRNAME=$(dirname $0) cd $DIRNAME/.. -# default port : if hostname starts with z -> use 8080 ; otherwise take 80 -#hostname | grep -q '^z' && port=8080 || port=8080 -hostname | grep -q '^z' && port=8080 || port=80 +# default port : if hostname starts with z or with srv- -> use 8000 ; otherwise take 80 +hostname | egrep -q '^(z|srv-)' && port=8000 || port=80 [[ -n "$@" ]] && port=$1 while true; do diff --git a/manifoldapi/static/js/manifold.js b/manifoldapi/static/js/manifold.js index c880831f..517ab693 100644 --- a/manifoldapi/static/js/manifold.js +++ b/manifoldapi/static/js/manifold.js @@ -737,6 +737,12 @@ var manifold = { } else { console.log('Unknown field'); } + // FIX if the record contains a string instead of a key:value + // example: select resource, slice_hrn from slice where slice_hrn=='xxx' + // Result will be {slice_hrn:'xxx', resource:'urn+zzz'} + // We don't have this resource:{urn:'urn+zzz'} + } else if(typeof(record) === 'string'){ + return record; } else { return record[fields]; } @@ -979,7 +985,8 @@ var manifold = { Loop per platform, allows a progressive loading per AM platform Update is run on all platforms at the same time to get a final answer, we don't manage partial answers yet... */ - if((query.object == 'resource' || query.object == 'lease' || query.object == 'slice') && query.action != "update"){ + // Removed slice from the per platform query - it's quick enough... + if((query.object == 'resource' || query.object == 'lease') && query.action != "update"){ var obj = query.object; $.post("/rest/platform/", function( data ) { $.each(data, function(index, p) { diff --git a/myslice/configengine.py b/myslice/configengine.py index 3d92bb16..4b40cb24 100644 --- a/myslice/configengine.py +++ b/myslice/configengine.py @@ -36,7 +36,7 @@ class ConfigEngine(object): default_myslice_theme = 'onelab' #iotlab dev url - default_iotlab_url = "https://devgrenoble.senslab.info/rest/admin/users" + default_iotlab_url = "https://devwww.iot-lab.info/rest/admin/users" default_iotlab_admin_user = "xxx" default_iotlab_admin_password= "yyy" diff --git a/myslice/myslice.ini.onelab b/myslice/myslice.ini.onelab new file mode 100644 index 00000000..7cfe4949 --- /dev/null +++ b/myslice/myslice.ini.onelab @@ -0,0 +1,2 @@ +[manifold] +url = https://portal.onelab.eu:7080/ diff --git a/myslice/settings.py b/myslice/settings.py index bd1474bd..10b39533 100644 --- a/myslice/settings.py +++ b/myslice/settings.py @@ -1,5 +1,7 @@ # Django settings for unfold project. +from __future__ import print_function + import os.path import djcelery @@ -13,7 +15,9 @@ except: building=True DEBUG = True -TEMPLATE_DEBUG = DEBUG + +# show the various settings as we go +DEBUG_SETTINGS = False # compute ROOT from where this file is installed # should fit every need including developers @@ -48,6 +52,10 @@ except: HTTPROOT="/var/myslice-f4f" # the place to store local data, like e.g. the sqlite db DATAROOT="/var/unfold" +if not os.path.isdir(DATAROOT): + print("WARNING: {} is a non-existing directory".format(DATAROOT)) + print("consequently we assume development mode and re-route DATAROOT to {}".format(ROOT)) + DATAROOT=ROOT # if not there, then we assume it's from a devel tree if not os.path.isdir (os.path.join(HTTPROOT,"static")): HTTPROOT=ROOT @@ -55,6 +63,11 @@ if not os.path.isdir (os.path.join(HTTPROOT,"static")): if not os.path.isdir(ROOT): raise Exception,"Cannot find ROOT %s for unfold"%ROOT if not os.path.isdir(HTTPROOT): raise Exception,"Cannot find HTTPROOT %s for unfold"%HTTPROOT +if DEBUG_SETTINGS: + print('ROOT', ROOT) + print('DATAROOT', DATAROOT) + print('HTTPROOT', HTTPROOT) + # dec 2013 - we currently have 2 auxiliary subdirs with various utilities # that we do not wish to package # * sandbox is for plugin developers @@ -101,6 +114,9 @@ DATABASES = { } } +if DEBUG_SETTINGS: + print('DATABASE NAME',DATABASES['default']['NAME']) + # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name # although not all choices may be available on all operating systems. @@ -252,7 +268,7 @@ BROKER_URL = "amqp://myslice:myslice@localhost:5672/myslice" for aux in auxiliaries: if os.path.isdir(os.path.join(ROOT,aux)): - print "Using devel auxiliary",aux + print("Using devel auxiliary",aux) INSTALLED_APPS.append(aux) ACCOUNT_ACTIVATION_DAYS = 7 # One-week activation window; you may, of course, use a different value. diff --git a/myslice/urls.py b/myslice/urls.py index da697cf7..ca150a40 100644 --- a/myslice/urls.py +++ b/myslice/urls.py @@ -132,7 +132,7 @@ urls = [ url(r'^portal/', include('portal.urls')), # SLA - url(r'^sla/', include('sla.urls')), +# url(r'^sla/', include('sla.urls')), ] #this one would not match the convention diff --git a/plugins/scheduler2/static/js/scheduler2.js b/plugins/scheduler2/static/js/scheduler2.js index 6b55b92a..a72341e3 100755 --- a/plugins/scheduler2/static/js/scheduler2.js +++ b/plugins/scheduler2/static/js/scheduler2.js @@ -1,925 +1,929 @@ -/* -# -# Copyright (c) 2013 NITLab, University of Thessaly, CERTH, Greece -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# -# This is a MySlice plugin for the NITOS Scheduler -# Nitos Scheduler v1 -# -*/ - -// XXX groupid = all slots those that go with a min granularity - -/* some params */ -var scheduler2; -var scheduler2Instance; -//is ctrl keyboard button pressed -var schedulerCtrlPressed = false; -//table Id -var schedulerTblId = "scheduler-reservation-table"; -var SCHEDULER_FIRST_COLWIDTH = 200; - - -/* Number of scheduler slots per hour. Used to define granularity. Should be inferred from resources XXX */ -var schedulerSlotsPerHour = 6; -var RESOURCE_DEFAULT_GRANULARITY = 1800 /* s */; // should be computed automatically from resource information -var DEFAULT_GRANULARITY = 1800 /* s */; // should be computed automatically from resource information. Test with 600 -var DEFAULT_PAGE_RANGE = 5; - -var schedulerMaxRows = 12; - -/* All resources */ -var SchedulerData = []; - -/* ??? */ -var SchedulerSlots = []; - -var SchedulerDateSelected = new Date(); -// Round to midnight -SchedulerDateSelected.setHours(0,0,0,0); - -/* Filtered resources */ -var SchedulerDataViewData = []; - -var SchedulerSlotsViewData = []; -//Help Variables -var _schedulerCurrentCellPosition = 0; -//Enable Debug -var schedulerDebug = true; -//tmp to delete -var tmpSchedulerLeases = []; - -var SCHEDULER_COLWIDTH = 50; - - -/****************************************************************************** - * ANGULAR CONTROLLER * - ******************************************************************************/ - -// Create a private execution space for our controller. When -// executing this function expression, we're going to pass in -// the Angular reference and our application module. -(function (ng, app) { - - // Define our Controller constructor. - function Controller($scope) { - - // Store the scope so we can reference it in our - // class methods - this.scope = $scope; - - // Set up the default scope value. - this.scope.errorMessage = null; - this.scope.name = ""; - - //Pagin - $scope.current_page = 1; - this.scope.items_per_page = 10; - $scope.from = 0; // JORDAN - - $scope.instance = null; - $scope.resources = new Array(); - $scope.slots = SchedulerSlotsViewData; - $scope.granularity = DEFAULT_GRANULARITY; /* Will be setup */ - //$scope.msg = "hello"; - - angular.element(document).ready(function() { - //console.log('Hello World'); - //alert('Hello World'); - //afterAngularRendered(); - }); - - // Pagination - - $scope.range = function() { - var range_size = $scope.page_count() > DEFAULT_PAGE_RANGE ? DEFAULT_PAGE_RANGE : $scope.page_count(); - var ret = []; - var start; - - start = $scope.current_page; - if ( start > $scope.page_count()-range_size ) { - start = $scope.page_count()-range_size+1; - } - - for (var i=start; i 1) { - $scope.current_page--; - } - }; - - $scope.prevPageDisabled = function() { - return $scope.current_page === 1 ? "disabled" : ""; - }; - - $scope.page_count = function() - { - // XXX need visible resources only - var query_ext, visible_resources_length; - if (!$scope.instance) - return 0; - query_ext = manifold.query_store.find_analyzed_query_ext($scope.instance.options.query_uuid); - var visible_resources_length = 0; - query_ext.state.each(function(i, state) { - if (state[STATE_VISIBLE]) - visible_resources_length++; - }); - return Math.ceil(visible_resources_length/$scope.items_per_page); - }; - - $scope.nextPage = function() { - if ($scope.current_page < $scope.page_count()) { - $scope.current_page++; - } - }; - - $scope.nextPageDisabled = function() { - return $scope.current_page === $scope.page_count() ? "disabled" : ""; - }; - - $scope.setPage = function(n) { - $scope.current_page = n; - }; - // END pagination - - // FILTER - - $scope.filter_visible = function(resource) - { - return manifold.query_store.get_record_state($scope.instance.options.query_uuid, resource['urn'], STATE_VISIBLE); - }; - - // SELECTION - - $scope._create_new_lease = function(resource_urn, start_time, end_time) - { - var lease_key, new_lease, data; - - lease_key = manifold.metadata.get_key('lease'); - - new_lease = { - resource: resource_urn, - start_time: start_time, - end_time: end_time, - }; - - // This is needed to create a hashable object - new_lease.hashCode = manifold.record_hashcode(lease_key.sort()); - new_lease.equals = manifold.record_equals(lease_key); - - data = { - state: STATE_SET, - key : null, - op : STATE_SET_ADD, - value: new_lease - } - manifold.raise_event($scope.instance.options.query_lease_uuid, FIELD_STATE_CHANGED, data); - /* Add to local cache also, unless we listen to events from outside */ - if (!(resource_urn in $scope._leases_by_resource)) - $scope._leases_by_resource[resource_urn] = []; - $scope._leases_by_resource[resource_urn].push(new_lease); - } - - $scope._remove_lease = function(other) - { - var lease_key, other_key, data; - - lease_key = manifold.metadata.get_key('lease'); - - // XXX This could be a manifold.record_get_value - other_key = { - resource: other.resource, - start_time: other.start_time, - end_time: other.end_time - } - other_key.hashCode = manifold.record_hashcode(lease_key.sort()); - other_key.equals = manifold.record_equals(lease_key); - - data = { - state: STATE_SET, - key : null, - op : STATE_SET_REMOVE, - value: other_key - } - manifold.raise_event($scope.instance.options.query_lease_uuid, FIELD_STATE_CHANGED, data); - /* Remove from local cache also, unless we listen to events from outside */ - $scope._leases_by_resource[other.resource] = $.grep($scope._leases_by_resource[other.resource], function(x) { return x != other; }); - - } - - $scope.select = function(index, model_lease, model_resource) - { - var data, resource_granularity; - - //resource_granularity = model_resource.granularity === undefined ? RESOURCE_DEFAULT_GRANULARITY : model_resource.granularity; - - console.log("Selected", index, model_lease, model_resource); - - var day_timestamp = SchedulerDateSelected.getTime() / 1000; - var start_time = day_timestamp + index * model_resource.granularity; // XXX resource_granularity - var end_time = day_timestamp + (index + 1) * model_resource.granularity; // - var start_date = new Date(start_time * 1000); - var end_date = new Date(end_time * 1000); - - var lease_key = manifold.metadata.get_key('lease'); - - // We search for leases in the cache we previously constructed - var resource_leases = $scope._leases_by_resource[model_resource.urn]; - - switch (model_lease.status) - { - case 'free': // out - case 'pendingout': - if (resource_leases) { - /* Search for leases before */ - $.each(resource_leases, function(i, other) { - if (other.end_time != start_time) - return true; // ~ continue - - /* The lease 'other' is just before, and there should not exist - * any other lease before it */ - start_time = other.start_time; - - other_key = { - resource: other.resource, - start_time: other.start_time, - end_time: other.end_time - } - // This is needed to create a hashable object - other_key.hashCode = manifold.record_hashcode(lease_key.sort()); - other_key.equals = manifold.record_equals(lease_key); - - data = { - state: STATE_SET, - key : null, - op : STATE_SET_REMOVE, - value: other_key - } - manifold.raise_event($scope.instance.options.query_lease_uuid, FIELD_STATE_CHANGED, data); - /* Remove from local cache also, unless we listen to events from outside */ - $scope._leases_by_resource[model_resource.urn] = $.grep($scope._leases_by_resource[model_resource.urn], function(x) { return x != other; }); - return false; // ~ break - }); - - /* Search for leases after */ - $.each(resource_leases, function(i, other) { - if (other.start_time != end_time) - return true; // ~ continue - - /* The lease 'other' is just after, and there should not exist - * any other lease after it */ - end_time = other.end_time; - other_key = { - resource: other.resource, - start_time: other.start_time, - end_time: other.end_time - } - // This is needed to create a hashable object - other_key.hashCode = manifold.record_hashcode(lease_key.sort()); - other_key.equals = manifold.record_equals(lease_key); - - data = { - state: STATE_SET, - key : null, - op : STATE_SET_REMOVE, - value: other_key - } - manifold.raise_event($scope.instance.options.query_lease_uuid, FIELD_STATE_CHANGED, data); - /* Remove from local cache also, unless we listen to events from outside */ - $scope._leases_by_resource[model_resource.urn] = $.grep($scope._leases_by_resource[model_resource.urn], function(x) { return x != other; }); - return false; // ~ break - }); - } - - $scope._create_new_lease(model_resource.urn, start_time, end_time); - model_lease.status = (model_lease.status == 'free') ? 'pendingin' : 'selected'; - // unless the exact same lease already existed (pending_out status for the lease, not the cell !!) - - break; - - case 'selected': - case 'pendingin': - // We remove the cell - - /* We search for leases including this cell. Either 0, 1 or 2. - * 0 : NOT POSSIBLE, should be checked. - * 1 : either IN or OUT, we have make no change in the session - * 2 : both will be pending, since we have made a change in the session - * /!\ need to properly remove pending_in leases when removed again - */ - if (resource_leases) { - $.each(resource_leases, function(i, other) { - if ((other.start_time <= start_time) && (other.end_time >= end_time)) { - // The cell is part of this lease. - - // If the cell is not at the beginning of the lease, we recreate a lease with cells before - if (start_time > other.start_time) { - $scope._create_new_lease(model_resource.urn, other.start_time, start_time); - } - - // If the cell is not at the end of the lease, we recreate a lease with cells after - if (end_time < other.end_time) { - $scope._create_new_lease(model_resource.urn, end_time, other.end_time); - } - - // The other lease will be removed - $scope._remove_lease(other); - } - // NOTE: We can interrupt the search if we know that there is a single lease (depending on the status). - }); - } - - // cf comment in previous switch case - model_lease.status = (model_lease.status == 'selected') ? 'pendingout' : 'free'; - - break; - - case 'reserved': - case 'maintainance': - // Do nothing - break; - } - - - $scope._dump_leases(); - }; - - $scope._dump_leases = function() - { - // DEBUG: display all leases and their status in the log - var leases = manifold.query_store.get_records($scope.instance.options.query_lease_uuid); - console.log("--------------------"); - $.each(leases, function(i, lease) { - var key = manifold.metadata.get_key('lease'); - var lease_key = manifold.record_get_value(lease, key); - var state = manifold.query_store.get_record_state($scope.instance.options.query_lease_uuid, lease_key, STATE_SET); - var state_str; - switch(state) { - case STATE_SET_IN: - state_str = 'STATE_SET_IN'; - break; - case STATE_SET_OUT: - state_str = 'STATE_SET_OUT'; - break; - case STATE_SET_IN_PENDING: - state_str = 'STATE_SET_IN_PENDING'; - break; - case STATE_SET_OUT_PENDING: - state_str = 'STATE_SET_OUT_PENDING'; - break; - case STATE_SET_IN_SUCCESS: - state_str = 'STATE_SET_IN_SUCCESS'; - break; - case STATE_SET_OUT_SUCCESS: - state_str = 'STATE_SET_OUT_SUCCESS'; - break; - case STATE_SET_IN_FAILURE: - state_str = 'STATE_SET_IN_FAILURE'; - break; - case STATE_SET_OUT_FAILURE: - state_str = 'STATE_SET_OUT_FAILURE'; - break; - } - console.log("LEASE", new Date(lease.start_time * 1000), new Date(lease.end_time * 1000), lease.resource, state_str); - }); - }; - - // Return this object reference. - return (this); - - } - - // Define the Controller as the constructor function. - app.controller("SchedulerCtrl", Controller); - -})(angular, ManifoldApp); - -/****************************************************************************** - * MANIFOLD PLUGIN * - ******************************************************************************/ - -(function($) { - scheduler2 = Plugin.extend({ - - /** XXX to check - * @brief Plugin constructor - * @param options : an associative array of setting values - * @param element : - * @return : a jQuery collection of objects on which the plugin is - * applied, which allows to maintain chainability of calls - */ - init: function(options, element) { - // Call the parent constructor, see FAQ when forgotten - this._super(options, element); - - var scope = this._get_scope() - scope.instance = this; - - // XXX not needed - scheduler2Instance = this; - - // We need to remember the active filter for datatables filtering - // XXX not needed - this.filters = Array(); - - // XXX BETTER !!!! - $(window).delegate('*', 'keypress', function (evt){ - alert("erm"); - }); - - $(window).keydown(function(evt) { - if (evt.which == 17) { // ctrl - schedulerCtrlPressed = true; - } - }).keyup(function(evt) { - if (evt.which == 17) { // ctrl - schedulerCtrlPressed = false; - } - }); - - // XXX naming - //$("#" + schedulerTblId).on('mousedown', 'td', rangeMouseDown).on('mouseup', 'td', rangeMouseUp).on('mousemove', 'td', rangeMouseMove); - - this._resources_received = false; - this._leases_received = false; - - scope._leases_by_resource = {}; - - /* Listening to queries */ - this.listen_query(options.query_uuid, 'resources'); - this.listen_query(options.query_lease_uuid, 'leases'); - - this.elmt().on('show', this, this.on_show); - this.elmt().on('shown.bs.tab', this, this.on_show); - this.elmt().on('resize', this, this.on_resize); - - /* Generate slots according to the default granularity. Should - * be updated when resources arrive. Should be the pgcd in fact XXX */ - this._granularity = DEFAULT_GRANULARITY; - scope.granularity = this._granularity; - this.scope_resources_by_key = {}; - - this.do_resize(); - - scope.from = 0; - - this._initUI(); - - }, - - do_resize: function() - { - var scope = this._get_scope(); - var num_hidden_cells, new_max, lcm; - - // do_resize has to be called when the window is resized, or one parameter changes - // e.g. when new resources have been received - // - this.resource_granularities = [3600, 1800]; //, 2400]; /* s */ - - /* Compute the slot length to accommodate all resources. This - * is the GCD of all resource granularities. */ - this._slot_length = this._gcdn(this.resource_granularities); - - $('#' + schedulerTblId + ' thead tr th:eq(0)').css("width", SCHEDULER_FIRST_COLWIDTH); - //self get width might need fix depending on the template - var tblwidth = $('#scheduler-reservation-table').parent().outerWidth(); - - /* Number of visible cells...*/ - this._num_visible_cells = parseInt((tblwidth - SCHEDULER_FIRST_COLWIDTH) / SCHEDULER_COLWIDTH); - - /* ...should be a multiple of the lcm of all encountered granularities. */ - lcm = this._lcmn(this.resource_granularities) / this._slot_length; - this._num_visible_cells = this._num_visible_cells - this._num_visible_cells % lcm; - - // A list of {id, time} dictionaries representing the slots for the given day - this._all_slots = this._generate_all_slots(); - - /* scope also needs this value */ - scope.slots = this._all_slots; - scope.slot_length = this._slot_length; - scope.num_visible_cells = this._num_visible_cells; - scope.lcm_colspan = this._lcmn(this.resource_granularities); // XXX WHY ? - - /* Redraw... */ - this._scope_clear_leases(); - this._set_all_lease_slots(); - - // Slider max value - if ($('#tblSlider').data('slider') != undefined) { - num_hidden_cells = this._all_slots.length - this._num_visible_cells; - - $('#tblSlider').slider('setAttribute', 'max', num_hidden_cells); - $('#tblSlider').slider('setValue', scope.from, true); - } - this._get_scope().$apply(); - - - }, - - on_show: function(e) - { - var self = e.data; - self.do_resize(); - self._get_scope().$apply(); - }, - - on_resize: function(e) - { - var self = e.data; - self.do_resize(); - self._get_scope().$apply(); - }, - - /* Handlers */ - - _get_scope : function() - { - return angular.element(document.getElementById('SchedulerCtrl')).scope(); - }, - - _scope_set_resources : function() - { - var self = this; - var scope = this._get_scope(); - - var records = manifold.query_store.get_records(this.options.query_uuid); - - scope.resources = []; - - $.each(records, function(i, record) { - if (!record.exclusive) - return true; // ~ continue - - // copy not to modify original record - var resource = jQuery.extend(true, {}, record); - - // Fix granularity - //resource_granularity = ((resource.granularity === undefined) || (typeof(resource.granularity) != "number")) ? RESOURCE_DEFAULT_GRANULARITY : resource.granularity; - if (typeof(resource.granularity) != "number") - resource.granularity = RESOURCE_DEFAULT_GRANULARITY; - resource.leases = []; // a list of occupied timeslots - - self.scope_resources_by_key[resource['urn']] = resource; - scope.resources.push(resource); - }); - }, - - _scope_clear_leases: function() - { - var time, now; - var self = this; - var scope = this._get_scope(); - - now = new Date().getTime(); - - // Setup leases with a default free status... - $.each(this.scope_resources_by_key, function(resource_key, resource) { - resource.leases = []; - var colspan_lease = resource.granularity / self._slot_length; //eg. 3600 / 1800 => 2 cells - time = SchedulerDateSelected.getTime(); - for (i=0; i < self._all_slots.length / colspan_lease; i++) { // divide by granularity - resource.leases.push({ - id: 'coucou', - status: (time < now) ? 'disabled': 'free', // 'selected', 'reserved', 'maintenance' XXX pending ?? - }); - time += resource.granularity * 1000; - } - }); - - }, - - _scope_set_leases: function() - { - var status; - var self = this; - var scope = this._get_scope(); - - manifold.query_store.iter_records(this.options.query_lease_uuid, function(lease_key, lease) { - console.log("SET LEASES", lease.resource, new Date(lease.start_time* 1000), new Date(lease.end_time* 1000)); - // XXX We should ensure leases are correctly merged, otherwise our algorithm won't work - - // Populate leases by resource array: this will help us merging leases later - - // let's only put _our_ leases - lease_status = manifold.query_store.get_record_state(self.options.query_lease_uuid, lease_key, STATE_SET); - if (lease_status != STATE_SET_IN) - return true; // ~continue - if (!(lease.resource in scope._leases_by_resource)) - scope._leases_by_resource[lease.resource] = []; - scope._leases_by_resource[lease.resource].push(lease); - - }); - - this._set_all_lease_slots(); - }, - - _set_all_lease_slots: function() - { - var self = this; - - manifold.query_store.iter_records(this.options.query_lease_uuid, function(lease_key, lease) { - self._set_lease_slots(lease_key, lease); - }); - }, - - on_resources_query_done: function(data) - { - this._resources_received = true; - this._scope_set_resources(); - this._scope_clear_leases(); - if (this._leases_received) - this._scope_set_leases(); - - this._get_scope().$apply(); - }, - - on_leases_query_done: function(data) - { - this._leases_received = true; - if (this._resources_received) { - this._scope_set_leases(); - this._get_scope().$apply(); - } - }, - - /* Filters on resources */ - on_resources_filter_added: function(filter) { this._get_scope().$apply(); }, - on_resources_filter_removed: function(filter) { this._get_scope().$apply(); }, - on_resources_filter_clear: function() { this._get_scope().$apply(); }, - - /* Filters on leases ? */ - on_leases_filter_added: function(filter) { this._get_scope().$apply(); }, - on_leases_filter_removed: function(filter) { this._get_scope().$apply(); }, - on_leases_filter_clear: function() { this._get_scope().$apply(); }, - - on_field_state_changed: function(data) - { - /* - this._set_lease_slots(lease_key, lease); - - switch(data.state) { - case STATE_SET: - switch(data.op) { - case STATE_SET_IN: - case STATE_SET_IN_SUCCESS: - case STATE_SET_OUT_FAILURE: - this.set_checkbox_from_data(data.value, true); - this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_RESET); - break; - case STATE_SET_OUT: - case STATE_SET_OUT_SUCCESS: - case STATE_SET_IN_FAILURE: - this.set_checkbox_from_data(data.value, false); - this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_RESET); - break; - case STATE_SET_IN_PENDING: - this.set_checkbox_from_data(data.key, true); - this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_ADDED); - break; - case STATE_SET_OUT_PENDING: - this.set_checkbox_from_data(data.key, false); - this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_REMOVED); - break; - } - break; - - case STATE_WARNINGS: - this.change_status(data.key, data.value); - break; - } - */ - }, - - - /* INTERNAL FUNCTIONS */ - - _set_lease_slots: function(lease_key, lease) - { - var resource, lease_status, lease_class; - var day_timestamp, id_start, id_end, colspan_lease; - - resource = this.scope_resources_by_key[lease.resource]; - day_timestamp = SchedulerDateSelected.getTime() / 1000; - id_start = Math.floor((lease.start_time - day_timestamp) / resource.granularity); - - /* Some leases might be in the past */ - if (id_start < 0) - id_start = 0; - /* Leases in the future: ignore */ - if (id_start >= this._all_slots.length) - return true; // ~ continue - - id_end = Math.ceil((lease.end_time - day_timestamp) / resource.granularity); - colspan_lease = resource.granularity / this._slot_length; //eg. 3600 / 1800 => 2 cells - if (id_end >= this._all_slots.length / colspan_lease) { - /* Limit the display to the current day */ - id_end = this._all_slots.length / colspan_lease - } - lease_status = manifold.query_store.get_record_state(this.options.query_lease_uuid, lease_key, STATE_SET); - // the same slots might be affected multiple times. - // PENDING_IN + PENDING_OUT => IN - // - // RESERVED vs SELECTED ! - // - // PENDING !! - switch(lease_status) { - case STATE_SET_IN: - lease_class = 'selected'; // my leases - lease_success = ''; - break; - case STATE_SET_IN_SUCCESS: - lease_class = 'selected'; // my leases - lease_success = 'success'; - case STATE_SET_OUT_FAILURE: - lease_class = 'selected'; // my leases - lease_success = 'failure'; - break; - case STATE_SET_OUT: - lease_class = 'reserved'; // other leases - lease_success = ''; - break; - case STATE_SET_OUT_SUCCESS: - lease_class = 'free'; // other leases - lease_success = 'success'; - break; - case STATE_SET_IN_FAILURE: - lease_class = 'free'; // other leases - lease_success = 'failure'; - break; - case STATE_SET_IN_PENDING: - lease_class = 'pendingin'; - lease_success = ''; - break; - case STATE_SET_OUT_PENDING: - // pending_in & pending_out == IN == replacement - if (resource.leases[i].status == 'pendingin') - lease_class = 'pendingin' - else - lease_class = 'pendingout'; - lease_success = ''; - break; - - } - - for (i = id_start; i < id_end; i++) { - resource.leases[i].status = lease_class; - resource.leases[i].success = lease_success; - } - }, - -/* XXX IN TEMPLATE XXX - if (SchedulerDataViewData.length == 0) { - $("#plugin-scheduler").hide(); - $("#plugin-scheduler-empty").show(); - tmpScope.clearStuff(); - } else { - $("#plugin-scheduler-empty").hide(); - $("#plugin-scheduler").show(); - // initSchedulerResources - tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length); - } -*/ - - /** - * Initialize the date picker, the table, the slider and the buttons. Once done, display scheduler. - */ - _initUI: function() - { - var self = this; - var scope = self._get_scope(); - - var num_hidden_cells; - - $("#DateToRes").datepicker({ - dateFormat: "D, d M yy", - onRender: function(date) { - return date.valueOf() < now.valueOf() ? 'disabled' : ''; - } - }).on('changeDate', function(ev) { - SchedulerDateSelected = new Date(ev.date); - SchedulerDateSelected.setHours(0,0,0,0); - // Set slider to origin - //$('#tblSlider').slider('setValue', 0); // XXX - // Refresh leases - self._scope_clear_leases(); - self._set_all_lease_slots(); - // Refresh display - self._get_scope().$apply(); - }).datepicker('setValue', SchedulerDateSelected); //.data('datepicker'); - - //init Slider - num_hidden_cells = self._all_slots.length - self._num_visible_cells; - init_cell = (new Date().getHours() - 1) * 3600 / self._granularity; - if (init_cell > num_hidden_cells) - init_cell = num_hidden_cells; - - $('#tblSlider').slider({ - min: 0, - max: num_hidden_cells, - value: init_cell, - }).on('slide', function(ev) { - var scope = self._get_scope(); - scope.from = ev.value; - scope.$apply(); - }); - scope.from = init_cell; - scope.$apply(); - - $("#plugin-scheduler-loader").hide(); - $("#plugin-scheduler").show(); - }, - - // PRIVATE METHODS - - /** - * Greatest common divisor - */ - _gcd : function(x, y) - { - return (y==0) ? x : this._gcd(y, x % y); - }, - - _gcdn : function(array) - { - var self = this; - return array.reduce(function(prev, cur, idx, arr) { return self._gcd(prev, cur); }); - }, - - /** - * Least common multiple - */ - _lcm : function(x, y) - { - return x * y / this._gcd(x, y); - }, - - _lcmn : function(array) - { - var self = this; - return array.reduce(function(prev, cur, idx, arr) { return self._lcm(prev, cur); }); - }, - - _pad_str : function(i) - { - return (i < 10) ? "0" + i : "" + i; - }, - - /** - * Member variables used: - * _granularity - * - * Returns: - * A list of {id, time} dictionaries. - */ - _generate_all_slots: function() - { - var slots = []; - // Start with a random date (a first of a month), only time will matter - var d = new Date(2014, 1, 1, 0, 0, 0, 0); - var i = 0; - // Loop until we change the day - while (d.getDate() == 1) { - // Nicely format the time... - var tmpTime = this._pad_str(d.getHours()) + ':' + this._pad_str(d.getMinutes()); - /// ...and add the slot to the list of results - slots.push({ id: i, time: tmpTime }); - // Increment the date with the granularity - d = new Date(d.getTime() + this._slot_length * 1000); - i++; - } - return slots; - - }, - }); - - /* Plugin registration */ - $.plugin('Scheduler2', scheduler2); - -})(jQuery); - - - +/* +# +# Copyright (c) 2013 NITLab, University of Thessaly, CERTH, Greece +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# +# This is a MySlice plugin for the NITOS Scheduler +# Nitos Scheduler v1 +# +*/ + +// XXX groupid = all slots those that go with a min granularity + +/* some params */ +var scheduler2; +var scheduler2Instance; +//is ctrl keyboard button pressed +var schedulerCtrlPressed = false; +//table Id +var schedulerTblId = "scheduler-reservation-table"; +var SCHEDULER_FIRST_COLWIDTH = 200; + + +/* Number of scheduler slots per hour. Used to define granularity. Should be inferred from resources XXX */ +var schedulerSlotsPerHour = 6; +var RESOURCE_DEFAULT_GRANULARITY = 1800 /* s */; // should be computed automatically from resource information +var DEFAULT_GRANULARITY = 1800 /* s */; // should be computed automatically from resource information. Test with 600 +var DEFAULT_PAGE_RANGE = 5; + +var schedulerMaxRows = 12; + +/* All resources */ +var SchedulerData = []; + +/* ??? */ +var SchedulerSlots = []; + +var SchedulerDateSelected = new Date(); +// Round to midnight +SchedulerDateSelected.setHours(0,0,0,0); + +/* Filtered resources */ +var SchedulerDataViewData = []; + +var SchedulerSlotsViewData = []; +//Help Variables +var _schedulerCurrentCellPosition = 0; +//Enable Debug +var schedulerDebug = true; +//tmp to delete +var tmpSchedulerLeases = []; + +var SCHEDULER_COLWIDTH = 50; + + +/****************************************************************************** + * ANGULAR CONTROLLER * + ******************************************************************************/ + +// Create a private execution space for our controller. When +// executing this function expression, we're going to pass in +// the Angular reference and our application module. +(function (ng, app) { + + // Define our Controller constructor. + function Controller($scope) { + + // Store the scope so we can reference it in our + // class methods + this.scope = $scope; + + // Set up the default scope value. + this.scope.errorMessage = null; + this.scope.name = ""; + + //Pagin + $scope.current_page = 1; + this.scope.items_per_page = 10; + $scope.from = 0; // JORDAN + + $scope.instance = null; + $scope.resources = new Array(); + $scope.slots = SchedulerSlotsViewData; + $scope.granularity = DEFAULT_GRANULARITY; /* Will be setup */ + //$scope.msg = "hello"; + + angular.element(document).ready(function() { + //console.log('Hello World'); + //alert('Hello World'); + //afterAngularRendered(); + }); + + // Pagination + + $scope.range = function() { + var range_size = $scope.page_count() > DEFAULT_PAGE_RANGE ? DEFAULT_PAGE_RANGE : $scope.page_count(); + var ret = []; + var start; + + start = $scope.current_page; + if ( start > $scope.page_count()-range_size ) { + start = $scope.page_count()-range_size+1; + } + + for (var i=start; i 1) { + $scope.current_page--; + } + }; + + $scope.prevPageDisabled = function() { + return $scope.current_page === 1 ? "disabled" : ""; + }; + + $scope.page_count = function() + { + // XXX need visible resources only + var query_ext, visible_resources_length; + if (!$scope.instance) + return 0; + query_ext = manifold.query_store.find_analyzed_query_ext($scope.instance.options.query_uuid); + var visible_resources_length = 0; + query_ext.state.each(function(i, state) { + if (state[STATE_VISIBLE]) + visible_resources_length++; + }); + return Math.ceil(visible_resources_length/$scope.items_per_page); + }; + + $scope.nextPage = function() { + if ($scope.current_page < $scope.page_count()) { + $scope.current_page++; + } + }; + + $scope.nextPageDisabled = function() { + return $scope.current_page === $scope.page_count() ? "disabled" : ""; + }; + + $scope.setPage = function(n) { + $scope.current_page = n; + }; + // END pagination + + // FILTER + + $scope.filter_visible = function(resource) + { + return manifold.query_store.get_record_state($scope.instance.options.query_uuid, resource['urn'], STATE_VISIBLE); + }; + + // SELECTION + + $scope._create_new_lease = function(resource_urn, start_time, end_time) + { + var lease_key, new_lease, data; + + lease_key = manifold.metadata.get_key('lease'); + + new_lease = { + resource: resource_urn, + start_time: start_time, + end_time: end_time, + }; + + // This is needed to create a hashable object + new_lease.hashCode = manifold.record_hashcode(lease_key.sort()); + new_lease.equals = manifold.record_equals(lease_key); + + data = { + state: STATE_SET, + key : null, + op : STATE_SET_ADD, + value: new_lease + } + manifold.raise_event($scope.instance.options.query_lease_uuid, FIELD_STATE_CHANGED, data); + /* Add to local cache also, unless we listen to events from outside */ + if (!(resource_urn in $scope._leases_by_resource)) + $scope._leases_by_resource[resource_urn] = []; + $scope._leases_by_resource[resource_urn].push(new_lease); + } + + $scope._remove_lease = function(other) + { + var lease_key, other_key, data; + + lease_key = manifold.metadata.get_key('lease'); + + // XXX This could be a manifold.record_get_value + other_key = { + resource: other.resource, + start_time: other.start_time, + end_time: other.end_time + } + other_key.hashCode = manifold.record_hashcode(lease_key.sort()); + other_key.equals = manifold.record_equals(lease_key); + + data = { + state: STATE_SET, + key : null, + op : STATE_SET_REMOVE, + value: other_key + } + manifold.raise_event($scope.instance.options.query_lease_uuid, FIELD_STATE_CHANGED, data); + /* Remove from local cache also, unless we listen to events from outside */ + $scope._leases_by_resource[other.resource] = $.grep($scope._leases_by_resource[other.resource], function(x) { return x != other; }); + + } + + $scope.select = function(index, model_lease, model_resource) + { + var data, resource_granularity; + + //resource_granularity = model_resource.granularity === undefined ? RESOURCE_DEFAULT_GRANULARITY : model_resource.granularity; + + console.log("Selected", index, model_lease, model_resource); + + var day_timestamp = SchedulerDateSelected.getTime() / 1000; + var start_time = day_timestamp + index * model_resource.granularity; // XXX resource_granularity + var end_time = day_timestamp + (index + 1) * model_resource.granularity; // + var start_date = new Date(start_time * 1000); + var end_date = new Date(end_time * 1000); + + var lease_key = manifold.metadata.get_key('lease'); + + // We search for leases in the cache we previously constructed + var resource_leases = $scope._leases_by_resource[model_resource.urn]; + + switch (model_lease.status) + { + case 'free': // out + case 'pendingout': + if (resource_leases) { + /* Search for leases before */ + $.each(resource_leases, function(i, other) { + if (other.end_time != start_time) + return true; // ~ continue + + /* The lease 'other' is just before, and there should not exist + * any other lease before it */ + start_time = other.start_time; + + other_key = { + resource: other.resource, + start_time: other.start_time, + end_time: other.end_time + } + // This is needed to create a hashable object + other_key.hashCode = manifold.record_hashcode(lease_key.sort()); + other_key.equals = manifold.record_equals(lease_key); + + data = { + state: STATE_SET, + key : null, + op : STATE_SET_REMOVE, + value: other_key + } + manifold.raise_event($scope.instance.options.query_lease_uuid, FIELD_STATE_CHANGED, data); + /* Remove from local cache also, unless we listen to events from outside */ + $scope._leases_by_resource[model_resource.urn] = $.grep($scope._leases_by_resource[model_resource.urn], function(x) { return x != other; }); + return false; // ~ break + }); + + /* Search for leases after */ + $.each(resource_leases, function(i, other) { + if (other.start_time != end_time) + return true; // ~ continue + + /* The lease 'other' is just after, and there should not exist + * any other lease after it */ + end_time = other.end_time; + other_key = { + resource: other.resource, + start_time: other.start_time, + end_time: other.end_time + } + // This is needed to create a hashable object + other_key.hashCode = manifold.record_hashcode(lease_key.sort()); + other_key.equals = manifold.record_equals(lease_key); + + data = { + state: STATE_SET, + key : null, + op : STATE_SET_REMOVE, + value: other_key + } + manifold.raise_event($scope.instance.options.query_lease_uuid, FIELD_STATE_CHANGED, data); + /* Remove from local cache also, unless we listen to events from outside */ + $scope._leases_by_resource[model_resource.urn] = $.grep($scope._leases_by_resource[model_resource.urn], function(x) { return x != other; }); + return false; // ~ break + }); + } + + $scope._create_new_lease(model_resource.urn, start_time, end_time); + model_lease.status = (model_lease.status == 'free') ? 'pendingin' : 'selected'; + // unless the exact same lease already existed (pending_out status for the lease, not the cell !!) + + break; + + case 'selected': + case 'pendingin': + // We remove the cell + + /* We search for leases including this cell. Either 0, 1 or 2. + * 0 : NOT POSSIBLE, should be checked. + * 1 : either IN or OUT, we have make no change in the session + * 2 : both will be pending, since we have made a change in the session + * /!\ need to properly remove pending_in leases when removed again + */ + if (resource_leases) { + $.each(resource_leases, function(i, other) { + if ((other.start_time <= start_time) && (other.end_time >= end_time)) { + // The cell is part of this lease. + + // If the cell is not at the beginning of the lease, we recreate a lease with cells before + if (start_time > other.start_time) { + $scope._create_new_lease(model_resource.urn, other.start_time, start_time); + } + + // If the cell is not at the end of the lease, we recreate a lease with cells after + if (end_time < other.end_time) { + $scope._create_new_lease(model_resource.urn, end_time, other.end_time); + } + + // The other lease will be removed + $scope._remove_lease(other); + } + // NOTE: We can interrupt the search if we know that there is a single lease (depending on the status). + }); + } + + // cf comment in previous switch case + model_lease.status = (model_lease.status == 'selected') ? 'pendingout' : 'free'; + + break; + + case 'reserved': + case 'maintainance': + // Do nothing + break; + } + + + $scope._dump_leases(); + }; + + $scope._dump_leases = function() + { + // DEBUG: display all leases and their status in the log + var leases = manifold.query_store.get_records($scope.instance.options.query_lease_uuid); + console.log("--------------------"); + $.each(leases, function(i, lease) { + var key = manifold.metadata.get_key('lease'); + var lease_key = manifold.record_get_value(lease, key); + var state = manifold.query_store.get_record_state($scope.instance.options.query_lease_uuid, lease_key, STATE_SET); + var state_str; + switch(state) { + case STATE_SET_IN: + state_str = 'STATE_SET_IN'; + break; + case STATE_SET_OUT: + state_str = 'STATE_SET_OUT'; + break; + case STATE_SET_IN_PENDING: + state_str = 'STATE_SET_IN_PENDING'; + break; + case STATE_SET_OUT_PENDING: + state_str = 'STATE_SET_OUT_PENDING'; + break; + case STATE_SET_IN_SUCCESS: + state_str = 'STATE_SET_IN_SUCCESS'; + break; + case STATE_SET_OUT_SUCCESS: + state_str = 'STATE_SET_OUT_SUCCESS'; + break; + case STATE_SET_IN_FAILURE: + state_str = 'STATE_SET_IN_FAILURE'; + break; + case STATE_SET_OUT_FAILURE: + state_str = 'STATE_SET_OUT_FAILURE'; + break; + } + console.log("LEASE", new Date(lease.start_time * 1000), new Date(lease.end_time * 1000), lease.resource, state_str); + }); + }; + + // Return this object reference. + return (this); + + } + + // Define the Controller as the constructor function. + app.controller("SchedulerCtrl", Controller); + +})(angular, ManifoldApp); + +/****************************************************************************** + * MANIFOLD PLUGIN * + ******************************************************************************/ + +(function($) { + scheduler2 = Plugin.extend({ + + /** XXX to check + * @brief Plugin constructor + * @param options : an associative array of setting values + * @param element : + * @return : a jQuery collection of objects on which the plugin is + * applied, which allows to maintain chainability of calls + */ + init: function(options, element) { + // Call the parent constructor, see FAQ when forgotten + this._super(options, element); + + var scope = this._get_scope() + scope.instance = this; + + // XXX not needed + scheduler2Instance = this; + + // We need to remember the active filter for datatables filtering + // XXX not needed + this.filters = Array(); + + // XXX BETTER !!!! + $(window).delegate('*', 'keypress', function (evt){ + alert("erm"); + }); + + $(window).keydown(function(evt) { + if (evt.which == 17) { // ctrl + schedulerCtrlPressed = true; + } + }).keyup(function(evt) { + if (evt.which == 17) { // ctrl + schedulerCtrlPressed = false; + } + }); + + // XXX naming + //$("#" + schedulerTblId).on('mousedown', 'td', rangeMouseDown).on('mouseup', 'td', rangeMouseUp).on('mousemove', 'td', rangeMouseMove); + + this._resources_received = false; + this._leases_received = false; + + scope._leases_by_resource = {}; + + /* Listening to queries */ + this.listen_query(options.query_uuid, 'resources'); + this.listen_query(options.query_lease_uuid, 'leases'); + + this.elmt().on('show', this, this.on_show); + this.elmt().on('shown.bs.tab', this, this.on_show); + this.elmt().on('resize', this, this.on_resize); + + /* Generate slots according to the default granularity. Should + * be updated when resources arrive. Should be the pgcd in fact XXX */ + this._granularity = DEFAULT_GRANULARITY; + scope.granularity = this._granularity; + this.scope_resources_by_key = {}; + + this.do_resize(); + + scope.from = 0; + + this._initUI(); + + }, + + do_resize: function() + { + var scope = this._get_scope(); + var num_hidden_cells, new_max, lcm; + + // do_resize has to be called when the window is resized, or one parameter changes + // e.g. when new resources have been received + // + this.resource_granularities = [3600, 1800]; //, 2400]; /* s */ + + /* Compute the slot length to accommodate all resources. This + * is the GCD of all resource granularities. */ + this._slot_length = this._gcdn(this.resource_granularities); + + $('#' + schedulerTblId + ' thead tr th:eq(0)').css("width", SCHEDULER_FIRST_COLWIDTH); + //self get width might need fix depending on the template + var tblwidth = $('#scheduler-reservation-table').parent().outerWidth(); + + /* Number of visible cells...*/ + this._num_visible_cells = parseInt((tblwidth - SCHEDULER_FIRST_COLWIDTH) / SCHEDULER_COLWIDTH); + + /* ...should be a multiple of the lcm of all encountered granularities. */ + lcm = this._lcmn(this.resource_granularities) / this._slot_length; + this._num_visible_cells = this._num_visible_cells - this._num_visible_cells % lcm; + + // A list of {id, time} dictionaries representing the slots for the given day + this._all_slots = this._generate_all_slots(); + + /* scope also needs this value */ + scope.slots = this._all_slots; + scope.slot_length = this._slot_length; + scope.num_visible_cells = this._num_visible_cells; + scope.lcm_colspan = this._lcmn(this.resource_granularities); // XXX WHY ? + + /* Redraw... */ + this._scope_clear_leases(); + this._set_all_lease_slots(); + + // Slider max value + if ($('#tblSlider').data('slider') != undefined) { + num_hidden_cells = this._all_slots.length - this._num_visible_cells; + + $('#tblSlider').slider('setAttribute', 'max', num_hidden_cells); + $('#tblSlider').slider('setValue', scope.from, true); + } + this._get_scope().$apply(); + + + }, + + on_show: function(e) + { + var self = e.data; + self.do_resize(); + self._get_scope().$apply(); + }, + + on_resize: function(e) + { + var self = e.data; + self.do_resize(); + self._get_scope().$apply(); + }, + + /* Handlers */ + + _get_scope : function() + { + return angular.element(document.getElementById('SchedulerCtrl')).scope(); + }, + + _scope_set_resources : function() + { + var self = this; + var scope = this._get_scope(); + + var records = manifold.query_store.get_records(this.options.query_uuid); + + scope.resources = []; + + $.each(records, function(i, record) { + if (!record.exclusive) + return true; // ~ continue + + // copy not to modify original record + var resource = jQuery.extend(true, {}, record); + + // Fix granularity + //resource_granularity = ((resource.granularity === undefined) || (typeof(resource.granularity) != "number")) ? RESOURCE_DEFAULT_GRANULARITY : resource.granularity; + if (typeof(resource.granularity) != "number") + resource.granularity = RESOURCE_DEFAULT_GRANULARITY; + resource.leases = []; // a list of occupied timeslots + + self.scope_resources_by_key[resource['urn']] = resource; + scope.resources.push(resource); + }); + }, + + _scope_clear_leases: function() + { + var time, now; + var self = this; + var scope = this._get_scope(); + + now = new Date().getTime(); + + // Setup leases with a default free status... + $.each(this.scope_resources_by_key, function(resource_key, resource) { + resource.leases = []; + var colspan_lease = resource.granularity / self._slot_length; //eg. 3600 / 1800 => 2 cells + time = SchedulerDateSelected.getTime(); + for (i=0; i < self._all_slots.length / colspan_lease; i++) { // divide by granularity + resource.leases.push({ + id: 'coucou', + status: (time < now) ? 'disabled': 'free', // 'selected', 'reserved', 'maintenance' XXX pending ?? + }); + time += resource.granularity * 1000; + } + }); + + }, + + _scope_set_leases: function() + { + var status; + var self = this; + var scope = this._get_scope(); + + manifold.query_store.iter_records(this.options.query_lease_uuid, function(lease_key, lease) { + //console.log("SET LEASES", lease.resource, new Date(lease.start_time* 1000), new Date(lease.end_time* 1000)); + // XXX We should ensure leases are correctly merged, otherwise our algorithm won't work + + // Populate leases by resource array: this will help us merging leases later + + // let's only put _our_ leases + lease_status = manifold.query_store.get_record_state(self.options.query_lease_uuid, lease_key, STATE_SET); + if (lease_status != STATE_SET_IN) + return true; // ~continue + if (!(lease.resource in scope._leases_by_resource)) + scope._leases_by_resource[lease.resource] = []; + scope._leases_by_resource[lease.resource].push(lease); + + }); + + this._set_all_lease_slots(); + }, + + _set_all_lease_slots: function() + { + var self = this; + + manifold.query_store.iter_records(this.options.query_lease_uuid, function(lease_key, lease) { + self._set_lease_slots(lease_key, lease); + }); + }, + + on_resources_query_done: function(data) + { + this._resources_received = true; + this._scope_set_resources(); + this._scope_clear_leases(); + if (this._leases_received) + this._scope_set_leases(); + + this._get_scope().$apply(); + }, + + on_leases_query_done: function(data) + { + this._leases_received = true; + if (this._resources_received) { + this._scope_set_leases(); + this._get_scope().$apply(); + } + }, + + /* Filters on resources */ + on_resources_filter_added: function(filter) { this._get_scope().$apply(); }, + on_resources_filter_removed: function(filter) { this._get_scope().$apply(); }, + on_resources_filter_clear: function() { this._get_scope().$apply(); }, + + /* Filters on leases ? */ + on_leases_filter_added: function(filter) { this._get_scope().$apply(); }, + on_leases_filter_removed: function(filter) { this._get_scope().$apply(); }, + on_leases_filter_clear: function() { this._get_scope().$apply(); }, + + on_field_state_changed: function(data) + { + /* + this._set_lease_slots(lease_key, lease); + + switch(data.state) { + case STATE_SET: + switch(data.op) { + case STATE_SET_IN: + case STATE_SET_IN_SUCCESS: + case STATE_SET_OUT_FAILURE: + this.set_checkbox_from_data(data.value, true); + this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_RESET); + break; + case STATE_SET_OUT: + case STATE_SET_OUT_SUCCESS: + case STATE_SET_IN_FAILURE: + this.set_checkbox_from_data(data.value, false); + this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_RESET); + break; + case STATE_SET_IN_PENDING: + this.set_checkbox_from_data(data.key, true); + this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_ADDED); + break; + case STATE_SET_OUT_PENDING: + this.set_checkbox_from_data(data.key, false); + this.set_bgcolor(data.value, QUERYTABLE_BGCOLOR_REMOVED); + break; + } + break; + + case STATE_WARNINGS: + this.change_status(data.key, data.value); + break; + } + */ + }, + + + /* INTERNAL FUNCTIONS */ + + _set_lease_slots: function(lease_key, lease) + { + var resource, lease_status, lease_class; + var day_timestamp, id_start, id_end, colspan_lease; + + resource = this.scope_resources_by_key[lease.resource]; + day_timestamp = SchedulerDateSelected.getTime() / 1000; + if(resource === undefined){ + console.log('resource undefined = '+lease.resource); + return; + } + id_start = Math.floor((lease.start_time - day_timestamp) / resource.granularity); + + /* Some leases might be in the past */ + if (id_start < 0) + id_start = 0; + /* Leases in the future: ignore */ + if (id_start >= this._all_slots.length) + return true; // ~ continue + + id_end = Math.ceil((lease.end_time - day_timestamp) / resource.granularity); + colspan_lease = resource.granularity / this._slot_length; //eg. 3600 / 1800 => 2 cells + if (id_end >= this._all_slots.length / colspan_lease) { + /* Limit the display to the current day */ + id_end = this._all_slots.length / colspan_lease + } + lease_status = manifold.query_store.get_record_state(this.options.query_lease_uuid, lease_key, STATE_SET); + // the same slots might be affected multiple times. + // PENDING_IN + PENDING_OUT => IN + // + // RESERVED vs SELECTED ! + // + // PENDING !! + switch(lease_status) { + case STATE_SET_IN: + lease_class = 'selected'; // my leases + lease_success = ''; + break; + case STATE_SET_IN_SUCCESS: + lease_class = 'selected'; // my leases + lease_success = 'success'; + case STATE_SET_OUT_FAILURE: + lease_class = 'selected'; // my leases + lease_success = 'failure'; + break; + case STATE_SET_OUT: + lease_class = 'reserved'; // other leases + lease_success = ''; + break; + case STATE_SET_OUT_SUCCESS: + lease_class = 'free'; // other leases + lease_success = 'success'; + break; + case STATE_SET_IN_FAILURE: + lease_class = 'free'; // other leases + lease_success = 'failure'; + break; + case STATE_SET_IN_PENDING: + lease_class = 'pendingin'; + lease_success = ''; + break; + case STATE_SET_OUT_PENDING: + // pending_in & pending_out == IN == replacement + if (resource.leases[i].status == 'pendingin') + lease_class = 'pendingin' + else + lease_class = 'pendingout'; + lease_success = ''; + break; + + } + + for (i = id_start; i < id_end; i++) { + resource.leases[i].status = lease_class; + resource.leases[i].success = lease_success; + } + }, + +/* XXX IN TEMPLATE XXX + if (SchedulerDataViewData.length == 0) { + $("#plugin-scheduler").hide(); + $("#plugin-scheduler-empty").show(); + tmpScope.clearStuff(); + } else { + $("#plugin-scheduler-empty").hide(); + $("#plugin-scheduler").show(); + // initSchedulerResources + tmpScope.initSchedulerResources(schedulerMaxRows < SchedulerDataViewData.length ? schedulerMaxRows : SchedulerDataViewData.length); + } +*/ + + /** + * Initialize the date picker, the table, the slider and the buttons. Once done, display scheduler. + */ + _initUI: function() + { + var self = this; + var scope = self._get_scope(); + + var num_hidden_cells; + + $("#DateToRes").datepicker({ + dateFormat: "D, d M yy", + onRender: function(date) { + return date.valueOf() < now.valueOf() ? 'disabled' : ''; + } + }).on('changeDate', function(ev) { + SchedulerDateSelected = new Date(ev.date); + SchedulerDateSelected.setHours(0,0,0,0); + // Set slider to origin + //$('#tblSlider').slider('setValue', 0); // XXX + // Refresh leases + self._scope_clear_leases(); + self._set_all_lease_slots(); + // Refresh display + self._get_scope().$apply(); + }).datepicker('setValue', SchedulerDateSelected); //.data('datepicker'); + + //init Slider + num_hidden_cells = self._all_slots.length - self._num_visible_cells; + init_cell = (new Date().getHours() - 1) * 3600 / self._granularity; + if (init_cell > num_hidden_cells) + init_cell = num_hidden_cells; + + $('#tblSlider').slider({ + min: 0, + max: num_hidden_cells, + value: init_cell, + }).on('slide', function(ev) { + var scope = self._get_scope(); + scope.from = ev.value; + scope.$apply(); + }); + scope.from = init_cell; + scope.$apply(); + + $("#plugin-scheduler-loader").hide(); + $("#plugin-scheduler").show(); + }, + + // PRIVATE METHODS + + /** + * Greatest common divisor + */ + _gcd : function(x, y) + { + return (y==0) ? x : this._gcd(y, x % y); + }, + + _gcdn : function(array) + { + var self = this; + return array.reduce(function(prev, cur, idx, arr) { return self._gcd(prev, cur); }); + }, + + /** + * Least common multiple + */ + _lcm : function(x, y) + { + return x * y / this._gcd(x, y); + }, + + _lcmn : function(array) + { + var self = this; + return array.reduce(function(prev, cur, idx, arr) { return self._lcm(prev, cur); }); + }, + + _pad_str : function(i) + { + return (i < 10) ? "0" + i : "" + i; + }, + + /** + * Member variables used: + * _granularity + * + * Returns: + * A list of {id, time} dictionaries. + */ + _generate_all_slots: function() + { + var slots = []; + // Start with a random date (a first of a month), only time will matter + var d = new Date(2014, 1, 1, 0, 0, 0, 0); + var i = 0; + // Loop until we change the day + while (d.getDate() == 1) { + // Nicely format the time... + var tmpTime = this._pad_str(d.getHours()) + ':' + this._pad_str(d.getMinutes()); + /// ...and add the slot to the list of results + slots.push({ id: i, time: tmpTime }); + // Increment the date with the granularity + d = new Date(d.getTime() + this._slot_length * 1000); + i++; + } + return slots; + + }, + }); + + /* Plugin registration */ + $.plugin('Scheduler2', scheduler2); + +})(jQuery); + + + diff --git a/portal/accountview.py b/portal/accountview.py index 264948ac..dfda1826 100644 --- a/portal/accountview.py +++ b/portal/accountview.py @@ -418,7 +418,6 @@ def account_process(request): sfa_update_user(request, user_hrn, user_pub_key) result_sfa_user = sfa_get_user(request, user_hrn, public_key) try: - result_sfa_user = result_sfa_user[0] if 'keys' in result_sfa_user and result_sfa_user['keys'][0] == public_key: # updating manifold updated_config = json.dumps(account_config) @@ -427,7 +426,7 @@ def account_process(request): messages.success(request, 'Sucess: New Keypair Generated! Delegation of your credentials will be automatic.') else: raise Exception,"Keys are not matching" - except Exception,e: + except Exception, e: messages.error(request, 'Error: An error occured during the update of your public key at the Registry, or your public key is not matching the one stored.') print "Exception in accountview ", e return HttpResponseRedirect("/portal/account/") diff --git a/portal/actions.py b/portal/actions.py index fa3ed105..047288d2 100644 --- a/portal/actions.py +++ b/portal/actions.py @@ -1060,10 +1060,11 @@ def iotlab_create_user (wsgi_request, request, namespace = None, as_admin=False) import requests import time from requests.auth import HTTPBasicAuth - - URL_REST = ConfigEngine.default_iotlab_url - LOGIN_ADMIN = ConfigEngine.default_iotlab_admin_user - PASSWORD_ADMIN = ConfigEngine.default_iotlab_admin_password + + engine = ConfigEngine() + URL_REST = engine.iotlab_url() + LOGIN_ADMIN = engine.iotlab_admin_user() + PASSWORD_ADMIN = engine.iotlab_admin_password() auth = HTTPBasicAuth(LOGIN_ADMIN,PASSWORD_ADMIN) headers = {'content-type': 'application/json'} diff --git a/portal/joinview.py b/portal/joinview.py index 0282e962..2add3a4f 100644 --- a/portal/joinview.py +++ b/portal/joinview.py @@ -173,7 +173,7 @@ class JoinView (FreeAccessView, ThemeView): 'user_hrn' : user_hrn, 'pi' : [reg_auth], 'auth_type' : 'managed', - 'validation_link': 'http://' + current_site + '/portal/email_activation/'+ email_hash + 'validation_link': current_site + '/portal/email_activation/'+ email_hash } diff --git a/portal/projectrequestview.py b/portal/projectrequestview.py index aaa79b2f..8a484282 100644 --- a/portal/projectrequestview.py +++ b/portal/projectrequestview.py @@ -109,7 +109,7 @@ class ProjectRequestView(LoginRequiredAutoLogoutView, ThemeView): errors.append('Organization is mandatory') if (post['purpose'] is None or post['purpose'] == ''): - errors.append('Experiment purpose is mandatory') + errors.append('Project purpose is mandatory') if (re.search(r'^[A-Za-z0-9_]*$', post['project_name']) == None): errors.append('Project name may contain only letters, numbers, and underscore.') @@ -128,14 +128,14 @@ class ProjectRequestView(LoginRequiredAutoLogoutView, ThemeView): hrn = post['authority_hrn'] + '.' + post['project_name'] sfa_add_authority(wsgi_request, {'authority_hrn':hrn}) authority_add_pis(wsgi_request, hrn, user_hrn) - self.template_name = 'slice-request-done-view.html' + self.template_name = 'project-request-done-view.html' else: # Otherwise a wsgi_request is sent to the PI if 'join' in wsgi_request.POST: create_pending_join(wsgi_request, post) else: create_pending_project(wsgi_request, post) - self.template_name = 'slice-request-ack-view.html' + self.template_name = 'project-request-ack-view.html' # retrieves the pending projects creation list pending_projects = PendingProject.objects.all().filter(user_hrn=user_hrn) diff --git a/portal/registrationview.py b/portal/registrationview.py index 47ae6c9b..d1c12ca5 100644 --- a/portal/registrationview.py +++ b/portal/registrationview.py @@ -81,7 +81,7 @@ class RegistrationView (FreeAccessView, ThemeView): 'current_site' : current_site, 'email_hash' : email_hash, 'pi' : '', - 'validation_link': 'http://' + current_site + '/portal/email_activation/'+ email_hash + 'validation_link': current_site + '/portal/email_activation/'+ email_hash } print "############ BREAKPOINT 4 #################" diff --git a/portal/slicetabexperiment.py b/portal/slicetabexperiment.py index f198e158..1779d1c8 100644 --- a/portal/slicetabexperiment.py +++ b/portal/slicetabexperiment.py @@ -17,6 +17,8 @@ from myslice.configengine import ConfigEngine from myslice.theme import ThemeView from myslice.configengine import ConfigEngine +from sfa.planetlab.plxrn import hash_loginbase + import urllib2,json class ExperimentView (FreeAccessView, ThemeView): @@ -26,12 +28,14 @@ class ExperimentView (FreeAccessView, ThemeView): username = self.request.user - split_slicename = slicename.split('.') - ple_slicename = split_slicename[0] + '8' + split_slicename[1] + '_' + split_slicename[2] - - query_current_resources = Query.get('slice').select('resource').filter_by('slice_hrn','==',slicename) + query_current_resources = Query.get('slice').select('resource','parent_authority').filter_by('slice_hrn','==',slicename) current_resources = execute_query(request, query_current_resources) + parent_authority = current_resources[0]['parent_authority'] + + split_slicename = slicename.split('.') + ple_slicename = hash_loginbase(parent_authority) + '_' + split_slicename[-1] + ple_resource_list=[] nitos_resource_list=[] nitos_paris_resource_list=[] @@ -75,6 +79,7 @@ class ExperimentView (FreeAccessView, ThemeView): #print nitos_resource_list #get all iotlab users + all_users = list() try: engine = ConfigEngine() userData = "Basic " + (engine.iotlab_admin_user() + ":" + engine.iotlab_admin_password()).encode("base64").rstrip() @@ -88,7 +93,6 @@ class ExperimentView (FreeAccessView, ThemeView): except urllib2.URLError as e: print "There is a problem in getting iotlab users %s" % e.reason - all_users = list() #getting the login from email #initial value no-account == contact_admin diff --git a/portal/static/css/smartfire.css b/portal/static/css/smartfire.css index e6d06d78..46271241 100644 --- a/portal/static/css/smartfire.css +++ b/portal/static/css/smartfire.css @@ -13,7 +13,7 @@ body { a, a:active, a:focus { outline: 0; text-decoration:none; - color:#760073; + color:#FF4400; } a:hover { color:#0D0049; @@ -178,14 +178,14 @@ button.btn-danger:active { } button.btn-onelab, input.btn-onelab { border:0; - border-bottom:3px solid #760073; - background-color:#302562; + border-bottom:3px solid #FFA315; + background-color:#FFA315; color:white; } button.btn-onelab:hover, input.btn-onelab:hover { border:0; - border-bottom:3px solid #760073; - background-color:#302562; + border-bottom:3px solid #FF7E00; + background-color:#FF7E00; color:white; } button.btn-onelab:active, input.btn-onelab:active { @@ -590,7 +590,7 @@ div.navigation li a { color:#0C0047; } div.navigation li a:hover, div.navigation li a.current { - color:#760073; + color:#FF4400; text-decoration:none; } @@ -729,7 +729,7 @@ div.home { line-height:1.2em; letter-spacing:0.3pt; min-height:500px; - //background-image: url('../img/bg-experiment.png'); + background-image: url('../img/bg-smartfire.png'); background-repeat:no-repeat; background-size:cover; background-position:center top; @@ -812,7 +812,6 @@ div.registration-form { div.slogan { text-align:center; color:white; - padding-top:60px; text-shadow: 1px 1px #013540; } diff --git a/portal/static/icons/IoTLab.png b/portal/static/icons/iotlab.png similarity index 100% rename from portal/static/icons/IoTLab.png rename to portal/static/icons/iotlab.png diff --git a/portal/static/icons/Mobile.png b/portal/static/icons/mobile.png similarity index 100% rename from portal/static/icons/Mobile.png rename to portal/static/icons/mobile.png diff --git a/portal/static/icons/PlanetLab.png b/portal/static/icons/planetlab.png similarity index 100% rename from portal/static/icons/PlanetLab.png rename to portal/static/icons/planetlab.png diff --git a/portal/static/icons/Wireless.png b/portal/static/icons/wireless.png similarity index 100% rename from portal/static/icons/Wireless.png rename to portal/static/icons/wireless.png diff --git a/portal/static/img/bg-smartfire.png b/portal/static/img/bg-smartfire.png new file mode 100644 index 00000000..f5340fc4 Binary files /dev/null and b/portal/static/img/bg-smartfire.png differ diff --git a/portal/templates/_widget-topmenu.html b/portal/templates/_widget-topmenu.html index 6236344a..668c3d32 100644 --- a/portal/templates/_widget-topmenu.html +++ b/portal/templates/_widget-topmenu.html @@ -1,51 +1,49 @@ - -

-

Organization not listed? Request its addition now.

diff --git a/portal/templates/slice-resource-view.html b/portal/templates/slice-resource-view.html index 93285e12..3fefedf7 100644 --- a/portal/templates/slice-resource-view.html +++ b/portal/templates/slice-resource-view.html @@ -54,9 +54,7 @@ $(document).ready(function() { @@ -92,24 +90,6 @@ $(document).ready(function() {
{{map_resources}}
-
-

{{vms_list}}

-

{{vm_form}}

- -

{{below_table}}

-
- -
-

{{welcome}}

-

{{flowspaces}}

-

{{flowspaces_form}}

-

{{oflowspaces_form}}

-

{{topology}}

-

{{resources}}

- -

{{below_table}}

-
-
{{scheduler}}
diff --git a/portal/templates/slice-tab-experiment.html b/portal/templates/slice-tab-experiment.html index ce97efa1..e10c88f9 100644 --- a/portal/templates/slice-tab-experiment.html +++ b/portal/templates/slice-tab-experiment.html @@ -16,7 +16,6 @@ {%endfor%}

NOTE: Your original slicename {{slicename}} has been converted to PlanetLab specific format {{ple_slicename}} in order to do SSH.

-

Please note that the first '.' is replaced by number 8 and the rest of the dot/s are replaced by underscore/s.

Be aware that after you reserve a PlanetLab Europe resource your slice will be deployed with a delay of about 15 minutes, after witch you will be able to access the resource. @@ -74,7 +73,7 @@ the following command:

- ssh {{iot_login}}@fit3-dev.inrialpes.fr + ssh {{iot_login}}@grenoble.iot-lab.info

{% endif %} {% if nitos_resources or nitos_paris_resources %} @@ -88,18 +87,22 @@ {% if nitos_resources %}

NITLab

- $ ssh {{slicename}}@nitlab.inf.uth.gr -

+ $ ssh {{slicename}}@nitlab.inf.uth.gr #nodes 001-040
+ $ ssh {{slicename}}@nitlab2.inf.uth.gr #nodes 041-049
+ $ ssh {{slicename}}@nitlab3.inf.uth.gr #nodes > 049 +

-

For each of the reserved nodes, follo the steps given below:

+

Loading an OMF-compatible image on your resource:

{%for resource in nitos_resources %} Resource
- $ omf load -i baseline_grid.ndz -t {{resource}} #loading OMF image on the node
- $ omf tell -a on -t {{resource}} #turn on the node
- $ ssh root@{{resource}} #ssh to the node

+ $ omf6 stat -t {{resource}} #check the status of the node
+ $ omf6 tell -a on -t {{resource}} #turn on/off the node
+ $ omf6 load -i baseline.ndz -t {{resource}} #for orbit-like node (002-009) use "baseline_orbit.ndz"
+ $ ssh root@{{resource}} #ssh to the node
{%endfor%}

+

NOTE: Nodes 002-009 are orbit-like nodes. For these nodes use "baseline_orbit.ndz". All these images come with OMF5.4 resource controller. To do OMF6 experiments use "baseline_omf6_1_1.ndz" and "baseline_orbit_omf6_1_1.ndz" for grid nodes and orbit nodes respectively.

{% endif %} {% if nitos_paris_resources %} @@ -119,17 +122,18 @@ {%endif%}

- On the node itself you will have to modify the file /etc/omf-resctl-5.3/omf-resctl.yaml according to your slice settings and then + On the node itself you will have to modify the file /etc/omf-resctl-5.3/omf-resctl.yaml (OMF5.4 only) according to your slice settings and then restart the OMF Resource Controller and finally execute the experiment:

$ omf exec --slice {{slicename}} your_exp.rb

- The complete tutorial is available at the following address: + The complete tutorial on NITOS nodes: NITOS basic tutorial

-

To learn more about OMF6, please click here.

+

OMF based experiments' tutorials are available here.

+

To learn more about OMF, please click here.

{% endif %} diff --git a/portal/templates/smartfire/smartfire_account-view.html b/portal/templates/smartfire/smartfire_account-view.html index 199444a3..985974fb 100644 --- a/portal/templates/smartfire/smartfire_account-view.html +++ b/portal/templates/smartfire/smartfire_account-view.html @@ -1,15 +1,20 @@ {% extends "layout.html" %} +{% load portal_filters %} {% block content %} - +{% widget "_widget-no_credentials.html" %} +{% widget "_widget-tradeoff.html" %}
- {%if 'no_creds' in user_cred %} + {%if 'no_creds' in user_cred %}

NO CREDENTIALS are delegated to the portal!

-{%endif%} + {%endif%} + {%if 'creds_expired' in user_cred %} +

EXPIRED CREDENTIALS Please delegate again your credentials to the portal!

+ {%endif%}
{% if messages %} @@ -19,6 +24,10 @@ {% endfor %} {% endif %} + +
+ +
- -
@@ -321,7 +320,7 @@ {{ row.account_type }} {{ row.account_reference }} - @@ -340,7 +339,7 @@ {{ platform.platform_no_access }} - @@ -350,16 +349,20 @@
{%endif%}
-
+ -{# widget "_widget-monitor.html" #} -{# widget "_widget-stats-top-slices.html" #} {% endblock %} diff --git a/portal/templates/smartfire/smartfire_slice_request_denied.html b/portal/templates/smartfire/smartfire_slice_request_denied.html new file mode 100644 index 00000000..6c7d595e --- /dev/null +++ b/portal/templates/smartfire/smartfire_slice_request_denied.html @@ -0,0 +1,17 @@ + +
+

Dear SmartFIRE user,

+

+

You have recently requested the following slice on the SmartFIRE portal({{portal_url}}):

+
+Slice name : {{slice_name}}
+URL : {{url}}
+Purpose : {{purpose}}
+
+

We regret to inform you that, a manager of your institution has not confirmed your request. Please contact the manager of your institution for further information. +For any other queries, please contact us by replying to this email.

+
+

We wish you a fruitful user experience on SmartFIRE.

+
+

Yours sincerely,

+

The SmartFIRE team

diff --git a/portal/templates/smartfire/smartfire_slice_request_denied.txt b/portal/templates/smartfire/smartfire_slice_request_denied.txt new file mode 100644 index 00000000..e4b49903 --- /dev/null +++ b/portal/templates/smartfire/smartfire_slice_request_denied.txt @@ -0,0 +1,14 @@ +Dear SmartFIRE user, + +You have recently requested the following slice on the SmartFIRE portal({{portal_url}}): + +Slice name : {{slice_name}} +URL : {{url}} +Purpose : {{purpose}} + +We regret to inform you that, a manager of your institution has not confirmed your request. Please contact the manager of your institution for further information. For any other queries, please contact us by replying to this email. + +We wish you a fruitful user experience on SmartFIRE. + +Yours sincerely, +The SmartFIRE team diff --git a/portal/templates/smartfire/smartfire_slice_request_email_subject.txt b/portal/templates/smartfire/smartfire_slice_request_email_subject.txt new file mode 100644 index 00000000..e3988dfc --- /dev/null +++ b/portal/templates/smartfire/smartfire_slice_request_email_subject.txt @@ -0,0 +1 @@ +Slice request submitted diff --git a/portal/templates/smartfire/smartfire_slice_request_validated.html b/portal/templates/smartfire/smartfire_slice_request_validated.html new file mode 100644 index 00000000..2c96a1db --- /dev/null +++ b/portal/templates/smartfire/smartfire_slice_request_validated.html @@ -0,0 +1,21 @@ + +
+

Dear SmartFIRE user,

+

+

You have recently requested a slice in the SmartFIRE portal.

+
+Slice name : {{slice_name}}
+URL : {{number_of_nodes}}
+Purpose : {{purpose}}
+

+

+ We are pleased to inform you that a manager from your institution has validated your slice request on the SmartFIRE portal. + You can now add resources to you slice and start experimenting. +

+

+

We wish you a fruitful user experience with the SmartFIRE portal.

+

+

Yours sincerely,

+

The SmartFIRE team

+ + diff --git a/portal/templates/smartfire/smartfire_slice_request_validated.txt b/portal/templates/smartfire/smartfire_slice_request_validated.txt new file mode 100644 index 00000000..571a3e4c --- /dev/null +++ b/portal/templates/smartfire/smartfire_slice_request_validated.txt @@ -0,0 +1,16 @@ +Dear SmartFIRE user, + +You have recently requested a slice in the SmartFIRE portal. + +Slice name : {{slice_name}} +URL : {{number_of_nodes}} +Purpose : {{purpose}} + + +We are pleased to inform you that a manager from your institution has validated your slice request on the SmartFIRE portal. You can now add resources to you slice and start experimenting. + +We wish you a fruitful user experience with the SmartFIRE portal. + +Yours sincerely, +The SmartFIRE team + diff --git a/portal/templates/smartfire/smartfire_user_request_denied.html b/portal/templates/smartfire/smartfire_user_request_denied.html new file mode 100644 index 00000000..64678e3d --- /dev/null +++ b/portal/templates/smartfire/smartfire_user_request_denied.html @@ -0,0 +1,11 @@ + +
+

Dear {{first_name}} {{last_name}},

+

+

You have recently registered as a user to SmartFIRE portal. We are sorry to inform you that, a manager of your institution has rejected your request. Please contact the manager of your institution for further information. For any other queries, contact us by replying to this email.

+

+

We wish you all the best.

+

+

Yours sincerely,

+

The SmartFIRE team

+ diff --git a/portal/templates/smartfire/smartfire_user_request_denied.txt b/portal/templates/smartfire/smartfire_user_request_denied.txt new file mode 100644 index 00000000..29edc211 --- /dev/null +++ b/portal/templates/smartfire/smartfire_user_request_denied.txt @@ -0,0 +1,8 @@ +Dear {{first_name}} {{last_name}}, + +You have recently registered as a user to SmartFIRE portal. We are sorry to inform you that, a manager of your institution has rejected your request. Please contact the manager of your institution for further information. For any other queries, contact us by replying to this email. + +We wish you all the best. + +Yours sincerely, +The SmartFIRE team diff --git a/portal/templates/smartfire/smartfire_user_request_email.html b/portal/templates/smartfire/smartfire_user_request_email.html new file mode 100644 index 00000000..ae8952c2 --- /dev/null +++ b/portal/templates/smartfire/smartfire_user_request_email.html @@ -0,0 +1,16 @@ + +
+

NEW USER REQUEST

+
+First name : {{first_name}}
+Last name : {{last_name}}
+Organization : {{organization}}
+Authority hrn: {{authority_hrn}}
+Public key : {{public_key}}
+Email : {{email}}
+User hrn : {{user_hrn}}
+Portal url : {{ current_site }}
+

+

You can validate the user here.

+
+

Please note that the validation request will only become visible once the user has confirmed his/her email address.

diff --git a/portal/templates/smartfire/smartfire_user_request_email.txt b/portal/templates/smartfire/smartfire_user_request_email.txt new file mode 100644 index 00000000..17ce1842 --- /dev/null +++ b/portal/templates/smartfire/smartfire_user_request_email.txt @@ -0,0 +1,14 @@ +NEW USER REQUEST + +First name : {{first_name}} +Last name : {{last_name}} +Organization :{{organization}} +Authority hrn: {{authority_hrn}} +Public key : {{public_key}} +Email : {{email}} +User hrn : {{user_hrn}} +Portal url : {{ current_site }} + +Please note that the validation request will only become visible once the user has confirmed his/her email address. + + diff --git a/portal/templates/smartfire/smartfire_user_request_email_subject.txt b/portal/templates/smartfire/smartfire_user_request_email_subject.txt new file mode 100644 index 00000000..a373b60f --- /dev/null +++ b/portal/templates/smartfire/smartfire_user_request_email_subject.txt @@ -0,0 +1 @@ +User request submitted diff --git a/portal/templates/smartfire/smartfire_user_request_validated.html b/portal/templates/smartfire/smartfire_user_request_validated.html new file mode 100644 index 00000000..7997a180 --- /dev/null +++ b/portal/templates/smartfire/smartfire_user_request_validated.html @@ -0,0 +1,14 @@ + +
+

Dear {{first_name}} {{last_name}},

+

+

It is my pleasure to welcome you as a fully signed-up user of the SmartFIRE experimental facility. SmartFIRE provides you with access to world class computer networking testbeds. Our aim at SmartFIRE is to promote the use of these testbeds for pre-commercial research and development by industry, for scientific research, and for university level laboratory exercises.

+

+

+Your entry point for access to the testbeds is the SmartFIRE portal, which provides a web-based interface for browsing and reserving resources on the various testbeds. To run an experiment using those resources, you may log in to the testbed and/or individual nodes on the testbed with your SmartFIRE public/private key pair, or you may use an experiment control tool such as as OMF. The SmartFIRE operations team is standing by at support@onelab.eu to provide you with help regarding the portal and to refer your testbed- and tool-specific queries to those best able to answer them. +

+

+

We wish you a fruitful user experience with the SmartFIRE portal.

+

+

Yours sincerely,

+

The SmartFIRE team

diff --git a/portal/templates/smartfire/smartfire_user_request_validated.txt b/portal/templates/smartfire/smartfire_user_request_validated.txt new file mode 100644 index 00000000..b546b19d --- /dev/null +++ b/portal/templates/smartfire/smartfire_user_request_validated.txt @@ -0,0 +1,10 @@ +Dear {{first_name}} {{last_name}}, + +It is our pleasure to welcome you as a fully signed-up user of the SmartFIRE experimental facility. SmartFIRE provides you with access to world class computer networking testbeds.. Our aim at SmartFIRE is to promote the use of these testbeds for pre-commercial research and development by industry, for scientific research, and for university level laboratory exercises. + +Your entry point for access to the testbeds is the SmartFIRE portal, which provides a web-based interface for browsing and reserving resources on the various testbeds. To run an experiment using those resources, you may log in to the testbed and/or to individual nodes on the testbed with your SmartFIRE public/private key pair, or you may use an experiment control tool such as as OMF. The SmartFIRE operations team is standing by at support@onelab.eu to provide you with help regarding the portal and to refer your testbed- and tool-specific queries to those best able to answer them. + +We wish you a fruitful user experience with the SmartFIRE portal. + +Yours sincerely, +The SmartFIRE team diff --git a/portal/templates/smartfire/smartfire_widget-login-user.html b/portal/templates/smartfire/smartfire_widget-login-user.html index 7529c61f..eaa5c2aa 100644 --- a/portal/templates/smartfire/smartfire_widget-login-user.html +++ b/portal/templates/smartfire/smartfire_widget-login-user.html @@ -16,11 +16,8 @@ - diff --git a/portal/templates/smartfire/smartfire_widget-topmenu.html b/portal/templates/smartfire/smartfire_widget-topmenu.html index 738075f9..de34e320 100644 --- a/portal/templates/smartfire/smartfire_widget-topmenu.html +++ b/portal/templates/smartfire/smartfire_widget-topmenu.html @@ -19,7 +19,7 @@ - {%if 'is_pi' in pi %} + {%if pi %} {%endif%}
  • SUPPORT
  • diff --git a/portal/templates/user_register_email.txt b/portal/templates/user_register_email.txt deleted file mode 100644 index dc34c217..00000000 --- a/portal/templates/user_register_email.txt +++ /dev/null @@ -1,4 +0,0 @@ -Your have registered for an account in {{site}}. - -Your activation key is :{{activation_key}}; it will expire in {{expiration_days}} days. - diff --git a/portal/templates/user_register_email_subject.txt b/portal/templates/user_register_email_subject.txt deleted file mode 100644 index 6ec4cc2b..00000000 --- a/portal/templates/user_register_email_subject.txt +++ /dev/null @@ -1 +0,0 @@ -Onelab New User request submitted diff --git a/sla/urls.py b/sla/urls.py index e385bafd..676d108c 100755 --- a/sla/urls.py +++ b/sla/urls.py @@ -3,10 +3,16 @@ from django.conf.urls import patterns, url, include from sla import slicetabsla urlpatterns = patterns('', - url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^testbeds/', slicetabsla.Testbeds.as_view(), name="testbeds"), - url(r'^(?P[^/]+)/?$', slicetabsla.SLAView.as_view(), name="agreements_summary"), - url(r'^agreements/(?P[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/detail$', slicetabsla.agreement_details, name='agreement_details'), - url(r'^agreements/(?P[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/guarantees/(?P\w+)/violations$', slicetabsla.agreement_term_violations, name='agreement_term_violations'), - url(r'^agreements/simplecreate/?$', slicetabsla.AgreementSimple.as_view(), name="agreementsimple"), -) \ No newline at end of file + url(r'^api-auth/', + include('rest_framework.urls', namespace='rest_framework')), + url(r'^testbeds/', + slicetabsla.Testbeds.as_view(), name="testbeds"), + url(r'^(?P[^/]+)/?$', + slicetabsla.SLAView.as_view(), name="agreements_summary"), + url(r'^agreements/(?P[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/detail$', + slicetabsla.agreement_details, name='agreement_details'), + url(r'^agreements/(?P[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/guarantees/(?P\w+)/violations$', + slicetabsla.agreement_term_violations, name='agreement_term_violations'), + url(r'^agreements/simplecreate/?$', + slicetabsla.AgreementSimple.as_view(), name="agreementsimple"), +)