Merge branch 'onelab' of ssh://git.onelab.eu/git/myslice into onelab
authorLoic Baron <loic.baron@lip6.fr>
Wed, 17 Dec 2014 10:46:51 +0000 (11:46 +0100)
committerLoic Baron <loic.baron@lip6.fr>
Wed, 17 Dec 2014 10:46:51 +0000 (11:46 +0100)
Conflicts:
myslice/settings.py

61 files changed:
README
manifoldapi/static/js/manifold.js
myslice/settings.py
myslice/urls.py
plugins/queryupdater/static/js/queryupdater.js
plugins/sladialog/templates/sladialog.html
portal/reputationview.py
portal/servicedirectory.py
portal/static/img/fed4fire_favicon.ico [new file with mode: 0644]
portal/static/img/myslice_favicon.ico [new file with mode: 0644]
portal/static/img/onelab_favicon.ico [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_about.html
portal/templates/fed4fire/fed4fire_account-view.html
portal/templates/fed4fire/fed4fire_base.html [deleted file]
portal/templates/fed4fire/fed4fire_contact_support_email_subject.txt
portal/templates/fed4fire/fed4fire_email_activation.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_email_default_recipients.txt [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_email_default_sender.txt
portal/templates/fed4fire/fed4fire_footer.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_home-view.html
portal/templates/fed4fire/fed4fire_institution.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_management-tab-about.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_management-tab-requests.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_slice-resource-view.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_slice-tab-experiment.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_slice-view.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_slice_request_denied.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_slice_request_denied.txt [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_slice_request_email.html
portal/templates/fed4fire/fed4fire_slice_request_email.txt [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_slice_request_validated.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_slice_request_validated.txt [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_slicerequest_view.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_supportview.html
portal/templates/fed4fire/fed4fire_user_request_denied.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_user_request_denied.txt [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_user_request_email.html
portal/templates/fed4fire/fed4fire_user_request_email.txt [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_user_request_validated.html [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_user_request_validated.txt [new file with mode: 0644]
portal/templates/fed4fire/fed4fire_widget-slice-sections.html
portal/templates/fed4fire/fed4fire_widget-topmenu.html
portal/templates/onelab/onelab_base.html [deleted file]
portal/templates/servicedirectory.html
portal/templates/slice-tab-experiment.html
portal/usersview.py
rest/monitor.py
rest/sfa_api.py [new file with mode: 0644]
sla/slaclient/restclient.py
sla/slaclient/service/fed4fire/fed4fireservice.py
sla/slaclient/service/fed4fire/jsonparser.py
sla/slaclient/templates/fed4fire/django/agreement.xml
sla/slaclient/templates/fed4fire/fed4fire.py
sla/slaclient/wsag_model.py
sla/slaclient/xmlconverter.py
sla/slicetabsla.py
sla/static/images/sort_asc.png [new file with mode: 0644]
sla/static/images/sort_both.png [new file with mode: 0644]
sla/static/images/sort_desc.png [new file with mode: 0644]
sla/templates/slice-tab-sla.html
sla/urls.py

diff --git a/README b/README
index b1f201d..3530ed2 100644 (file)
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
 This file documents the contents of this module
 change
-Last update 4 sept. 2013
+Last update 4 DEC. 2014
 
 See the devel/ subdir for more devel-oriented doc.
 
index ca111de..fe493cd 100644 (file)
@@ -243,6 +243,7 @@ function QueryStore() {
         // XXX query.change_action() should become deprecated
         update_query = query.clone();
         update_query.action = 'update';
+        update_query.fields = [];
         update_query.analyzed_query.action = 'update';
         update_query.params = {};
         update_query_ext = new QueryExt(update_query);
@@ -1363,8 +1364,9 @@ case TYPE_LIST_OF_VALUES:
                 case TYPE_LIST_OF_VALUES: // XXX Until fixed
                 case TYPE_LIST_OF_RECORDS:
                     var key, new_state, cur_query_uuid;
-
-                    cur_query_uuid = query.analyzed_query.subqueries[field].query_uuid;
+                    if($.inArray(field,Object.keys(query.analyzed_query.subqueries)) > -1){
+                        cur_query_uuid = query.analyzed_query.subqueries[field].query_uuid;
+                    }
 
                     // example: slice.resource
                     //  - update_query_orig.params.resource = resources in slice before update
@@ -1449,6 +1451,8 @@ case TYPE_LIST_OF_VALUES:
         var query_ext = manifold.query_store.find_query_ext(query.query_uuid);
         query_ext.query_state = QUERY_STATE_DONE;
 
+        var tmp_query = manifold.query_store.find_analyzed_query(query.query_uuid);
+        manifold.publish_result_rec(tmp_query, records);
 
         // Send DONE message to plugins
         query.iter_subqueries(function(sq, data, parent_query) {
@@ -1884,6 +1888,7 @@ case TYPE_LIST_OF_VALUES:
                 break;
 
             case RUN_UPDATE:
+                query_ext.main_query_ext.update_query_ext.query.fields = [];
                 manifold.run_query(query_ext.main_query_ext.update_query_ext.query);
                 break;
 
index 6cca7f2..bd1474b 100644 (file)
@@ -286,7 +286,8 @@ LOGGING = {
     }
 }
 
-AUTHENTICATION_BACKENDS = ( 'auth.manifoldbackend.ManifoldBackend','django.contrib.auth.backends.ModelBackend' )
+AUTHENTICATION_BACKENDS = ('auth.manifoldbackend.ManifoldBackend',
+                           'django.contrib.auth.backends.ModelBackend')
 
 ### the view to redirect malformed (i.e. with a wrong CSRF) incoming requests
 # without this setting django will return a 403 forbidden error, which is fine
@@ -300,6 +301,7 @@ CSRF_FAILURE_VIEW = 'manifoldapi.manifoldproxy.csrf_failure'
 
 ####SLA#####
 
-SLA_MANAGER_URL = "http://157.193.215.125:4000/sla-service"
-SLA_MANAGER_USER = "normal_user"
+SLA_MANAGER_URL = "http://157.193.215.125:4001/sla-collector/sla"
+#SLA_MANAGER_URL = "http://172.24.76.28:8000/sla"
+SLA_MANAGER_USER = "portal"
 SLA_MANAGER_PASSWORD = "password"
index c50c08f..5f4c7d4 100644 (file)
@@ -84,6 +84,7 @@ urls = [
     #
     # RESTful interface
     (r'^rest/(?P<object_type>[^/]+)/(?P<object_name>[^/]+)?/?$', 'rest.get.dispatch'),
+    (r'^sfa/(?P<method>[^/]+)/?$', 'rest.sfa_api.dispatch'),
     (r'^table/(?P<object_type>[^/]+)/(?P<object_name>[^/]+)?/?$', 'rest.get.dispatch'),
     (r'^datatable/(?P<object_type>[^/]+)/(?P<object_name>[^/]+)?/?$', 'rest.get.dispatch'),
     (r'^update/(?P<object_type>[^/]+)/(?P<object_name>[^/]+)?/?$', 'rest.update.dispatch'),
index f3ba672..f1d6b32 100644 (file)
 
         /***************************** GUI EVENTS *****************************/
 
-        /************************** GUI MANIPULATION **************************/
+        do_checksla: function(e) {
+            var username = e.data.options.username;
+            var urn = data.value;
+            var arraySelectedResources = data.selected_resources;
+
+            var accepted_sla = [];
+            var count = 0;
+            var self = e.data;
+            // var testbedsWithSLA = ["iminds", "fuseco", "netmode"];
+            var testbedsWithSLA;
+            
+            var sliverPattern = /IDN\+(.+)\+(node|channel)\+/;
+            var list = [];
+
+            var promt = $('#sla-table-body');
+            
+            $.get("/sla/testbeds/", function(data) {
+                testbedsWithSLA = data;
+
+                console.log("Testbeds with SLA: " + testbedsWithSLA);
+
+                $(arraySelectedResources).each(function () {
+                    var sliverMatch = sliverPattern.exec(this);
+                    var sliverId = sliverMatch[1];
+                    for (var i = 0; i < testbedsWithSLA.length; i++) {
+                        if(this.indexOf(testbedsWithSLA[i].toLowerCase()) >= 0){ // If it has SLA
+                            if (list.indexOf(sliverId) == -1) { // If it is not in the list
+                                list.push(sliverId);
+                            }
+                        }
+                    }
+                });
+
+                if (list.length > 0) {
+                    for (var i = 0; i < list.length; i++) {
+                        var element = $('<tr>');
+                        element.append(
+                            $('<td>').append(list[i]),
+                            $('<td>').append('99% of Uptime for 99% of resources'),
+                            $('<td align="center">').append('<input type="checkbox" name="slaaccept" value="' + list[i] + '"/> <br />')
+                        );
+                        promt.append(element);
+                    }
+
+                    $('#sla_dialog').show();
+                    $('#slamodal').modal('show');
+                } else {
+                    //manifold.raise_event(self.options.query_uuid, RUN_UPDATE);
+                }
+            
+            });
+                    
+            $("#submit_sla").unbind().click(function(){
+                console.log("With username: " + username);
+
+                var notChecked = $("input[name='slaaccept']:not(:checked)");
+                
+                if (notChecked.length > 0) {
+                    for (var i = 0; i < notChecked.length; i++) {
+                         console.log("SLA not accepted: " + notChecked[i].value);
+                    }    
+
+                    alert("All SLAs have to be accepted to continue with the reservation");
+
+                } else {
+                    // $(list).each(function () {
+                    //     var date = new Date();
+                    //     date.setYear(date.getFullYear() + 1);
+
+                    //     $.post("/sla/agreements/simplecreate", 
+                    //         { "template_id": this.toString(),
+                    //           "user": username,
+                    //           "expiration_time": date.toISOString()
+                    //         });
+
+                        
+                    // });
+
+                    $.ajax({
+                        url: "/sla/agreements/simplecreate", 
+                        data: { testbeds: list,
+                          user: username,
+                          resources: arraySelectedResources,
+                          slice: main_query.filters.slice()[0][2]
+                        },
+                        type: "post",
+                        traditional: true
+                    });
+
+                    console.log(main_query.filters.slice()[0][2]);
+                      
+                    $('#slamodal').modal('hide');
+                    $('#sla-table-body').empty();
+                    //manifold.raise_event(self.options.query_uuid, RUN_UPDATE);
+                }
+            });
+
+               $("#cancel_sla").unbind().click(function(){
+                $('#slamodal').modal('hide');
+                $('#sla-table-body').empty();
+            }); 
+        },
+               /************************** GUI MANIPULATION **************************/
 
         populate_table: function()
         {
index ce27c2e..cb50c29 100644 (file)
@@ -1,18 +1,27 @@
 <div id={{ domid }}>
-<div class="modal fade" id="slamodal-wilab2" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"
+<div class="modal fade" id="slamodal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"
                data-backdrop="static" data-keyboard="false">
   <div class="modal-dialog">
     <div class="modal-content">
       <div class="modal-header">
-        <h4 class="modal-title" id="myModalLabel">Provider iMinds offers the following SLA</h4>
+        <h4 class="modal-title" id="myModalLabel">Selected testbed(s) provide the following SLAs</h4>
       </div>
       <div class="modal-body"  id="modal-body">
-        <!-- <p>SLA description</p>
-        <p>Testbed guarantees 0.99 Uptime rate for 0.99 rate of the WiLab2 resources during the sliver lifetime</p> -->
+        <table class="table" id="sla-modal-table">
+          <thead>
+          <tr>
+            <th>Testbed</th>
+            <th>SLA Description</th>
+            <th>Accept</th>
+          </tr>
+          </thead>
+          <tbody id="sla-table-body">
+          </tbody>
+        </table>
       </div>
       <div class="modal-footer">
-        <button type="button" id="dismiss_sla_wilab2" class="btn btn-default" data-dismiss="modal">Dismiss</button>
-        <button type="button" id="accept_sla_wilab2" class="btn btn-primary">Accept</button>
+        <button type="button" id="cancel_sla" class="btn btn-default" data-dismiss="modal">Cancel</button>
+        <button type="button" id="submit_sla" class="btn btn-primary">Submit</button>
       </div>
     </div>
   </div>
index 520253d..40f8506 100644 (file)
@@ -119,12 +119,6 @@ class ReputationView (LoginRequiredAutoLogoutView, ThemeView):
     def post (self,request):\r
         env = self.default_env()\r
         env['theme'] = self.theme\r
-        \r
-        \r
-        \r
-        with open('/home/coyiotis/testlog.log') as f:\r
-            f.write(str('test'))\r
-                \r
                 \r
         return render_to_response(self.template, env, context_instance=RequestContext(request))\r
 \r
@@ -135,12 +129,6 @@ class ReputationView (LoginRequiredAutoLogoutView, ThemeView):
         env = self.default_env()\r
                 \r
         #####    *** Reputation Plugin-specific START       ***     ############\r
-        with open('/home/coyiotis/testlog.log', 'w') as f:\r
-                f.write(str(request.GET))\r
-                for key in request.GET:\r
-                    f.write('\n')\r
-                    f.write(str(request.GET[key]))\r
-                    \r
         #The following 'if' is a dirty way for bypassing the JS AJAX cross-domain prevention policy...not pretty\r
         if request.GET.has_key(u'slicedata[user_eval][overall]'):\r
             dict_to_send = {}\r
index c645538..ad4967d 100644 (file)
@@ -18,7 +18,7 @@ import json
 
 class ServiceDirectoryView (LoginRequiredAutoLogoutView, ThemeView):
     template_name = 'servicedirectory.html'
-    server_url = "http://157.193.215.125:4001/"
+    server_url = "http://157.193.215.125:4001/service-directory/"
         
     # expose this so we can mention the backend URL on the welcome page
     def default_env (self):
diff --git a/portal/static/img/fed4fire_favicon.ico b/portal/static/img/fed4fire_favicon.ico
new file mode 100644 (file)
index 0000000..c2d91a0
Binary files /dev/null and b/portal/static/img/fed4fire_favicon.ico differ
diff --git a/portal/static/img/myslice_favicon.ico b/portal/static/img/myslice_favicon.ico
new file mode 100644 (file)
index 0000000..08b8cd4
Binary files /dev/null and b/portal/static/img/myslice_favicon.ico differ
diff --git a/portal/static/img/onelab_favicon.ico b/portal/static/img/onelab_favicon.ico
new file mode 100644 (file)
index 0000000..a2754aa
Binary files /dev/null and b/portal/static/img/onelab_favicon.ico differ
index 91998cb..b0c3b6d 100644 (file)
     <div class="tab-pane active row" id="about">
                <div class="col-md-12">
                        <p>
-                               Fed4Fire Portal is a central place to get acess to all Fed4fire testbeds.In order to get access to the portal,
+                               Fed4FIRE Portal is a central place to get acess to all Fed4FIRE testbeds.In order to get access to the portal,
                                an experimenter needs to  <a href="/portal/register">register</a> to the portal. The portal administrative body
                                is responsible to accept or reject newly registered users.   
                        </p>
                        <p>
-                               To learn more about Fed4fire visit:  <a href="http://www.fed4fire.eu/" target="_blank">http://www.fed4fire.eu/</a>                      
+                               To learn more about Fed4FIRE visit:  <a href="http://www.fed4fire.eu/" target="_blank">http://www.fed4fire.eu/</a>                      
                        </p>
                        <p>
                                If you have any questions regarding using the portal visit our <a href="/portal/support/">FAQ</a>
                        </p>
                        <p>
-                               Fed4fire portal is a community effot. To get more information about Fed4fire portal team visit: 
+                               Fed4FIRE portal is a community effot. To get more information about Fed4FIRE portal team visit: 
                                <a href="http://myslice.info/community" target="_blank">http://myslice.info/community</a>
                        </p>
                </div>
@@ -80,8 +80,8 @@
                                        <p> Documentation: <a href="http://trac.myslice.info/" target="_blank">http://trac.myslice.info/</a></p>
                                        <p> Code: <a href="https://git.top-hat.info/?p=tophat.git;a=shortlog;h=refs/heads/devel" target="_blank">Git Repository</a> (read only)</p>     
 
-                               <h5>Fed4fire Registry</h5>
-                                       <p><a href="https://sfa-fed4fire.pl.sophia.inria.fr" target="_blank">Fed4fire registry</a> is a SFA registry. SFA Registry is a specific installation mode of the SFAWrapper.</p>
+                               <h5>Fed4FIRE Registry</h5>
+                                       <p><a href="https://sfa-fed4fire.pl.sophia.inria.fr" target="_blank">Fed4FIRE registry</a> is a SFA registry. SFA Registry is a specific installation mode of the SFAWrapper.</p>
                                        <p> More Info: <a href="http://svn.planet-lab.org/wiki/SfaDeveloperRegistryTutorial#RunninginRegistry-Onlymode" target="_blank">SFA Registry</a></p>
        </div>
    </div>
index ac85870..6163459 100644 (file)
@@ -1,7 +1,20 @@
-{% extends "layout_wide.html" %}
+{% extends "layout.html" %}
 {% block content %}
 
+<div class="row">
+       <div class="col-md-12">
+                <div class="breadcrumbs">
+                        Account &nbsp;>&nbsp; <a href="/account">{{ person.email }}</a>
+                </div>
+       </div>
+        {%if 'no_creds'  in user_cred %}
+    <p class="command"><a href="#" style="color:red" data-toggle="modal" data-target="#myModal">NO CREDENTIALS</a> are delegated to the portal!</p>
+    {%endif%}
+        {%if 'creds_expired'  in user_cred %}
+    <p class="command"><a href="#" style="color:red" data-toggle="modal" data-target="#myModal">EXPIRED CREDENTIALS</a> Please delegate again your credentials to the portal!</p>
+    {%endif%}
 
+</div>
 {% if messages %}
 <ul class="messages">
     {% for message in messages %}
     {% endfor %}
 </ul>
 {% endif %}
-<div class="container">
-       <div class="row">
-               <div class="col-md-12">
-                       <ul class="nav nav-tabs nav-section">
-                               <li class="active"><a href="#profile"><img src="{{ STATIC_URL }}icons/user-xs.png" alt="User Account" /> User Profile</a></li>
-                               <li><a href="#account">Account</a></li>
-                               <li><a href="#access">Testbed Access</a></li>
-                       </ul>
-           </div>
-       </div>
+<div class="row">
+       <div class="col-md-12">
+               <ul class="nav nav-tabs nav-section">
+                       <li class="active"><a href="#profile">User Profile</a></li>
+                       <li><a href="#account">Account</a></li>
+                       <li><a href="#access">Testbed Access</a></li>
+               </ul>
+    </div>
 </div>
-<div class="container tab-content">
+<div class="tab-content">
        <div class="tab-pane active row" id="profile">
                
                <div class="col-md-12">
                                        <table class="profile">          
                                        <tr>
                                                <td colspan="2">
-                                                               <div>Platform: Myslice</div>
+                                                               <div><h3>Platform: Myslice</h3></div>
                                                </td>
                                        </tr>
                                        <tr>
                                                <td class="key">Email</td>
                                                <td class="value">
                                                                <span id="emailval" class="value" >{{ person.email }}</span>
-                                                               <button class="btn btn-default btn-xs" type="button" id="edit_email" onclick="editAlert();"  title="To change your affiliation please contact the administrator">
+                                                               <button class="btn btn-default" type="button" id="edit_email" onclick="editAlert();"  title="To change your affiliation please contact the administrator">
                                                                <span class="glyphicon glyphicon-question-sign"></span> Edit
                                                                </button>
                                                        </td>
                                                <tr class="even">
                                                        <td class="key">Generate Keys</td>
                                                        <td>
-                                                               <input type="submit" name="generate" class="btn btn-danger btn-xs" value="Generate a new Key Pair" id="generate_keypair" 
+                                                               <input type="submit" name="generate" class="btn btn-primary" value="Generate a new Key Pair" id="generate_keypair" 
                                                                           onclick="return confirm('Are you sure? If you do so, your current credentials will be overwritten.');" 
                                                                           title="It will generate a new key Pair and your current credentials will be overwritten."/>
                                                </td> 
                                                <td class="value">
                                                                <span id="keyval" class="value">******** </span>
                                                                <span class="hide_this" id="span_upload">
-                                                                       <button type="button" class="btn btn-default btn-xs" title="Cancel" id="cancel_upload"> Cancel </button>
+                                                                       <button type="button" class="btn btn-default" title="Cancel" id="cancel_upload"> Cancel </button>
                                                                        <div style='display:none;'>
                                                                                <input type='hidden'  name='upload'  /></div>
                                                                                <input type="file" name="pubkey" class="required" id="pubkey"/>  
                                                 {%if 'N/A' not in user_private_key%}
                                                <td class="key">Private Key </td> <!-- Hide if priv_key doesn't exist in myslice platform   -->
                                                <td class="value">********<a href="#"></a>
-                                                       <button type="submit" name="dl_pkey" class="btn btn-default btn-xs" title="Download your privaye key" id="dl_pkey">
+                                                       <button type="submit" name="dl_pkey" class="btn btn-default" title="Download your privaye key" id="dl_pkey">
                                                                        <span class="glyphicon glyphicon-download"></span> Download     
                                                                </button>
                                                        <input class="btn btn-danger btn-xs" id="delete" name="delete" type="submit"  value="Delete" title="Delete your private key"
                                                  {%else%}
                                                        <td class="key">Private Key </td> <!-- Hide if priv_key doesn't exist in myslice platform   -->
                                                        <td class="value">********<a href="#"></a>
-                                                       <button type="submit" name="dl_pkey" class="btn btn-default btn-xs disabled" title="Download your privaye key" id="dl_pkey">
+                                                       <button type="submit" name="dl_pkey" class="btn btn-default disabled" title="Download your privaye key" id="dl_pkey">
                                                                <span class="glyphicon glyphicon-download"></span> Download 
                                                        </button>
                                                        <input class="btn btn-danger btn-xs disabled" id="delete" name="delete" type="submit" title="Delete your private key" value="Delete" />
                                                        </td>
                                                 {%endif%}              
                                                </tr>
+                                       <tr class="even" id="sfi_config_row">
+                                               <td class="key">sfi_config </td>
+                                               <td class="value">use sfi_config file with sfi.py package (pip install sfa)<a href="#"></a>
+                                                       <button type="submit" name="dl_sfi_config" class="btn btn-default btn-xs" title="Download your sfi_config" id="dl_sfi_config">
+                                                                       <span class="glyphicon glyphicon-download"></span> Download
+                                                               </button>
+                                               </td>
+                        </tr>
                                                <tr class="odd">
                                                        {%if 'N/A' not in user_private_key%}
                                                        <td class="key">Identity</td> 
                                                        </td>
                                                        {%endif%} 
                                                </tr>
+
                                                <tr class="even">
                                                <td colspan="2">
-                                                       <p class="message" id="pkey_del_msg"><b> Tradeoff:</b> Ease-of-use vs Security.<br>
-                                                                       <b>Ease-of-use:</b> Automatic account delegation. Don't delete private key.<br>
-                                                                       <b>Security:</b> Manual account delegation. Download & Delete private key.
+                                                               <p class="command">
+                                                                       <a href="#" style="color:green" data-toggle="modal" data-target="#tradeoffmodal">Automatic vs. Manual delegation of credentials:</a>
+                                                                       Trade-off between ease-of-use & security</p>
                                                                </p>
                                                </td>
                                                </tr>
                                                        <button class="btn btn-default btn-xs" name= "dl_user_cert" type="submit" title="Download User Certificate">
                                                                <span class="glyphicon glyphicon-download"></span> Certificate
                                                        </button>
-                                                       <button class="btn btn-default btn-xs" name= "dl_user_p12" type="submit" title="Download User PKCS12">
-                                                               <span class="glyphicon glyphicon-download"></span> PKCS p12
-                                                       </button>
+                             <button class="btn btn-default btn-xs" name= "dl_user_p12" type="submit" title="Download User PKCS12">
+                                 <span class="glyphicon glyphicon-download"></span> PKCS p12
+                             </button>
                                                </td>
                                        </tr>
                                        {%endfor%}
                                {%endif%}
                </div>
        </div>
+<!-- Modal- No credentials -->
+<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+            <div class="modal-dialog">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+                            <h4 class="modal-title" id="myModalLabel">No credentials are delegated to the portal</h4>
+                    </div>
+                                       <div class="modal-body" style="text-align:justify;">
+                                       <p>You are getting this message for any of the following reasons:</p>
+                                       <ul>
+                                               <li>If your account is still pending for validation</li>
+                                               <li>If you press the "Clear Credentials" button</li>
+                                               <li>If you "Generate a new key pair"</li>
+                                               <li>If a new slice is added to your account</li>
+                                       </ul>
+                                       <p>Unless your account has not yet been validated, it is sufficient to refresh the page or go back to the home page. 
+                                               The portal will then regenerate your credentials. In some cases it may take more time than usual. If nothing works, 
+                                               then please logout and login back into to the portal.
+                                       </p>
+                                       <h3>Manual delegation of credentials</h3>
+                                               <p>
+                                                       You have selected upon sign-up to upload your public key. As you have uploaded your own public key, 
+                                                       the portal can no longer generate your credentials automatically. In order to have your credentials 
+                                                       delegated to the portal, please follow these instructions:
+                                               </p>
+                                               <ul>
+                                                       <li>Your account must first be validated by the manager of your organization.</li>
+                                                       <li>In order for the portal to contact testbeds on your behalf, so as to list and reserve resources, you will need to
+                                                               <a href="/portal/manual_delegation" target="_blank">delegate your credentials to the portal.</a></li>
+                                               </ul>
+                                       </p>
+                                       <h3>Contact support</h3>
+                                       <p>If you don't have the above mentioned cases and still have this message, please  <a href="/contact/" target="_blank">contact us</a>.</p>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                    </div>
+                </div>
+            </div>
+</div>
+
+
+<!-- Modal- Trade-off Message  -->
+<div class="modal fade" id="tradeoffmodal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+            <div class="modal-dialog">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+                            <h4 class="modal-title" id="myModalLabel">
+                                                               Automatic vs. Manual delegation of credentials
+                                                       </h4>
+                    </div>
+                                       <div class="modal-body" style="text-align:justify;">
+                                       <h3>Automatic delegation of credentials</h3>
+                                               <p>Don't delete private key, ease-of-use option:</p>
+                                               <ul>
+                                                       <li>
+                                                               This means that you will keep your private key in the portal and it will automatically delegate your credentials on your behalf.
+                                                       </li>
+                                                       <li>
+                                                               This option does not provide as high of a level of security; however, your private key will still only be used in the portal and 
+                                                               will be available to you and the Fed4FIRE admins only.
+                                                       </li>
+                                               </ul>
+                                       <h3>Manual delegation of credentials</h3>
+                                               <p>Download & Delete private key, higher security option:</p>
+                                               <ul>
+                                                       <li>If you delete your private key, you will have more security but the portal will no longer be able to delegate credentials 
+                                                               on your behalf, and you will have to manually
+                                                               <a href="/portal/manual_delegation" target="_blank">delegate your credentials to the portal.</a>
+                                                       </li>
+                                               </ul>
+                                       <h3>Contact support</h3>
+                                       <p>For more information, please  <a href="/contact/" target="_blank">contact us</a>.</p>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                    </div>
+                </div>
+            </div>
+</div>
+
+
 
        <div class="tab-pane row" id="access">
                <div class="col-md-12">
                 <td class="odd"> {{ row.account_type }} </td>
                                <td class="odd"> {{ row.account_reference }} </td>
                                <td class="odd">
-                               <button class="btn btn-danger btn-xs" name="delete_{{row.platform_name}}" type="submit" title="Delete account from this platform">
+                               <button class="btn btn-danger" name="delete_{{row.platform_name}}" type="submit" title="Delete account from this platform">
                                                <span class="glyphicon glyphicon-minus"></span>
                                        </button>
                                </td>
diff --git a/portal/templates/fed4fire/fed4fire_base.html b/portal/templates/fed4fire/fed4fire_base.html
deleted file mode 100644 (file)
index 7eaaf05..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-{# This is required by insert_above #}{% insert_handler %}<!DOCTYPE html>
-<html lang="en"><head>
-<title>Fed4Fire Portal - {{ section }}</title>
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<link rel="shortcut icon" href="/static/img/myslice-icon.png">
-{# This is where insert_str will end up #}{% media_container prelude %}
-{% include 'messages-transient-header.html' %}
-<script type="text/javascript"> {# raw js code - use {% insert prelude_js %} ... {% endinsert %} #} {% container prelude_js %}</script>
-<script src="{{ STATIC_URL }}js/jquery.dataTables.min.js"></script>
-<script src="{{ STATIC_URL }}js/bootstrap.datatables.js"></script>
-<script src="{{ STATIC_URL }}js/myslice.js"></script>
-<script src="{{ STATIC_URL }}js/myslice-ui.js"></script>
-<style type="text/css">{# In case we need to add raw css code #}{% container prelude_css %}</style>
-{{ header_prelude }}
-{% block head %} {% endblock head %}
-{# let's add these ones no matter what #}
-{% insert_str prelude "js/jquery.min.js" %}
-{% insert_str prelude "js/angular/angular.min.js" %}
-{% insert_str prelude "js/jquery.html5storage.min.js" %}
-{% insert_str prelude "js/messages-runtime.js" %}
-{% insert_str prelude "js/class.js" %}
-{% insert_str prelude "js/plugin-helper.js" %}
-{% insert_str prelude "js/mustache.js" %}
-{% insert_str prelude "js/hashtable.js" %}
-{% insert_str prelude "js/plugin.js" %}
-{% insert_str prelude "js/manifold.js" %}
-{% insert_str prelude "css/manifold.css" %}
-{% insert_str prelude "css/plugin.css" %}
-{% insert_str prelude "js/bootstrap.js" %}
-{% insert_str prelude "css/bootstrap.css" %}
-{% insert_str prelude "js/bootstrap-datepicker.js" %}
-{% insert_str prelude "css/datepicker.css" %}
-{% insert_str prelude "js/bootstrap-slider.js" %}
-{% insert_str prelude "css/slider.css" %}
-{% insert_str prelude "css/topmenu.css" %}
-{% insert_str prelude "js/logout.js" %}
-<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/{{ theme }}.css">
-</head>
-<body ng-app="ManifoldApp">
-{% block container %}
-       {% block topmenu %}
-       {% include theme|add:"__widget-topmenu.html" %}
-       {% endblock topmenu %}
-       {% include 'messages-transient.html' %}
-       {% block base_content %}
-       {% endblock %}
-{% endblock container %}
-</body>
-</html>
diff --git a/portal/templates/fed4fire/fed4fire_email_activation.html b/portal/templates/fed4fire/fed4fire_email_activation.html
new file mode 100644 (file)
index 0000000..ae7627a
--- /dev/null
@@ -0,0 +1,21 @@
+{% extends "layout.html" %}
+
+{% block content %}
+
+<div class="row">
+       <h1><img src="{{ STATIC_URL }}img/icon_user_small.png" alt="User Registration" />User sign-up</h1>
+</div>
+<div class="row">
+       {% if activation_status == 'success' %}
+               <h3>Signup request confirmed.</h3>
+               <p>You are currently able to log in to the portal using your email address and the password that you have provided; however, your access is still limited.</p> 
+               <p>You will have full access as soon as your account is validated by a manager at your organization. We have sent an email to your organisation's managers with a validation request.</p>
+       {%else%}
+               <h3>Signup confirmation failed.</h3>
+               <p>You have probably arrived at this page by clicking a confirmation link in an email that we have sent to you. 
+               We have been unable to match the link that you have clicked to a signup request in our database.</p>
+               <p>Please <a href="/portal/contact/">contact support</a> so that we may help you complete the signup process.</p>
+       {%endif%}
+ </div>
+
+{% endblock %}
diff --git a/portal/templates/fed4fire/fed4fire_email_default_recipients.txt b/portal/templates/fed4fire/fed4fire_email_default_recipients.txt
new file mode 100644 (file)
index 0000000..b2de7ee
--- /dev/null
@@ -0,0 +1 @@
+Fed4FIRE Support <contact@fed4fire.eu>
diff --git a/portal/templates/fed4fire/fed4fire_footer.html b/portal/templates/fed4fire/fed4fire_footer.html
new file mode 100644 (file)
index 0000000..d4db4be
--- /dev/null
@@ -0,0 +1 @@
+<!--No foorter added for the moment -->
index 09e4731..e5ce3f0 100644 (file)
@@ -6,8 +6,56 @@
 {% widget '_widget-news.html' %}
 </div> -->
 {% if username %}
+<!-- Modal- No credentials -->
+<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+            <div class="modal-dialog">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+                            <h4 class="modal-title" id="myModalLabel">No credentials are delegated to the portal</h4>
+                    </div>
+                    <div class="modal-body" style="text-align:justify;">
+                                       <p>You are getting this message for any of the following reasons:</p>
+                                       <ul>
+                                               <li>If your account is still pending for validation</li>
+                                               <li>If you press the "Clear Credentials" button</li>
+                                               <li>If you "Generate a new key pair"</li>
+                                               <li>If a new slice is added to your account</li>
+                                       </ul>
+                                       <p>Unless your account has not yet been validated, it is sufficient to refresh the page or go back to the home page. 
+                                               The portal will then regenerate your credentials. In some cases it may take more time than usual. If nothing works, 
+                                               then please logout and login back into to the portal.
+                                       </p>
+                                       <h3>Manual delegation of credentials</h3>
+                                               <p>
+                                                       You have selected upon sign-up to upload your public key. As you have uploaded your own public key, 
+                                                       the portal can no longer generate your credentials automatically. In order to have your credentials 
+                                                       delegated to the portal, please follow these instructions:
+                                               </p>
+                                               <ul>
+                                                       <li>Your account must first be validated by the manager of your organization.</li>
+                                                       <li>In order for the portal to contact testbeds on your behalf, so as to list and reserve resources, you will need to
+                                                               <a href="/portal/manual_delegation" target="_blank">delegate your credentials to the portal.</a></li>
+                                               </ul>
+                                       </p>
+                                       <h3>Contact support</h3>
+                                       <p>If you don't have the above mentioned cases and still have this message, please  <a href="/contact/" target="_blank">contact us</a>.</p>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                    </div>
+                </div>
+            </div>
+</div>
 <div class="container dashboard">
        <div class="row">
+       {%if 'no_creds'  in user_cred %}
+       <p class="command"><a href="#" style="color:red" data-toggle="modal" data-target="#myModal">NO CREDENTIALS</a> are delegated to the portal!</p>
+       {%endif%}
+       {%if 'creds_expired'  in user_cred %}
+       <p class="command"><a href="#" style="color:red" data-toggle="modal" data-target="#myModal">EXPIRED CREDENTIALS</a> Please delegate again your credentials to the portal!</p>
+    {%endif%}
+               {%if 'is_pi'  in pi %}
                <div class="col-md-3">
                        <h3>
                                EXPERIMENT
                                <a href="#"><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></a>
                        </div>
                        <div>
-                               <button id="slicerequestbtn" type="button" style="width: 150px;" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request slice</button>
+                               <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create Slice</button>
+                       </div>
+                       <div>
+                               <p><strong>Your slices </strong>
+                                       <span title="A slice is a set of testbed resources on which you can conduct an experiment. 
+                                       Either ask your colleagues to give you access to an existing slice or request a new slice by clicking 'Request Slice'. 
+                                       However, on the Fed4FIRE portal, you will only see slices that you have created through Fed4FIRE. If you have created slices elsewhere, 
+                                       those slices will not appear here."
+                                       class="glyphicon glyphicon-info-sign">
+                               </span>
+
+                               </p>
                        </div>
                        <div>   
                                <div id="home-slice-list"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
                        </div>
-                        <div>
-                <h3 title="Some tools do their own slice creation and management.">Experiment now</h3>
-                        </div>
-                       <div>
-                                       <a class="btn btn-primary" style="width: 150px;" 
-                    href='http://jfed.iminds.be/releases/r1389/webstart/experimenter/jfed-experimenter.jnlp'
+                       <h3 title="Some tools do their own slice creation and management.">Experiment now</h3>
+                       <a class="btn btn-primary" style="width: 150px;" 
+                    href='http://jfed.iminds.be/releases/5.4-dev/r2289/webstart/experimenter/jfed-experimenter.jnlp'
                                        title="Click here to start your experiment with jFed" 
-                                       onclick="return  launchApplication('http://jfed.iminds.be/releases/r1389/webstart/experimenter/jfed-experimenter.jnlp');">
+                                       onclick="return  launchApplication('http://jfed.iminds.be/releases/5.4-dev/r2289/webstart/experimenter/jfed-experimenter.jnlp');">
                     <span class="glyphicon glyphicon-cloud"></span> jFed</a>
-                       </div>
                </div>
                <div class="col-md-3">
                        <h3>MANAGEMENT</h3>
                                SUPPORT
                        </h3>
                        <div>
-                               <a href="http://doc.fed4fire.eu/support.html"><img src="{{ STATIC_URL }}img/icon_support.png" alt="" /></a>
+                               <a href="/portal/support"><img src="{{ STATIC_URL }}img/icon_support.png" alt="" /></a>
                        </div>
                        <div>
-                               <button id="ticketbtn" type="button" style="width: 150px;" class="btn btn-default"><span class="glyphicon glyphicon-envelope"></span> Contact</button>
+                               <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-envelope"></span> Contact</button>
                        </div>
                        <p></p>
                        <div>
                        <button id="statbtn" type="button" style="width: 150px;" class="btn btn-default"><span class="glyphicon glyphicon-stats"></span>Testbeds' status</button>
                        </div>
+                       <div>
+                       <button id="repbtn" type="button" style="width: 170px;" class="btn btn-default"><span class="glyphicon glyphicon-stats"></span>Testbeds' reputation</button>
+                       </div>
                </div>
                
                <div class="col-md-3">
                                <a href="/portal/account/"><img src="{{ STATIC_URL }}img/icon_user_color.png" alt="" /></a>
                        </div>
                        <div>
-                               <button id="logoutbtn" type="button" style="width: 150px;" class="btn btn-default" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</button>
+                               <button id="logoutbtn" type="button" class="btn btn-default" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</button>
+                       </div>
+                       <div>
+                               {% if person.last_name %}
+                                       {{person.first_name}} {{person.last_name}}<br />
+                               {% endif %}
+                       <span class="label">Username:</span> <a href='/portal/account/' title="Click here to see and edit your account details.">{{person.email}}</a>
+               </div>
+               </div>
+       </div>
+       {%else%}
+       <div class="row">
+               <div class="col-md-4">
+                       <h3>
+                               EXPERIMENT
+                       </h3>
+                       <div>
+                               <a href="#"><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></a>
+                       </div>
+                       <div>
+                               <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
+                       </div>
+                       <div>
+                               <p><strong>Your slices </strong>
+                               <span title="A slice is a set of testbed resources on which you can conduct an experiment. 
+                                       Either ask your colleagues to give you access to an existing slice or request a new slice by clicking 'Request Slice'. 
+                                       However, on the Fed4FIRE portal, you will only see slices that you have created through Fed4FIRE. If you have created slices elsewhere, 
+                                       those slices will not appear here."
+                                       class="glyphicon glyphicon-info-sign">
+                               </span>
+                               </p>
+                       </div>
+                       <div>   
+                               <div id="home-slice-list"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+                       </div>
+                       {% if pending_slices %}
+                       <p><strong>Pending slices</strong>
+                       <span title="Slices that you have requested and are pending for validation by the contact person of your organization."
+                               class="glyphicon glyphicon-info-sign">
+                       <ul>
+                       {% for slices in pending_slices %}
+                       <li>{{slices}}</li>
+                       {% endfor %}
+                       </ul>
+                       </span>
+                       </p>
+                       {%endif%}
+                       <h3 title="Some tools do their own slice creation and management.">Experiment now</h3>
+                       <a class="btn btn-primary" style="width: 150px;" 
+                    href='http://jfed.iminds.be/releases/5.4-dev/r2289/webstart/experimenter/jfed-experimenter.jnlp'
+                                       title="Click here to start your experiment with jFed" 
+                                       onclick="return  launchApplication('http://jfed.iminds.be/releases/5.4-dev/r2289/webstart/experimenter/jfed-experimenter.jnlp');">
+                    <span class="glyphicon glyphicon-cloud"></span> jFed</a>   
+               </div>
+               <div class="col-md-4">
+                       <h3>
+                               SUPPORT
+                       </h3>
+                       <div>
+                               <a href="/portal/support"><img src="{{ STATIC_URL }}img/icon_support.png" alt="" /></a>
+                       </div>
+                       <div>
+                               <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-envelope"></span> Contact</button>
+                       </div>
+                       <p></p>
+                       <div>
+                       <button id="statbtn" type="button" style="width: 150px;" class="btn btn-default"><span class="glyphicon glyphicon-stats"></span>Testbeds' status</button>
+                       </div>
+                       <div>
+                       <button id="repbtn" type="button" style="width: 170px;" class="btn btn-default"><span class="glyphicon glyphicon-stats"></span>Testbeds' reputation</button>
+                       </div>
+               </div>
+               
+               <div class="col-md-4">
+                       <h3>
+                               ACCOUNT
+                       </h3>
+                       <div>
+                               <a href="/portal/account/"><img src="{{ STATIC_URL }}img/icon_user_color.png" alt="" /></a>
+                       </div>
+                       <div>
+                               <button id="logoutbtn" type="button" class="btn btn-default" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</button>
                        </div>
                        <div>
                                {% if person.last_name %}
                                        {{person.first_name}} {{person.last_name}}<br />
                                {% endif %}
-                       <span class="label">Email:</span> <a href='/portal/account/'>{{person.email}}</a>
+                       <span class="label">Username:</span> <a href='/portal/account/' title="Click here to see and edit your account details.">{{person.email}}</a>
                </div>
                </div>
        </div>
+       {%endif%}
+
 </div>
 {% else %}
 <div class="container-fluid home">
                        $('div#'+$(this).data('panel')).show();
                });
                $('button#validaterequestbtn').click(function() {
-                       window.location="/portal/validate/";
+                       window.location="/portal/institution#requests";
                });
                $('button#ticketbtn').click(function() {
                        window.location="/portal/contact/";
                $('button#statbtn').click(function() {
                window.location="https://flsmonitor.fed4fire.eu";
                });
+                $('button#repbtn').click(function() {
+               window.location="/portal/reputation";
+                });
                $('button#signupbtn').click(function() {
                        window.location="/portal/register/";
                });
                $('button#slicerequestbtn').click(function() {
                        window.location="/portal/slice_request/";
                });
-/*-------
-List of slices has been moved in 
-portal/templates/base.html
-This should go into session
---------*/
+
+        /*
+            Launch queries to get the resources and leases in Manifold Cache
+        */
+            
+        $.post("/rest/resource/", function( data ) {
+        });
+        $.post("/rest/lease/", function( data ) {
+        });
+        
+        /*-------
+        List of slices has been moved in 
+        portal/templates/base.html
+        This is now in localStorage 
+        --------*/
+        // myslice.user is in LocalStorage
+        if(myslice.user.slices.length>0){
+            $.each( myslice.user.slices, function(i, val) {
+                /*
+                Launch a Query for each slice to get resources and leases in Manifold Cache
+                */
+                $.post("/rest/slice/", { 'filters': { 'slice_hrn' : val } }, function(data) {
+                });
+            });
+        }
 });
 </script>
+
+<!--for jfed tool-->
 <script type="text/javascript" src="{{STATIC_URL}}js/fed4fire_dtjava_orig.js"></script>
 <script>
        function launchApplication(jnlpfile) {
@@ -146,4 +312,7 @@ This should go into session
         return false;
      }
 </script>
+{# widget "_widget-monitor.html" #}
+{# widget "_widget-stats-top-slices.html" #}
+
 {% endblock %}
diff --git a/portal/templates/fed4fire/fed4fire_institution.html b/portal/templates/fed4fire/fed4fire_institution.html
new file mode 100644 (file)
index 0000000..bd361de
--- /dev/null
@@ -0,0 +1,185 @@
+{% extends "layout_wide.html" %}
+
+{% block head %} 
+<script type="text/javascript" src="{{STATIC_URL}}/js/institution.js"></script>
+{% endblock head %}
+
+{% block content %}
+<div class="container">
+       <div class="row">
+               <div class="col-md-12">
+                        <div class="breadcrumbs">
+                                Management &nbsp;>&nbsp; Institution: <span id="authority_name"></span>
+                        </div>
+               </div>
+       </div>
+</div>
+<div class="container">
+       <div class="row">
+               <div class="col-md-12">
+                       <ul class="nav nav-tabs nav-section">
+                               <li class="active"><a href="#about">About</a></li>
+                               <li><a href="#users">Users</a></li>
+                               <li><a href="#slices">Slices</a></li>
+                               <li><a href="#requests">Requests</a></li>
+                       </ul>
+           </div>
+       </div>
+</div>
+<div class="container tab-content">
+       <div class="tab-pane active row" id="about">
+       </div>
+       
+       <div class="tab-pane row" id="users" data-authority="{{user_details.parent_authority}}">
+               <div class="col-md-12 el">
+                       <div id="user-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+                               <div id="user-tab-loaded" style="display:none;">
+                               <table id="user-tab" class="table">
+                                       <tr>
+                                       <th>+/-</th>
+                                       <th>Email</th>
+                                       <th>User hrn</th>
+                            <!--
+                                       <th>First name</th>
+                                       <th>Last name</th>
+                                       <th>Enabled</th>
+                            -->
+                                       </tr>
+                               </table>
+                               
+                       </div>
+                       {%if 'is_pi'  in pi %}  
+                       <div>
+                               <button id="deleteusers" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> Delete selected users</button>
+                       </div>
+                       {% endif %}
+               </div>
+       </div>
+
+       <div class="tab-pane row" id="slices">
+               <div class="col-md-12 el">
+           <div id="slice-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+           <div id="slice-tab-loaded" style="display:none;">
+               <table id="slice-tab" class="table">
+                   <tr>
+                       <th>+/-</th>
+                       <th>Slice hrn</th>
+                       <th>Users</th>
+                       <th>Url</th>
+                       <!-- <th>nodes</th> -->
+                       <th>Creation</th>
+                   </tr>
+               </table>                        
+           </div>
+       {% if 'is_pi'  in pi %}
+        <div>
+               {% if 'is_pi'  in pi %}
+                       <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create slice</button>
+                       {% else %}
+                       <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request slice</button>
+                       {% endif %}
+            <button id="renewslices" type="button" class="btn btn-primary"><span class="glyphicon glyphicon-refresh"></span> Renew Slices</button>
+            <button id="deleteslices" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> Delete Slices</button>
+        </div>
+               {% endif %} 
+          </div>
+       </div>
+       <div class="tab-pane row" id="requests">
+       </div>
+</div>
+<script>
+$(document).ready(function() {
+    {% if person %}
+    {% if user_details.parent_authority %}
+
+        $.post("/rest/slice/",{'fields':['slice_hrn','users','url','slice_date_created'],'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
+            var list_slices = [];
+            var table_slices = [];
+            /* "slice_hrn", "slice_description", "slice_type", "parent_authority", "created", "nodes", "slice_url", "slice_last_updated", "users", "slice_urn", "slice_expires" */
+            $.each( data, function( key, val ) {
+                list_slices.push( "<li><a href=\"portal/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></li>" );
+                if(val.nodes=="undefined" || val.nodes==null){
+                    nodes_length=0;
+                }else{
+                    nodes_length=val.nodes.length;
+                }
+                console.log(val);
+                if(val.users=="undefined" || val.users==null){
+                    users_length=0;
+                }else{
+                    users_length=val.users.length;
+                }
+
+                if(val.url=="undefined" || val.url==null){
+                    slice_url="";
+                }else{
+                    slice_url="<a href='"+val.url+"' target='_blank'>"+val.url+"</a>";
+                }
+                
+                slice_row = "<tr id='"+val.slice_hrn+"'>";
+                slice_row += "<td><input type='checkbox' class='slice' id='"+val.slice_hrn+"'></td>";
+                slice_row += "<td><a href=\"/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></td>";
+                slice_row += "<td>"+users_length+"</td>";
+                slice_row += "<td>"+slice_url+"</td>";
+                //slice_row += "<td>"+nodes_length+"</td>";
+                slice_row += "<td>"+val.slice_date_created+"</td>";
+                slice_row += "</tr>";
+                table_slices.push(slice_row);
+                
+            });
+           
+            /* $("div#slice-list").html($( "<ul/>", { html: list_slices.join( "" ) })); */
+            $("table#slice-tab tr:last").after(table_slices.join( "" ));
+            $("div#slice-tab-loaded").css("display","block");
+            $("div#slice-tab-loading").css("display","none");
+        });
+               
+               
+        $.post("/rest/user/",{'fields':['user_hrn','user_email'],'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
+            var list_users = [];
+            var table_users = [];
+                   /* Available fields
+                   user_gid, user_enabled, slices, pi_authorities, keys, parent_authority, user_first_name,
+                   user_urn, user_last_name, user_phone, user_hrn, user_email, user_type
+                   */
+            $.each( data, function( key, val ) {
+                list_users.push( "<li><a href=\"portal/user/"+val.user_email+"\">" + val.user_email + "</a></li>" );
+                user_row = "<tr id='"+val.user_hrn+"'>";
+                user_row += "<td><input type='checkbox' class='user' id='"+val.user_hrn+"'></td>";
+                user_row += "<td>"+val.user_email+"</td>";
+                user_row += "<td>"+val.user_hrn+"</td>";
+                /*
+                user_row += "<td>"+val.user_first_name+"</td>";
+                user_row += "<td>"+val.user_last_name+"</td>";
+                           user_row += "<td>"+val.user_enabled+"</td>";
+                */
+                user_row += "</tr>";
+                table_users.push(user_row);
+            });
+            $("table#user-tab tr:last").after(table_users.join( "" ));
+            $("div#user-tab-loaded").css("display","block");
+            $("div#user-tab-loading").css("display","none");
+        });
+
+    {% endif %}
+    {% endif %}
+
+}); // End document.ready
+
+$(document).ready(function() {
+       $('.nav-tabs a').click(function (e) {
+               e.preventDefault();
+               $(this).tab('show');
+       var id = $(this).attr('href').substr(1);
+       if ((id == 'requests') || (id == 'about'))
+               $("#" + id).load('/management/' + id);
+       });
+       var hash = window.location.hash;
+       if (hash) {
+               $('.nav-tabs a[href='+hash+']').click();
+       } else {
+               $('.nav-tabs a[href=#about]').click();
+       }
+});
+</script>
+{% endblock %}
diff --git a/portal/templates/fed4fire/fed4fire_management-tab-about.html b/portal/templates/fed4fire/fed4fire_management-tab-about.html
new file mode 100644 (file)
index 0000000..bc768a6
--- /dev/null
@@ -0,0 +1,71 @@
+{% load portal_filters %}
+<div class="col-md-6">
+       <div>
+               <img src="{{ STATIC_URL|add:'img/institutions/'|add:authority.authority_hrn|add:'.gif'|file_exists }}" alt="{{authority.name}}">
+       </div>
+       <br />
+    {% if authority.name and authority.url %}
+       <h3><a href="{{authority.url}}">{{authority.name}}</a></h3>
+    {% elif authority.name %}
+       <h3>{{authority.name}}</h3>
+    {% endif %}
+       <p>
+    {% if authority.address %}
+               {{authority.address}} <br />
+    {% endif %}
+    {% if authority.postcode %}
+               {{authority.postcode}} 
+    {% endif %}
+    {% if authority.address %}
+        {{authority.city}} <br />
+    {% endif %}
+    {% if authority.address %}
+               {{authority.country}}
+    {% endif %}
+       </p>
+       <br />
+
+    {% if authority.address %}
+       <h4>Onelab membership</h4> 
+       <p>
+               {{ authority.onelab_membership }}
+       </p>
+    {% endif %}
+</div>
+<div class="col-md-6">
+    {% if authority.legal %}
+       <h4>Legal Contact:</h4>
+       <p>
+       {% for c in authority_contacts.legal %}
+                {{ c }} <br />
+       {% endfor %}
+       </p>
+       <br />
+    {% endif %}
+    {% if authority.scientific %}
+       <h4>Scientific Contact:</h4>
+       <p>
+       {% for c in authority_contacts.scientific %}
+               {{ c }} <br />
+       {% endfor %}
+       </p>
+       <br />
+    {% endif %}
+    {% if authority.technical %}
+       <h4>Technical Contact:</h4>
+       <p>
+       {% for c in authority_contacts.technical %}
+               {{ c }} <br />
+       {% endfor %}
+       </p>
+    {% endif %}
+</div>
+<script>$(document).ready(function() {
+{% if authority.name %}
+    auth_name = "{{authority.name}}";
+{% else %}
+    auth_name = "{{authority.authority_hrn}}";
+{% endif %}
+    $('#authority_name').text(auth_name);
+});
+</script>
diff --git a/portal/templates/fed4fire/fed4fire_management-tab-requests.html b/portal/templates/fed4fire/fed4fire_management-tab-requests.html
new file mode 100644 (file)
index 0000000..e255779
--- /dev/null
@@ -0,0 +1,226 @@
+<script type="text/javascript">
+       $(document).ready(function() {
+               $("li#nav-request").addClass("active");
+       });
+       function on_click_event() {
+               var ids = []; 
+               $('.portal__validate__checkbox').each(function(i, el) {
+                       if ($(el).prop('checked')) {
+                               // portal__validate__checkbox__slice__2
+                               var id_array = $(el).attr('id').split('__');
+                               // push(slice__2)
+                               ids.push(id_array[3] + '__' + id_array[4]);
+                       }
+               });
+               if (ids.length > 0) {
+                       var id_str = ids.join('/');
+                       // XXX spinner
+                       $.getJSON('/portal/validate_action/' + id_str,
+                               function(status) {
+                                       $.each(status, function(request_type__id, request_status) {
+                                               // request_status: NAME -> dict (status, description)
+                                               var status_str = '';
+                                               $.each(request_status, function(name, result) {
+                                                       if (status_str != '')
+                                                               status_str += ' -- ';
+
+                                                       if (result.status) {
+                                                               status_str += '<font color="green">OK</font>';
+                                                               $('#portal__validate__checkbox__' + request_type__id).hide();
+                                                       } else {
+                                                               status_str += '<font color="red">ERROR: ' + result.description + '</font>';
+                                                       }
+                                               });
+                                               $('#portal__status__' + request_type__id).html(status_str);
+
+
+                                       });
+                               }
+                       );
+               }
+       }
+</script>
+
+<div class="col-md-12">
+       <h2>From your authorities</h2>
+</div>
+{% if my_authorities %}
+       
+       {% for authority, requests in my_authorities.items %}
+       
+       <div class="col-md-12">
+               <h2>{{authority}}</h2>
+       </div>
+       
+    <table class="table">
+      <th>
+        <td>Type</td>
+        <td>Id</td>
+        <td>Details</td>
+        <td>Timestamp</td>
+        <td>Status</td>
+      </th>
+    {% for request in requests %}
+
+         <tr>
+               <td>
+               {% if request.allowed == 'allowed' %}
+               <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+               {% else %}
+                       {% if request.allowed == 'expired' %}
+                               expired
+                       {% else %} {# denied #}
+                               denied
+                       {% endif %}
+               {% endif %}
+               </td>
+               <td>{{ request.type }}</td>
+               <td>{{ request.id }}</td>
+               <td>
+        {% if request.type == 'user' %}
+            <b>{{request.first_name}} {{request.last_name}}</b> <a href="mailto:{{request.email}}">{{request.email}}</a>
+        {% else %}
+            {% if request.type == 'slice' %}
+            <b>{{request.slice_name}}</b> -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+            {% else %} {# authority #}
+            <b>{{request.site_name}}</b> ({{request.site_authority}}) -- {{request.address_city}}, {{request.address_country}}
+            {% endif %}
+        {% endif %}
+               </td>
+               <td>{{ request.timestamp }}</td>
+               
+               <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+
+    <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+         </tr>
+
+    {% endfor %}
+       </table>
+       {% endfor %}
+
+{% else %}
+       <div class="col-md-12">
+               <i>There is no pending request waiting for validation.</i>
+       </div>
+{% endif %}
+<div>nnllknjkn<br /><br /></div>
+<div class="col-md-12">
+       <h2>From your sub-authorities</h2>
+</div>
+{% if sub_authorities %}
+       
+       {% for authority, requests in sub_authorities.items %}
+       <div class="col-md-12">
+               <h2>{{authority}}</h2>
+       </div>
+       
+       <table class="table">
+             <th>
+               <td>Type</td>
+               <td>Id</td>
+               <td>Details</td>
+               <td>Timestamp</td>
+               <td>Status</td>
+             </th>
+           {% for request in requests %}
+                 <tr>
+                       <td>
+                       {% if request.allowed == 'allowed' %}
+                       <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+                       {% else %}
+                               {% if request.allowed == 'expired' %}
+                                       expired
+                               {% else %} {# denied #}
+                                       denied
+                               {% endif %}
+                       {% endif %}
+                       </td>
+                       <td>{{ request.type }}</td>
+                       <td>{{ request.id }}</td>
+                       <td>
+               {% if request.type == 'user' %}
+               Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+               {% else %}
+                   {% if request.type == 'slice' %}
+               Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+                   {% else %} {# authority #}
+               Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+                   {% endif %}
+               {% endif %}
+                       </td>
+                       <td>{{ request.timestamp }}</td>
+                       
+                       <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+       
+           <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+                 </tr>
+           {% endfor %}
+       </table>
+       {% endfor %}
+{% else %}
+<div class="col-md-12">
+       <i>There is no pending request waiting for validation.</i>
+</div>
+{% endif %}
+
+<div class="col-md-12">
+       <h2>From your authorities with delegation</h2>
+</div>
+
+{% if delegation_authorities %}
+       
+       {% for authority, requests in delegation_authorities.items %}
+       <div class="col-md-12">
+               <h3>{{authority}}</h3>
+       </div>
+       <table class="table">
+                     <th>
+                       <td>Type</td>
+                       <td>Id</td>
+                       <td>Details</td>
+                       <td>Timestamp</td>
+                       <td>Status</td>
+                     </th>
+                   {% for request in requests %}
+                         <tr>
+                               <td>
+                               {% if request.allowed == 'allowed' %}
+                               <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+                               {% else %}
+                                       {% if request.allowed == 'expired' %}
+                                               expired
+                                       {% else %} {# denied #}
+                                               denied
+                                       {% endif %}
+                               {% endif %}
+                               </td>
+                               <td>{{ request.type }}</td>
+                               <td>{{ request.id }}</td>
+                               <td>
+                       {% if request.type == 'user' %}
+                       Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+                       {% else %}
+                           {% if request.type == 'slice' %}
+                       Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+                           {% else %} {# authority #}
+                       Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+                           {% endif %}
+                      {% endif %}
+                               </td>
+                               <td>{{ request.timestamp }}</td>
+                               
+                               <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+               
+                   <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+                         </tr>
+                   {% endfor %}
+       </table>
+               {% endfor %}
+{% else %}
+<div class="col-md-12">
+       <i>There is no pending request waiting for validation.</i>
+</div>
+{% endif %}
+<div class="col-md-12">
+       <button class="btn btn-onelab" type="button" id="portal__validate" onclick="on_click_event();"><span class="glyphicon glyphicon-ok"></span> Validate</button>
+</div>
diff --git a/portal/templates/fed4fire/fed4fire_slice-resource-view.html b/portal/templates/fed4fire/fed4fire_slice-resource-view.html
new file mode 100644 (file)
index 0000000..3fefedf
--- /dev/null
@@ -0,0 +1,121 @@
+{% extends "layout_wide.html" %}
+{% load portal_filters %}
+
+{% block head %}
+<!-- <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyC1RUj824JAiHRVqgc2CSIg4CpKHhh84Lw&sensor=false"></script> -->
+<script src="{{ STATIC_URL }}js/onelab_slice-resource-view.js"></script>
+<script>
+       //myslice.slice = "{{ slice }}";
+
+$(document).ready(function() {
+            $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
+        // find the plugin object inside the tab content referenced by the current tabs
+        $('.plugin', $($(e.target).attr('href'))).trigger('shown.bs.tab');
+        $('.plugin', $($(e.target).attr('href'))).trigger('show');
+            });
+});
+</script>
+{% endblock %}
+
+{% block content %}
+{% widget '_widget-slice-sections.html' %}
+<div class="container-fluid container-resource">
+       <div class="row">
+       <div class="col-md-2">
+               <!-- <div id="select-platform" class="list-group"></div> -->
+               {{filter_testbeds}}
+       </div>
+       <div class="col-md-10" style="height:100%;">
+               <div class="row">
+                       {% if msg %}
+                       <div class="col-md-12"><p class="alert-success">{{ msg }}</p></div>
+                       {% endif %}
+               </div>
+       
+               <div class="row">
+                       <div class="col-md-6">
+                               {{ filter_status }}
+                       </div>
+                       <div class="col-md-1">
+                               {{ apply }}
+                       </div>
+               </div>
+               <!--
+               <div class="list-group-item list-resources">
+                       <span class="list-group-item-heading" style="padding-left: 0;">Resource status:</span>
+                       <a class="list-group-item active" data-panel="resources" href="#" style='display: inline-block !important;'>All</a>
+                       <a class="list-group-item" data-panel="reserved" href="#" style='display: inline-block !important;'>Reserved</a>
+                       <a class="list-group-item" data-panel="pending" href="#" style='display: inline-block !important;'>Pending <span class="badge" id="badge-pending" data-number="0"></span></a>
+               </div>
+               -->
+
+               <div class="row">
+                       <div class="col-md-12">
+                       <ul class="nav nav-tabs">
+                         <li class="active"><a href="#resourcelist" role="tab" data-toggle="tab">Table</a></li>
+                         <li> <a href="#resourcemap" role="tab" data-toggle="tab">Map</a></li>
+                         <li> <a href="#resourcescheduler" role="tab" data-toggle="tab">Scheduler</a></li>
+                       </ul>
+                       </div>
+               </div>
+               
+               <!-- Modal - columns selector -->
+               <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+                       <div class="modal-dialog">
+                       <div class="modal-content">
+                               <div class="modal-header">
+                                       <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+                                               <h4 class="modal-title" id="myModalLabel">Columns selector</h4>
+                               </div>
+                               <div class="modal-body">
+                                       {{columns_editor}}
+                               </div>
+                               <div class="modal-footer">
+                                       <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                               </div>
+                       </div>
+                       </div>
+               </div>
+               
+               
+               <div class="row">
+                       <div class="col-md-12">
+                       <div class="tab-content" style="height:100%;">
+                               <div class="tab-pane active" id="resourcelist">
+                                        <!-- Button trigger modal - columns selector -->
+                                       <button class="btn btn-default btn-sm" style="float:right;" data-toggle="modal" data-target="#myModal">...</button>
+                       {{list_resources}}
+                                       <!-- <table cellpadding="0" cellspacing="0" border="0" class="table" id="objectList"></table> -->
+                               </div>
+                               <div class="tab-pane" id="resourcemap">
+                       {{map_resources}}
+                               </div>
+                               <div class="tab-pane" id="resourcescheduler">
+                       {{scheduler}}
+                               </div>
+       
+                               <!--
+                               <div id="reserved" class="tab-pane" style="height:370px;display:none;">
+                       <table width="80%">
+                           <tr><th width="50%" style="text-align:center;">resources</th><th width="50%" style="text-align:center;">leases</th></tr>
+                           <tr>
+                               <td style="text-align:center">{{list_reserved_resources}}</td>
+                               <td style="text-align:center">{{list_reserved_leases}}</td>
+                           </tr>
+                       </table>
+                               </div>
+                               <div id="pending" class="tab-pane" style="height:370px;display:none;">
+                       {{pending_resources}}
+                               </div>
+                               <div id="sla_dialog" class="tab-pane" style="height:370px;display:none;">
+                       {{sla_dialog}}
+                               </div>
+       -->
+       
+                       </div>
+               </div>
+       </div>
+       </div>
+       </div>
+</div>
+{% endblock %}
diff --git a/portal/templates/fed4fire/fed4fire_slice-tab-experiment.html b/portal/templates/fed4fire/fed4fire_slice-tab-experiment.html
new file mode 100644 (file)
index 0000000..0ca237f
--- /dev/null
@@ -0,0 +1,111 @@
+<div class="col-md-2">
+</div>
+<div class="col-md-8">
+       <h2>How to access your slice</h2>
+       <h3>PlanetLab Europe</h3>
+       
+       <p>
+               PlanetLab Europe resources are accessible directly via SSH. Your SSH public key is deployed automatically
+               on the reserved nodes. To access your slice on a resource just type the following command:
+       </p>
+       {%if ple_resources%}
+       <p class="command">
+       {%for resource in ple_resources %}
+               $ ssh {{ple_slicename}}@{{resource}}<br>
+       {%endfor%}
+       </p>
+        <h4>Windows users</h4>
+        <p>Use <a href="http://www.putty.org/" target="_blank">SSH client.</a></p>
+
+       {%else%}
+               <p><b>NOTE:</b> You did not reserve any PLE resources yet. Once reserved, you will get the actual SSH command. A specimen command is given below:</p>
+               <p class="command">
+               $ ssh {{ple_slicename}}@planetlab-resource.hostname.com<br>
+               </p>
+                <h4>Windows users</h4>
+                <p>Use <a href="http://www.putty.org/" target="_blank">SSH client.</a></p>
+
+       {%endif%}
+       <p><strong>NOTE:</strong> Your original slicename <b>{{slicename}}</b> has been converted to PlanetLab specific format <b>{{ple_slicename}}</b> in order to do SSH.</p>
+       <p>Please note that the first '.' is replaced by number 8 and the rest of the dot/s are replaced by underscore/s.</p>
+       <p>
+               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.
+       </p>
+       
+       <h3>NITOS</h3>
+       
+       <p>
+        NITOS resources are not directly accessible. You will need to log in on a gateway server and from there access the node.
+        The NITOS server address is nitlab.inf.uth.gr, so to connect to the NITOS server:
+       </p>
+       <p class="command">
+       $ ssh {{slicename}}@nitlab.inf.uth.gr
+       </p>
+       <h4>Windows users</h4>
+       <p>Use <a href="http://www.putty.org/" target="_blank">SSH client.</a></p>
+
+       <p>
+       <!-- In order to connect to NITOS server he has to upload his public key on the server. 
+       For now we do it this way: http://nitlab.inf.uth.gr/NITlab/index.php/your-ssh-keys. 
+       I think this is a procedure that needs to be done at the registration phase of the user, 
+       through myslice, Broker etc. but I will answer you in a couple of days for sure. -->
+       </p>
+
+       <p>
+               You will then need to prepare the resource by loading an OMF image on it:
+       </p>
+       
+       <p class="command">
+               $ omf load -i baseline_grid.ndz -t omf.nitos.node016
+       </p>
+
+       <p>
+               Turn on the node:
+       </p>
+       
+       <p class="command">
+               $ omf tell -a on -t omf.nitos.node016
+       </p>
+       <p>
+               And finally ssh on the node:
+       </p>
+       <p class="command">
+               $ ssh root@node016
+       </p>
+       <p>
+               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
+               restart the OMF Resource Controller and finally execute the experiment:
+       </p>
+       <p class="command">
+               $ omf exec --slice slice_name your_exp.rb
+       </p>
+       <p>
+       The complete tutorial is available at the following address:
+       <a target="_blank" href="http://nitlab.inf.uth.gr/NITlab/index.php/testbed/instructions/basic-tutorial">NITOS basic tutorial</a>
+       </p>
+       
+       <br />
+       
+       <h2>Available Tools</h2>
+       <p><img src="{{ STATIC_URL }}img/terminal_icon.png" width="50"> <b>SSH</b></p>
+       <p>
+       Secure Shell (SSH) is a cryptographic network protocol for secure data communication, remote command-line login, remote command execution, and other secure network services between two networked computers that connects, via a secure channel over an insecure network, a server and a client (running SSH server and SSH client programs, respectively). The protocol specification distinguishes between two major versions that are referred to as SSH-1 and SSH-2.
+       </p>
+       <p> More Info: <a href="http://en.wikipedia.org/wiki/Secure_Shell" target="_blank">http://en.wikipedia.org/wiki/Secure_Shell</a></p>
+       <br>
+       <br>
+       <p><img src="{{ STATIC_URL }}img/nepi_logo.png" width="90"></p>
+       <p>NEPI, the Network Experimentation Programming Interface, is a life-cycle management tool for network experiments. The idea behind NEPI is to provide a single tool to design, deploy, and control network experiments, and gather the experiment results. Going further, NEPI was specially conceived to function with arbitrary experimentation platforms, so researchers could use a single tool to work with network simulators, emulators, or physical testbeds, or even a mixture of them. To accomplish this, NEPI provides a high-level interface to describe experiments that is independent from any experimentation platform, but is able to capture platform specific configurations. Experiment definitions can be stored in XML format to be later reproduced, and modified according to experimentation needs. Experiment execution is orchestrated by a global experiment controller, that is platform independent, and different platform-dependent testbed controllers, creating a control hierarchy that is able t adapt to platform specific requirements while providing an integrated control scheme.</p>
+       <p> More Info: <a href="http://nepi.inria.fr" target="_blank">http://nepi.inria.fr</a></p>
+       <br>
+       <p><img src="{{ STATIC_URL }}img/omf-logo.png" width="90"></p>
+       <p>OMF is a Testbed Control, Measurement and Management Framework.</p>
+       <p>
+       OMF was originally developed for the ORBIT wireless testbed at Winlab, Rutgers University. Since 2007, OMF has been actively extended to operate on testbeds with many different type of network and resource technologies. It is now deployed and used on different testbeds in Australia, Europe, and in the U.S. OMF is currently being extended further to support exciting new features and technologies. This website is hosting this ongoing activity. OMF development is now conducted essentially within the TEMPO project at NICTA (Australia) in strong collaboration with Winlab (Rutgers University).
+       </p>
+       <p>In addition to the main OMF software, this site also hosts OMF sub-projects addressing various related aspects of a testbed's control, measurement, and management.</p>
+       <p>More Info: <a href="http://mytestbed.net/projects/omf" target="_blank">http://mytestbed.net/projects/omf</a></p>
+</div>
+<div class="col-md-2">
+</div>
diff --git a/portal/templates/fed4fire/fed4fire_slice-view.html b/portal/templates/fed4fire/fed4fire_slice-view.html
new file mode 100644 (file)
index 0000000..c2d52c3
--- /dev/null
@@ -0,0 +1,18 @@
+{% extends "layout_wide.html" %}
+
+{% block head %}
+{% endblock %}
+
+{% block content %}
+{% include theme|add:"_widget-slice-sections.html" %}
+         
+<div class="container-fluid tab-content container-slice">
+  <div class="tab-pane active row" id="info">...</div>
+  <div class="tab-pane row" id="testbeds">...</div>
+  <div class="tab-pane row" id="resources">...</div>
+  <div class="tab-pane row" id="users">...</div>
+  <!-- <div class="tab-pane row" id="statistics">...</div> -->
+  <!-- <div class="tab-pane row" id="measurements">...</div> -->
+  <div class="tab-pane row" id="experiment">...</div>
+</div>         
+{% endblock %}
diff --git a/portal/templates/fed4fire/fed4fire_slice_request_denied.html b/portal/templates/fed4fire/fed4fire_slice_request_denied.html
new file mode 100644 (file)
index 0000000..ca2b910
--- /dev/null
@@ -0,0 +1,17 @@
+<img src="http://www.fed4fire.eu/uploads/media/fed4fire-logo.jpg">
+<br>
+<p>Dear Fed4FIRE user,</p>
+<p></p>
+<p>You have recently requested the following slice on the Fed4FIRE portal({{portal_url}}):</p> 
+<br>
+<b>Slice name   :</b> {{slice_name}}<br>
+<b>URL          :</b> {{url}}<br>
+<b>Purpose      :</b> {{purpose}}<br>
+<br>c
+<p>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.</p>
+<br>
+<p>We wish you a fruitful user experience on Fed4FIRE.</p>
+<br>
+<p>Yours sincerely,</p>
+<p>The Fed4FIRE team</p>
diff --git a/portal/templates/fed4fire/fed4fire_slice_request_denied.txt b/portal/templates/fed4fire/fed4fire_slice_request_denied.txt
new file mode 100644 (file)
index 0000000..21897b4
--- /dev/null
@@ -0,0 +1,15 @@
+Dear Fed4FIRE user,
+
+You have recently requested the following slice on the Fed4FIRE 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 Fed4FIRE.
+
+Yours sincerely,
+The Fed4FIRE team
+
index 888e032..1a49a14 100644 (file)
@@ -2,10 +2,21 @@
 <br>
 <h1>NEW SLICE REQUEST</h1>
 <br>
-<b>slice name      :</b> {{slice_name}}</br>
-<b>number of nodes :</b> {{number_of_nodes}}</br>
-<b>type of nodes   :</b> {{type_of_nodes}}</br>
-<b>purpose         :</b> {{purpose}}</br>
-<b>email           :</b> {{email}}</br>
+<p>You are receiving this request because we have you listed as a manager at an organization that uses Fed4FIRE.</p>
+<p>A user from your organization has requested the creation of a new slice, which will allow him or her to reserve testbed resources to conduct an experiment.</p>
+<br>
+<b>Slice name      :</b> {{slice_name}}</br>
+<b>URL                            :</b> {{url}}</br>
+<b>Purpose         :</b> {{purpose}}</br>
+<b>Organization           :</b> {{organization}}</br>
+<b>Email           :</b> {{email}}</br>
 <b>Portal url     :</b> {{current_site}}</br> 
+<p></p>
+<p>You can see new slice request <a href="http://{{current_site}}/portal/validate">in the portal.</a><p>
+<p>Please be sure that you know the user who is requesting this slice, as you are responsible for his or her actions.</p>
+<p>And kindly ensure that the stated experiment purpose is clear, and, if there is a website that explains the website, that a URL is provided.</p>
+<p>Fed4FIRE and its affiliated testbeds exist purely to support useful and interesting work. To ensure the future of these environments, we need to know what work is actually being done.</p>
+<p></p>
+<p>If you believe that you have received this message in error, or if you have any questions, kindly contact contact@fed4fire.eu</p>
+
 
diff --git a/portal/templates/fed4fire/fed4fire_slice_request_email.txt b/portal/templates/fed4fire/fed4fire_slice_request_email.txt
new file mode 100644 (file)
index 0000000..5b7ccb0
--- /dev/null
@@ -0,0 +1,20 @@
+NEW SLICE REQUEST
+
+You are receiving this request because we have you listed as a manager at an organization that uses Fed4FIRE.
+A user from your organization has requested the creation of a new slice, which will allow him or her to reserve testbed resources to conduct an experiment.
+
+Slice name      : {{slice_name}}
+URL                    : {{url}}
+Purpose         : {{purpose}}
+Email           : {{email}}
+Organization   : {{organization}}
+Portal url             : {{current_site}}
+
+You can see new slice request in: http://{{current_site}}/portal/validate
+Please be sure that you know the user who is requesting this slice, as you are responsible for his or her actions.
+And kindly ensure that the stated experiment purpose is clear, and, if there is a website that explains the website, that a URL is provided. 
+Fed4FIRE and its affiliated testbeds exist purely to support useful and interesting work. To ensure the future of these environments, we need to know what work is actually being done. 
+
+If you believe that you have received this message in error, or if you have any questions, kindly contact contact@fed4fire.eu
+
diff --git a/portal/templates/fed4fire/fed4fire_slice_request_validated.html b/portal/templates/fed4fire/fed4fire_slice_request_validated.html
new file mode 100644 (file)
index 0000000..fbcbea8
--- /dev/null
@@ -0,0 +1,21 @@
+<img src="http://www.fed4fire.eu/uploads/media/fed4fire-logo.jpg">
+<br>
+<p>Dear Fed4FIRE user,</p>
+<p></p>
+<p>You have recently requested a slice in the Fed4FIRE portal.</p>
+<br>
+<b>Slice name   :</b> {{slice_name}}<br>
+<b>URL          :</b> {{url}}<br>
+<b>Purpose      :</b> {{purpose}}<br>
+<p></p>
+<p>
+       We are pleased to inform you that a manager from your institution has validated your slice request on the Fed4FIRE portal. 
+       You can now add resources to you slice and start experimenting.
+</p>
+<p></p>
+<p>We wish you a fruitful user experience with the Fed4FIRE portal.</p>
+<p></p>
+<p>Yours sincerely,</p>
+<p>The Fed4FIRE team</p>
+
+
diff --git a/portal/templates/fed4fire/fed4fire_slice_request_validated.txt b/portal/templates/fed4fire/fed4fire_slice_request_validated.txt
new file mode 100644 (file)
index 0000000..a89be97
--- /dev/null
@@ -0,0 +1,15 @@
+Dear Fed4FIRE user,
+
+You have recently requested a slice in the Fed4FIRE portal.
+
+Slice name      : {{slice_name}}
+URL             : {{url}}
+Purpose         : {{purpose}}
+
+
+We are pleased to inform you that a manager from your institution has validated your slice request on the Fed4FIRE portal. You can now add resources to you slice and start experimenting.
+
+We wish you a fruitful user experience with the Fed4FIRE portal.
+
+Yours sincerely,
+The Fed4FIRE team
diff --git a/portal/templates/fed4fire/fed4fire_slicerequest_view.html b/portal/templates/fed4fire/fed4fire_slicerequest_view.html
new file mode 100644 (file)
index 0000000..211f35d
--- /dev/null
@@ -0,0 +1,108 @@
+{% extends "layout.html" %}
+{% load i18n %}
+
+{% block content %}
+       <div class="row">
+               <div class="col-md-12">
+                        <div class="breadcrumbs">
+                                Experiment &nbsp;>&nbsp; Request a new Slice
+                        </div>
+               </div>
+       </div>
+
+       {% if errors %}
+       <div class="row">
+               <div class="col-md-12">
+               <ul class="error">
+                 {% for error in errors %}
+                 <li>{{ error }}</li>
+                 {% endfor %}
+               </ul>
+               </div>
+       </div>
+       {% endif %}
+       
+       <div class="row">
+               <div class="col-md-8 el">
+                       <form role="form" method="post">
+                       {% csrf_token %}
+                         <div class="form-group" style="display:none">
+                           <input type="email" class="form-control" id="email" style="width:300px" value="{{ email }}" readonly="readonly">
+                         </div>
+                         <div class="form-group">
+                           <input type="text" class="form-control" name="slice_name" id="slice_name" style="width:300px" placeholder="Slice name" value="{{slice_name}}" 
+                               title="Please enter a name for your slice"required="required">
+                         </div>
+                         <div class="form-group">
+                               {%if 'is_pi'  in pi %}
+                               <input type="text" class="form-control" id="authority_hrn" name="org_name" style="width:300px" placeholder="Organization" 
+                               title="An authority responsible for vetting your slice" required="required">
+                               {%else%}
+                           <input type="text" class="form-control" id="authority_hrn" name="org_name" placeholder="Organization" style="width:300px;" 
+                               title="An authority responsible for vetting your slice" required="required" readonly>
+                               {%endif%}
+                         </div>
+                         <div class="form-group">
+                           <input type="text" class="form-control" name="url" id="url" style="width:300px" placeholder="Experiment URL (if one exists)"
+                               title="Please provide the url of your experiment if you have one." value="{{url}}">
+                         </div>
+                         <div class="form-group">
+                               <textarea id="purpose" name="purpose" class="form-control" rows="6" placeholder="Experiment purpose" style="width:300px" 
+                               title="Purpose of your experiment (informative)" required="required">{{ purpose }}</textarea>
+                         </div>
+                         {%if 'is_pi'  in pi %}        
+                         <button type="submit" id=submit_pi class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Create slice</button>
+                         {%else%}
+                         <button type="submit" class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Request slice</button>
+                         {%endif%}     
+                       </form>
+       
+               </div>
+       </div>
+               
+<script>
+jQuery(document).ready(function(){
+       
+       /*$("#authority_hrn").load("/rest/user/", {"fields" : ["parent_authority"], "filters": {"user_hrn": "{{ user_hrn }}"}}, function(data) {
+               var jsonData = JSON.parse(data);
+        $(this).attr("value", jsonData[0]['parent_authority']);
+    });*/
+       $("#authority_hrn").val("{{authority_name}}");
+       var availableTags = [
+    {% if authorities %}
+        {% for authority in authorities %}
+            {% if authority.name %}
+                {value:"{{ authority.name }}",label:"{{authority.name}}"},
+                       // to show only full name
+           // {% else %}
+           //     {value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
+            {% endif %}
+        {% endfor %}    
+    {% else %}
+        {value:"",label:"No authority found !!!"}
+    {% endif %}
+    ];
+       // sorting the list
+       availableTags.sort(function(a,b){
+               var nameA=a.value.toLowerCase(), nameB=b.value.toLowerCase();
+               if (nameA < nameB) {
+               return -1;
+               }
+               if (nameA > nameB) {
+               return 1;
+               }
+       return 0;
+       }); 
+    $( "#authority_hrn" ).autocomplete({
+      source: availableTags,
+      minLength: 0,
+      select: function( event, ui ) {console.log(jQuery(this));}
+    });
+
+       $("#submit_pi").click(function() {
+               localStorage.clear();
+       });
+});
+</script>
+{% endblock %}
+
index dffad05..9f50d2c 100644 (file)
@@ -11,7 +11,7 @@
                        <h3>Users</h3>
                        <ul>
                        <li><h4>Who is a user?</h4></li>
-                       <p>A user is an experimenter who registers to the OneLab portal and able to use all the facilites that the portal has to offer. However, a user does not
+                       <p>A user is an experimenter who registers to the Fed4FIRE portal and able to use all the facilites that the portal has to offer. However, a user does not
                        have the right to do any admin operation such as managing slices, users and resources.</p>
                        
                        
@@ -36,7 +36,7 @@
                        <p>Once you register, you can login to your account with limited access. It means that you can view your account details, modify your name and password. You can also view other pages. However, you will not be able to see any slices as well as resources before your account validation. But you can <a href="/portal/slice_request/">Request Slice</a> before being validated. Therefore, the PI will validate your account as well as your requested slice. Once validated, you will be able to see your slice and if you click on your slice, you will be able to see resources in that slice and you can reserve nodes and start your experiment.</p>
                        
                        <li><h4>How can I get access to a slice?</h4></li>
-                       <p>If you are a completely new user, you have to <a href="/portal/slice_request/">Request Slice</a>. It is upto the PI of your authority to accept/reject your slice request. </br>On the other hand, if you are a new user to the portal but you already have an account in OneLab SFA registry and you have access to slices, you will be able to see all your slices once your account is validated by the PI.</p> 
+                       <p>If you are a completely new user, you have to <a href="/portal/slice_request/">Request Slice</a>. It is upto the PI of your authority to accept/reject your slice request. </br>On the other hand, if you are a new user to the portal but you already have an account in Fed4FIRE SFA registry and you have access to slices, you will be able to see all your slices once your account is validated by the PI.</p> 
                        
                        <li><h4>I forgot my password, how to recover it?</h4></li>
                        <p>If you have an account in the portal but you forgot the password, you can always <a href="/portal/pass_reset/">Reset your password</a>.</p></ul>
diff --git a/portal/templates/fed4fire/fed4fire_user_request_denied.html b/portal/templates/fed4fire/fed4fire_user_request_denied.html
new file mode 100644 (file)
index 0000000..56f7f4f
--- /dev/null
@@ -0,0 +1,11 @@
+<img src="http://www.fed4fire.eu/uploads/media/fed4fire-logo.jpg">
+<br>
+<p>Dear {{first_name}} {{last_name}},</p>
+<p></p>
+<p>You have recently registered as a user to Fed4FIRE 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.</p>
+<p></p>
+<p>We  wish you all the best.</p>
+<p></p>
+<p>Yours sincerely,</p>
+<p>The Fed4FIRE team</p>
+
diff --git a/portal/templates/fed4fire/fed4fire_user_request_denied.txt b/portal/templates/fed4fire/fed4fire_user_request_denied.txt
new file mode 100644 (file)
index 0000000..b3afba5
--- /dev/null
@@ -0,0 +1,8 @@
+Dear {{first_name}} {{last_name}},
+
+You have recently registered as a user to Fed4FIRE 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 Fed4FIRE team
index 5c6801f..60abd27 100644 (file)
@@ -4,8 +4,13 @@
 <br>
 <b>First name   :</b> {{first_name}}<br>
 <b>Last name    :</b> {{last_name}}<br>
+<b>Organization :</b> {{organization}}<br>
 <b>Authority hrn:</b> {{authority_hrn}}<br>
 <b>Public key   :</b> {{public_key}}<br>
 <b>Email        :</b> {{email}}<br>
 <b>User hrn     :</b> {{user_hrn}}<br>
 <b>Portal url  :</b> {{ current_site }}<br>
+<p></p>
+<p>You can validate the user <a href="http://{{current_site}}/portal/validate">here</a>.<p>
+<br>
+<p>Please note that the validation request will only become visible once the user has confirmed his/her email address.</p>
diff --git a/portal/templates/fed4fire/fed4fire_user_request_email.txt b/portal/templates/fed4fire/fed4fire_user_request_email.txt
new file mode 100644 (file)
index 0000000..17ce184
--- /dev/null
@@ -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/fed4fire/fed4fire_user_request_validated.html b/portal/templates/fed4fire/fed4fire_user_request_validated.html
new file mode 100644 (file)
index 0000000..9048a6c
--- /dev/null
@@ -0,0 +1,14 @@
+<img src="http://www.fed4fire.eu/uploads/media/fed4fire-logo.jpg">
+<br>
+<p>Dear {{first_name}} {{last_name}},</p>
+<p></p>
+<p>It is my pleasure to welcome you as a fully signed-up user of the Fed4FIRE portal. Fed4FIRE provides you with access to world class computer networking testbeds. Our aim at Fed4FIRE is to promote the use of these testbeds for research and development by industry, for scientific research, and for university level laboratory exercises.</p>
+<p></p>
+</p>
+Your entry point for access to the testbeds is the Fed4FIRE 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 Fed4FIRE public/private key pair, or you may use an experiment control tool such as as NEPI or OMF. The Fed4FIRE  operations team is standing by at contact@fed4fire.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.
+</p>
+<p></p>
+</p>We  wish you a fruitful user experience with the Fed4FIRE portal.</p>
+<p></p>
+<p>Yours sincerely,</p>
+<p>THE Fed4FIRE team</p>
diff --git a/portal/templates/fed4fire/fed4fire_user_request_validated.txt b/portal/templates/fed4fire/fed4fire_user_request_validated.txt
new file mode 100644 (file)
index 0000000..40a1b03
--- /dev/null
@@ -0,0 +1,10 @@
+Dear {{first_name}} {{last_name}},
+
+It is my pleasure to welcome you as a fully signed-up user of the Fed4FIRE portal. Fed4FIRE provides you with access to world class computer networking testbeds. Our aim at Fed4FIRE is to promote the use of these testbeds for research and development by industry, for scientific research, and for university level laboratory exercises.
+
+Your entry point for access to the testbeds is the Fed4FIRE 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 Fed4FIRE public/private key pair, or you may use an experiment control tool such as as NEPI or OMF. TheFed4FIRE operations team is standing by at contact@fed4fire.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 Fed4FIRE portal.
+
+Yours sincerely,
+The Fed4FIRE team
index 230a14d..40761b5 100644 (file)
@@ -1,29 +1,37 @@
+<div class="container">
+       <div class="row">
+               <div class="col-md-12">
+                        <div class="breadcrumbs">
+                                Experiment &nbsp;>&nbsp; Slice: {{ slice }}
+                        </div>
+               </div>
+       </div>
+</div>
+<div class="container-fluid container-slice">
+<div class="row">
+               <div class="col-md-12">
 {% if section == "resources" %}
 <ul class="nav nav-tabs nav-section">
-       <li><a href="/slice/{{ slice }}#info"><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="About MySlice" /> {{ slice }}</a></li>
-<!--   <li><a href="/slice/{{ slice }}#testbeds">Testbeds</a></li> -->
+       
+       <!-- <li><a href="/slice/{{ slice }}#testbeds">Testbeds</a></li> -->
        <li class="active"><a class="link" href="/resources/{{ slice }}">Resources</a></li>
        <li><a href="/slice/{{ slice }}#users">Users</a></li>
-       <li class="sla"><a href="/slice/{{ slice }}#sla">SLA</a></li>
-
-<!--   <li><a href="/slice/{{ slice }}#experiment">Statistics</a></li> 
-       <li><a href="/slice/{{ slice }}#measurements">Measurements</a></li>
-       <li><a href="/slice/{{ slice }}#experiment" data-toggle="tab">Experiment</a></li> -->
-
+       <li><a href="/slice/{{ slice }}#info">Information</a></li>
+       <!-- <li><a href="/slice/{{ slice }}#experiment">Statistics</a></li> -->
+       <!-- <li><a href="/slice/{{ slice }}#experiment">Measurements</a></li> -->
+       <li><a href="/slice/{{ slice }}#experiment">Tools</a></li>
 </ul>
 {% else %}
 <ul class="nav nav-tabs nav-section">
-       <li class="active"><a href="#info"><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="About MySlice" /> {{ slice }}</a></li>
-       <!--<li class="testbeds"><a href="#testbeds">Testbeds</a></li> -->
+       <!-- <li class="testbeds"><a href="#testbeds">Testbeds</a></li> -->
        <li><a class="link" href="/resources/{{ slice }}">Resources</a></li>
        <li class="users"><a href="#users">Users</a></li>
-
-       <!-- <li class="statistics"><a href="#experiment">Statistics</a></li>
-       <li class="measurements"><a href="#experiment">Measurements</a></li>
-       <li class="experiment"><a href="#experiment" data-toggle="tab">Experiment</a></li> -->
-       <li class="sla"><a href="#sla">SLA</a></li>
-
+       <li class="active"><a href="#info">Information</a></li>
+       <!-- <li class="statistics"><a href="#experiment">Statistics</a></li> -->
+       <!-- <li class="measurements"><a href="#experiment">Measurements</a></li> -->
+       <li class="experiment"><a href="#experiment">Tools</a></li>
 </ul>
+
 <script>
 $(document).ready(function() {
        $('.nav-tabs a').click(function (e) {
@@ -33,7 +41,16 @@ $(document).ready(function() {
        var id = $(this).attr('href').substr(1);        
        $("#" + id).load('/' + id + '/{{ slice }}/');
        });
-       $('div#info').load('/info/{{ slice }}/');
+       
+       var hash = window.location.hash;
+       if (hash) {
+               $('.nav-tabs a[href='+hash+']').click();
+       } else {
+               $('div#info').load('/info/{{ slice }}/');
+       }
 });
 </script>
 {% endif %}
+</div>
+</div>
+</div>
\ No newline at end of file
index 66a5ce9..ddb4518 100644 (file)
@@ -20,7 +20,7 @@
                <ul>
                        <li id="nav-account"><a href="/portal/account/">{{ username }}</a></li>
                        <li>|</li>
-                       <li id="nav-institution" class=""><a href="/portal/institution">AUTHORITY</a></li>
+                       <!--<li id="nav-institution" class=""><a href="/portal/institution">AUTHORITY</a></li>-->
                        <li class="slices">
                                <a class="dropdown-toggle" data-toggle="dropdown" href="#">
                                        SLICES <span class="caret"></span>
@@ -39,7 +39,6 @@
                                                </ul>
                                </div>
                                </li>
-                       <li id="nav-request"><a href="/portal/validate">REQUESTS</a></li>
                        <li id="nav-service"><a href="/portal/servicedirectory">SERVICES</a></li>
                        <li id="nav-support"><a href="http://doc.fed4fire.eu/support.html">SUPPORT</a></li>
                        <li>|</li>
diff --git a/portal/templates/onelab/onelab_base.html b/portal/templates/onelab/onelab_base.html
deleted file mode 100644 (file)
index fdab352..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-{# This is required by insert_above #}{% insert_handler %}<!DOCTYPE html>
-<html lang="en"><head>
-<title>OneLab - {{ section }}</title>
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<link rel="shortcut icon" href="/static/img/myslice-icon.png">
-{# This is where insert_str will end up #}{% media_container prelude %}
-{% include 'messages-transient-header.html' %}
-<script type="text/javascript"> {# raw js code - use {% insert prelude_js %} ... {% endinsert %} #} {% container prelude_js %}</script>
-<script src="{{ STATIC_URL }}js/jquery.dataTables.min.js"></script>
-<script src="{{ STATIC_URL }}js/bootstrap.datatables.js"></script>
-<script src="{{ STATIC_URL }}js/myslice.js"></script>
-<script src="{{ STATIC_URL }}js/myslice-ui.js"></script>
-<style type="text/css">{# In case we need to add raw css code #}{% container prelude_css %}</style>
-{{ header_prelude }}
-{% block head %} {% endblock head %}
-{# let's add these ones no matter what #}
-{% insert_str prelude "js/jquery.min.js" %}
-{% insert_str prelude "js/angular/angular.min.js" %}
-{% insert_str prelude "js/jquery.html5storage.min.js" %}
-{% insert_str prelude "js/messages-runtime.js" %}
-{% insert_str prelude "js/class.js" %}
-{% insert_str prelude "js/plugin-helper.js" %}
-{% insert_str prelude "js/mustache.js" %}
-{% insert_str prelude "js/hashtable.js" %}
-{% insert_str prelude "js/plugin.js" %}
-{% insert_str prelude "js/manifold.js" %}
-{% insert_str prelude "css/manifold.css" %}
-{% insert_str prelude "css/plugin.css" %}
-{% insert_str prelude "js/bootstrap.js" %}
-{% insert_str prelude "css/bootstrap.css" %}
-{% insert_str prelude "js/bootstrap-datepicker.js" %}
-{% insert_str prelude "css/datepicker.css" %}
-{% insert_str prelude "js/bootstrap-slider.js" %}
-{% insert_str prelude "css/slider.css" %}
-{% insert_str prelude "css/topmenu.css" %}
-{% insert_str prelude "js/logout.js" %}
-<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/{{ theme }}.css">
-</head>
-<body ng-app="ManifoldApp">
-{% block container %}
-       {% block topmenu %}
-       {% include theme|add:"__widget-topmenu.html" %}
-       {% endblock topmenu %}
-       {% include 'messages-transient.html' %}
-       {% block base_content %}
-       {% endblock %}
-{% endblock container %}
-</body>
-</html>
index 85eee75..78502cf 100644 (file)
@@ -82,24 +82,11 @@ loadedTabs = [];
             async: "false",
             url: "{{ servdirurl }}appservices/",
             success: function(data, status, jqXHR){
-                // console.log(data);
-                // $.each(data, function(i, item){
-                //     console.log(item);
-                //     var tr = $('<tr>').append(
-                //         $('<td id="name">').text(item.name),
-                //         $('<td>').text(item.provider),
-                //         $('<td>').append('<a href="' + item.endPoint + '">' + item.endPoint + "</a>"),
-                //         $('<td>').text(item.protocol),
-                //         $('<td>').text(item.APIBasic),
-                //         $('<td>').text(item.briefDescription)
-                //     );
-                //     $("#appservices-tab > tbody:last").append(tr);
-                //     $("td#name").click(function(){
-                //         window.location.href = data.endPoint;
-                //     });
-                // });
+
                   function createToggle(name){
                       return function(){
+                        var icon = $('p#name-' + name + ' span');
+                        icon.toggleClass("glyphicon-chevron-down");
                         var el = $('p#expandable-' + name);
                         if(!el.is(':animated')){
                           $(el).toggle(300);
@@ -121,21 +108,23 @@ loadedTabs = [];
 
                     var row = $('<div class="row">').append(
                       $('<div>').addClass("col-md-3 portfolio-item").append(
-                        $('<img>').attr('src', "{{ STATIC_URL }}img/servicedirectory/" + imgsrc)
+                        $('<a href="' + item.APILink + '">').append(
+                          $('<img>').attr('src', "{{ STATIC_URL }}img/servicedirectory/" + imgsrc)
+                        )
                      ),
                       $('<div>').addClass("col-md-6 portfolio-item").append(
-                        $('<p id="name-' + item.name.replace(/ /g,'') + '">').text(item.name),
+                        $('<p id="name-' + item.name.replace(/ /g,'') + '">').append(
+                          $('<span class="glyphicon glyphicon-chevron-right">'), " " + item.name),
                         $('<p>').text(item.briefDescription),
                         $('<p>').text("Provider: " + item.provider),
                         $('<p>').append('Endpoint: <a href="' + item.endPoint + '">' + item.endPoint + "</a>"),
                         $('<p id="expandable-' + item.name.replace(/ /g,'') + '">').text(item.fullDescription).hide(),
                         $('<p id="expandable-' + item.name.replace(/ /g,'') + '">').text("Protocol: " + item.protocol).hide(),
                         $('<p id="expandable-' + item.name.replace(/ /g,'') + '">')
-                              .append('API documentation: <a href="' + item.APILink + '">' + item.APILink + "</a>").hide(),
-                        $('<p id="expandable-' + item.name.replace(/ /g,'') + '">').text(item.APIBasic).hide()
+                              .append('API documentation: <a href="' + item.APILink + '">' + item.APILink + "</a>").hide()
                       )
                     );
-                    $("#appservices-tab").append(row);
+                    $('#appservices-tab').append(row);
                     $('p#name-' + item.name.replace(/ /g,'')).click(createToggle(item.name.replace(/ /g,'')));
                 });
 
@@ -173,88 +162,6 @@ loadedTabs = [];
                 console.log("ERROR: " + status);
             }
         });
-        
-  //       $.post("/rest/authority/",{'filters':{'authority_hrn':'{{user_details.parent_authority}}'}}, function( data ) {
-  //           var authority_data = [];
-  //           var onelab_data = [];
-               //      /* 'city','enabled','legal','longitude','onelab_membership','address','parent_authority','slice','user','country',
-  //           'tech','abbreviated_name','url','postcode','description','scientific','authority_hrn','latitude','name' */
-  //           $.each( data, function( key, val ) {
-  //               authority_row = "<img src='{{ STATIC_URL }}img/institutions/{{user_details.parent_authority}}.gif' alt='' /><br>";
-  //               authority_row += "<br>";
-  //               authority_row += "<b>authority:</b> "+val.authority_hrn+"<br>";
-  //               authority_data.push(authority_row);
-  //           });
-  //           $("div#authority-data").html(authority_data.join( "" ));
-  //           $("div#onelab-data").html(onelab_data.join( "" ));
-  //           $("div#authority-tab-loaded").css("display","block");
-  //           $("div#authority-tab-loading").css("display","none");
-  //        });
-
-  //       $.post("/rest/slice/",{'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
-  //           var list_slices = [];
-  //           var table_slices = [];
-  //           /* "slice_hrn", "slice_description", "slice_type", "parent_authority", "created", "nodes", "slice_url", "slice_last_updated", "users", "slice_urn", "slice_expires" */
-  //           $.each( data, function( key, val ) {
-  //               list_slices.push( "<li><a href=\"portal/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></li>" );
-  //               if(val.nodes=="undefined" || val.nodes==null){
-  //                   nodes_length=0;
-  //               }else{
-  //                   nodes_length=val.nodes.length;
-  //               }
-  //               if(val.users=="undefined" || val.users==null){
-  //                   users_length=0;
-  //               }else{
-  //                   users_length=val.users.length;
-  //               }
-
-  //               if(val.slice_url=="undefined" || val.slice_url==null){
-  //                   slice_url="";
-  //               }else{
-  //                   slice_url="<a href='"+val.slice_url+"' target='_blank'>"+val.slice_url+"</a>";
-  //               }
-                
-  //               slice_row = "<tr id='"+val.slice_hrn+"'>";
-  //               slice_row += "<td><input type='checkbox' class='slice' id='"+val.slice_hrn+"'></td>";
-  //               slice_row += "<td><a href=\"/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></td>";
-  //               slice_row += "<td>"+users_length+"</td>";
-  //               slice_row += "<td>"+slice_url+"</td>";
-  //               //slice_row += "<td>"+nodes_length+"</td>";
-  //               slice_row += "<td>"+val.slice_expires+"</td>";
-  //               slice_row += "</tr>";
-  //               table_slices.push(slice_row);
-                
-  //           });
-           
-  //           /* $("div#slice-list").html($( "<ul/>", { html: list_slices.join( "" ) })); */
-  //           $("table#slice-tab tr:last").after(table_slices.join( "" ));
-  //           $("div#slice-tab-loaded").css("display","block");
-  //           $("div#slice-tab-loading").css("display","none");
-  //       });
-
-               // $.post("/rest/user/",{'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
-  //            var list_users = [];
-  //            var table_users = [];
-               //       /* Available fields
-               //       user_gid, user_enabled, slices, pi_authorities, keys, parent_authority, user_first_name,
-               //       user_urn, user_last_name, user_phone, user_hrn, user_email, user_type
-               //       */
-  //            $.each( data, function( key, val ) {
-  //                list_users.push( "<li><a href=\"portal/user/"+val.user_email+"\">" + val.user_email + "</a></li>" );
-  //                user_row = "<tr id='"+val.user_hrn+"'>";
-  //                user_row += "<td><input type='checkbox' class='user' id='"+val.user_hrn+"'></td>";
-  //                user_row += "<td>"+val.user_email+"</td>";
-  //                user_row += "<td>"+val.user_hrn+"</td>";
-  //                user_row += "<td>"+val.user_first_name+"</td>";
-  //                user_row += "<td>"+val.user_last_name+"</td>";
-               //               user_row += "<td>"+val.user_enabled+"</td>";
-  //                user_row += "</tr>";
-  //                table_users.push(user_row);
-  //            });
-  //            $("table#user-tab tr:last").after(table_users.join( "" ));
-  //            $("div#user-tab-loaded").css("display","block");
-  //            $("div#user-tab-loading").css("display","none");
-  //         });
 
    {% endif %}
 
index 9dca1d1..29b7baf 100644 (file)
                $ ssh {{ple_slicename}}@{{resource}}<br>
        {%endfor%}
        </p>
+        <h4>Windows users</h4>
+        <p>Use <a href="http://www.putty.org/" target="_blank">SSH client.</a></p>
        {%else%}
                <p><b>NOTE:</b> You did not reserve any PLE resources yet. Once reserved, you will get the actual SSH command. A specimen command is given below:</p>
                <p class="command">
                $ ssh {{ple_slicename}}@planetlab-resource.hostname.com<br>
                </p>
        {%endif%}
+       <h4>Windows users</h4>
+       <p>Use <a href="http://www.putty.org/" target="_blank">SSH client.</a></p>
        <p><strong>NOTE:</strong> Your original slicename <b>{{slicename}}</b> has been converted to PlanetLab specific format <b>{{ple_slicename}}</b> in order to do SSH.</p>
        <p>Please note that the first '.' is replaced by number 8 and the rest of the dot/s are replaced by underscore/s.</p>
        <p>
@@ -35,7 +39,9 @@
        <p class="command">
                ssh {{username}}@fit3-dev.inrialpes.fr
        </p>
-       
+       <h4>Windows users</h4>
+       <p>Use <a href="http://www.putty.org/" target="_blank">SSH client.</a></p>
+
        <h3>NITOS</h3>
        
        <p>
@@ -45,7 +51,9 @@
        <p class="command">
        $ ssh {{slicename}}@nitlab.inf.uth.gr
        </p>
-       
+        <h4>Windows users</h4>
+        <p>Use <a href="http://www.putty.org/" target="_blank">SSH client.</a></p>
+
        <p>
        <!-- In order to connect to NITOS server he has to upload his public key on the server. 
        For now we do it this way: http://nitlab.inf.uth.gr/NITlab/index.php/your-ssh-keys. 
index 5b4e2ee..1314175 100644 (file)
@@ -54,10 +54,10 @@ class UsersView (LoginRequiredAutoLogoutView, ThemeView):
 
             status_list.append(user_status)
             #get authority
-            #if user['config']:
-            user_config = json.loads(user['config'])
-            user_authority = user_config.get('authority','N/A')
-            authority_list.append(user_authority)
+            if user['config'] is not None:
+                user_config = json.loads(user['config'])
+                user_authority = user_config.get('authority','N/A')
+                authority_list.append(user_authority)
     
         user_list = [{'email': t[0], 'status': t[1], 'authority':t[2]}
             for t in zip(email_list, status_list, authority_list)]
index 2252189..4372a35 100644 (file)
@@ -59,4 +59,4 @@ def servicesStatus(request):
                 result[s]['status'] = 'ko'
 
         
-    return HttpResponse(json.dumps(result), content_type="application/json")
\ No newline at end of file
+    return HttpResponse(json.dumps(result), content_type="application/json")
diff --git a/rest/sfa_api.py b/rest/sfa_api.py
new file mode 100644 (file)
index 0000000..04b156b
--- /dev/null
@@ -0,0 +1,142 @@
+from sfa.trust.certificate      import Keypair, Certificate
+from sfa.client.sfaserverproxy  import SfaServerProxy
+from sfa.client.return_value    import ReturnValue
+from sfa.util.xrn               import Xrn, get_leaf, get_authority, hrn_to_urn, urn_to_hrn
+from manifold.core.query        import Query
+from manifold.models            import db
+from manifold.models.platform   import Platform
+from manifold.models.user       import User
+
+from django.shortcuts           import render_to_response
+
+from unfold.loginrequired       import LoginRequiredView
+
+from rest import ObjectRequest, error
+
+from string import join
+
+from django.http import HttpResponse
+from rest import error
+import os,json
+
+import ConfigParser 
+
+def dispatch(request, method):
+    Config = ConfigParser.ConfigParser()
+    Config.read(os.getcwd() + "/myslice/monitor.ini")
+
+    # hardcoded user to be replaced by auth
+    user_email = "loic.baron@lip6.fr"
+
+    # Get this as parameters
+    slice_hrn = "fed4fire.upmc.berlin"
+    urn = hrn_to_urn(slice_hrn, "slice")
+    #urn = hrn_to_urn("fed4fire.upmc.loic_baron", "user")
+
+    platforms = list()
+    options   = list()
+    rspec = ''
+    results = dict()
+
+    if request.method == 'POST':
+        req_items = request.POST
+    elif request.method == 'GET':
+        req_items = request.GET
+
+    for el in req_items.items():
+        if el[0].startswith('rspec'):
+            rspec += el[1]
+        if el[0].startswith('platform'):
+            platforms += req_items.getlist('platform[]')
+        elif el[0].startswith('options'):
+            options += req_items.getlist('options[]')
+
+    if len(platforms)==0:
+        platforms.append('myslice')
+    #results = {'method':method,'platforms':platforms,'rspec':rspec,'options':options}
+
+    from manifoldapi.manifoldapi    import execute_admin_query
+    for pf in platforms:
+        platform = get_platform_config(pf)
+        print platform
+        if 'sm' in platform and len(platform['sm']) > 0:
+            print 'sm'
+            server_url = platform['sm']
+        if 'rm' in platform and len(platform['rm']) > 0:
+            print 'rm'
+            server_url = platform['rm']
+        if 'registry' in platform and len(platform['registry']) > 0:
+            print 'registry'
+            server_url = platform['registry']
+    
+        if not Config.has_option('monitor', 'cert') :
+             return HttpResponse(json.dumps({'error' : '-1'}), content_type="application/json")
+
+        cert = os.path.abspath(Config.get('monitor', 'cert'))
+        if not os.path.isfile(cert) :
+             return HttpResponse(json.dumps({'error' : '-1'}), content_type="application/json")
+
+        if not Config.has_option('monitor', 'pkey') :
+             return HttpResponse(json.dumps({'error' : '-2'}), content_type="application/json")
+
+        pkey = os.path.abspath(Config.get('monitor', 'pkey'))
+        if not os.path.isfile(pkey) :
+             return HttpResponse(json.dumps({'error' : '-2'}), content_type="application/json")
+        server = SfaServerProxy(server_url, pkey, cert)
+
+        # Get user config from Manifold
+        user_config = get_user_config(user_email, pf)
+        if 'delegated_user_credential' in user_config:
+            user_cred = user_config['delegated_user_credential']
+        else:
+            user_cred = {}
+
+        #if 'delegated_slice_credentials' in user_config:
+        #    for slice_name, cred in user_config['delegated_slice_credentials']:
+        #        if slice_name == slice_param
+
+        if method == "GetVersion": 
+            result = server.GetVersion()
+        elif method == "ListResources":
+            api_options = {}
+            #api_options ['call_id'] = unique_call_id()
+            api_options['geni_rspec_version'] = {'type': 'GENI', 'version': '3'}
+            result = server.ListResources([user_cred], api_options)
+        elif method == "Describe":
+            api_options = {}
+            #api_options ['call_id'] = unique_call_id()
+            api_options['geni_rspec_version'] = {'type': 'GENI', 'version': '3'}
+            result = server.Describe([urn] ,[object_cred], api_options)
+
+        else:
+            return HttpResponse(json.dumps({'error' : '-3','msg':'method not supported yet'}), content_type="application/json")
+
+        results[pf] = result
+
+    return HttpResponse(json.dumps(results), content_type="application/json")
+
+def get_user_account(user_email, platform_name):
+    """
+    Returns the user configuration for a given platform.
+    This function does not resolve references.
+    """
+    user = db.query(User).filter(User.email == user_email).one()
+    platform = db.query(Platform).filter(Platform.platform == platform_name).one()
+    accounts = [a for a in user.accounts if a.platform == platform]
+    if not accounts:
+        raise Exception, "this account does not exist"
+
+    if accounts[0].auth_type == 'reference':
+        pf = json.loads(accounts[0].config)['reference_platform']
+        return get_user_account(user_email, pf)
+
+    return accounts[0]
+
+def get_user_config(user_email, platform_name):
+    account = get_user_account(user_email, platform_name)
+    return json.loads(account.config) if account.config else {}
+
+def get_platform_config(platform_name):
+    platform = db.query(Platform).filter(Platform.platform == platform_name).one()
+    return json.loads(platform.config) if platform.config else {}
index c00ca2f..8091f4e 100755 (executable)
@@ -12,13 +12,13 @@ from django.conf import settings
 
 """REST client to SLA Manager.
 
-Contains a generic rest client and wrappers over this generic client 
+Contains a generic rest client and wrappers over this generic client
 for each resource.
 
 Each resource client implements business-like() functions, but
 returns a tuple (output, requests.Response)
 
-The resource clients are initialized with the rooturl and a path, which 
+The resource clients are initialized with the rooturl and a path, which
 are combined to build the resource url. The path is defaulted to the known
 resource path. So, for example, to create a agreements client:
 
@@ -32,29 +32,27 @@ c = restclient.Factory.agreements()
 
 """
 
-_PROVIDERS_PATH = "providerso"
-_AGREEMENTS_PATH = "agreementso"
-_TEMPLATES_PATH = "templateso"
-_VIOLATIONS_PATH = "violationso"
+_PROVIDERS_PATH = "providers"
+_AGREEMENTS_PATH = "agreements"
+_TEMPLATES_PATH = "templates"
+_VIOLATIONS_PATH = "violations"
 _ENFORCEMENTJOBS_PATH = "enforcements"
 
 rooturl = settings.SLA_MANAGER_URL
 
-# SLA_MANAGER_USER = "normal_user"
-# SLA_MANAGER_PASSWORD = "password"
 
 class Factory(object):
     @staticmethod
-    def agreements():
-        """Returns aREST client for Agreements
+    def agreements(path=_AGREEMENTS_PATH):
+        """Returns a REST client for Agreements
 
         :rtype : Agreements
          """
-        return Agreements(rooturl)
+        return Agreements(rooturl, path)
 
     @staticmethod
     def providers():
-        """Returns aREST client for Providers
+        """Returns a REST client for Providers
 
         :rtype : Providers
         """
@@ -62,7 +60,7 @@ class Factory(object):
 
     @staticmethod
     def violations():
-        """Returns aREST client for Violations
+        """Returns a REST client for Violations
 
         :rtype : Violations
         """
@@ -70,7 +68,7 @@ class Factory(object):
 
     @staticmethod
     def templates():
-        """Returns aREST client for Violations
+        """Returns a REST client for Violations
 
         :rtype : Violations
         """
@@ -78,12 +76,13 @@ class Factory(object):
 
     @staticmethod
     def enforcements():
-        """Returns aREST client for Enforcements jobs
+        """Returns a REST client for Enforcements jobs
 
         :rtype : Enforcements
         """
         return Enforcements(rooturl)
 
+
 class Client(object):
 
     def __init__(self, root_url):
@@ -104,22 +103,34 @@ class Client(object):
         Returns a requests.Response
 
         :rtype : request.Response
-        :param str path: remaining path from root url; 
+        :param str path: remaining path from root url;
             empty if desired path equal to rooturl.
         :param kwargs: arguments to requests.get
-        
-        Example: 
+
+        Example:
             c = Client("http://localhost:8080/service")
             c.get("/resource", headers = { "accept": "application/json" })
         """
         url = _buildpath_(self.rooturl, path)
-        kwargs["auth"] = HTTPBasicAuth(settings.SLA_MANAGER_USER, settings.SLA_MANAGER_PASSWORD)
+        if "testbed" in kwargs:
+            url = url + "?testbed=" + kwargs["testbed"]
+
+        if "headers" not in kwargs:
+            kwargs["headers"] = {"accept": "application/xml"}
+
+        kwargs["auth"] = HTTPBasicAuth(settings.SLA_MANAGER_USER,
+                                       settings.SLA_MANAGER_PASSWORD)
+
+        # for key, values in kwargs.iteritems():
+        #     print key, values
+
         result = requests.get(url, **kwargs)
         print "GET {} {} {}".format(
             result.url, result.status_code, result.text[0:70])
+        print result.encoding
 
         return result
-    
+
     def post(self, path, data=None, **kwargs):
         """Just a wrapper over request.post, just in case
 
@@ -140,7 +151,17 @@ class Client(object):
             )
         """
         url = _buildpath_(self.rooturl, path)
-        kwargs["auth"] = HTTPBasicAuth(settings.SLA_MANAGER_USER, settings.SLA_MANAGER_PASSWORD)
+
+        if "testbed" in kwargs:
+            url = url + "?testbed=" + kwargs["testbed"]
+
+        if "headers" not in kwargs:
+            kwargs["headers"] = {"accept": "application/xml",
+                                 "content-type": "application/xml"}
+
+        kwargs["auth"] = HTTPBasicAuth(settings.SLA_MANAGER_USER,
+                                       settings.SLA_MANAGER_PASSWORD)
+
         result = requests.post(url, data, **kwargs)
         location = result.headers["location"] \
             if "location" in result.headers else "<null>"
@@ -148,7 +169,6 @@ class Client(object):
             result.url, result.status_code, location)
         return result
 
-    
 
 class _Resource(object):
 
@@ -184,7 +204,7 @@ class _Resource(object):
 
         content_type = r.headers.get('content-type', '')
 
-        print("content-type = " + content_type)
+        #print("content-type = " + content_type)
         if content_type == 'application/json':
             result = r.json()
         elif content_type == 'application/xml':
@@ -202,18 +222,21 @@ class _Resource(object):
         resources = self._processresult(r, self.listconverter)
         return resources, r
 
-    def getbyid(self, id):
+    def getbyid(self, id, params):
         """Get resource 'id'"""
-        r = self.client.get(id)
+        r = self.client.get(id, params=params)
         resource = _Resource._processresult(r, self.converter)
         return resource, r
 
-    def get(self, params):
+    def get(self, path, params):
         """Generic query over resource: GET /resource?q1=v1&q2=v2...
 
         :param dict[str,str] params: values to pass as get parameters
         """
-        r = self.client.get("", params=params)
+        if path is None:
+            path = ""
+
+        r = self.client.get(path, params=params)
         resources = self._processresult(r, self.listconverter)
         return resources, r
 
@@ -272,27 +295,36 @@ class Agreements(object):
         """
         return self.res.get(dict(providerId=providerid))
 
-    def getstatus(self, agreementid):
+    def getstatus(self, agreementid, testbed):
         """Get guarantee status of an agreement
 
         :param str agreementid :
         :rtype : wsag_model.AgreementStatus
         """
-        path = _buildpath_(agreementid, "guaranteestatus")
-        r = self.res.client.get(path, headers={'accept': 'application/json'})
+        path = _buildpath_(_AGREEMENTS_PATH, agreementid, "guaranteestatus")
+        r = self.res.client.get(path, headers={'accept': 'application/json'},
+                                params={'testbed': testbed})
 
         json_obj = r.json()
-        
+
         status = wsag_model.AgreementStatus.json_decode(json_obj)
 
         return status, r
-    
-    def create(self, agreement):
+
+    def getbyslice(self, slicename):
+        """Get the agreements corresponding to a slice
+
+        :rtype : list[wsag_model.Agreement]
+        """
+        return self.res.get(slicename, dict())
+
+    def create(self, agreement, testbed):
         """Create a new agreement
 
         :param str agreement: sla template in ws-agreement format.
         """
-        return self.res.create(agreement)
+        return self.res.create(agreement, params={'testbed': testbed})
+
 
 class Templates(object):
 
@@ -319,7 +351,7 @@ class Templates(object):
 
         :rtype: wsag_model.Template
         """
-        return self.res.getbyid(provider_id)
+        return self.res.getbyid(provider_id, {"testbed": provider_id})
 
     def create(self, template):
         """Create a new template
@@ -328,6 +360,7 @@ class Templates(object):
         """
         self.res.create(template)
 
+
 class Providers(object):
 
     def __init__(self, root_url, path=_PROVIDERS_PATH):
@@ -363,6 +396,7 @@ class Providers(object):
         body = provider.to_xml()
         return self.res.create(body)
 
+
 class Violations(object):
 
     def __init__(self, root_url, path=_VIOLATIONS_PATH):
@@ -389,7 +423,7 @@ class Violations(object):
         """
         return self.res.getbyid(violationid)
 
-    def getbyagreement(self, agreement_id, term=None):
+    def getbyagreement(self, agreement_id, testbed, term=None):
         """Get the violations of an agreement.
 
         :param str agreement_id:
@@ -397,8 +431,9 @@ class Violations(object):
             violations from all terms will be returned
         :rtype: list[wsag_model.Violation]
         """
-        return self.res.get(
-            {"agreementId": agreement_id, "guaranteeTerm": term})
+        return self.res.get("", params={"agreementId": agreement_id,
+                                        "guaranteeTerm": term,
+                                        "testbed": testbed})
 
 
 class Enforcements(object):
@@ -420,17 +455,20 @@ class Enforcements(object):
         """
         return self.res.getall()
 
-    def getbyagreement(self, agreement_id):
+    def getbyagreement(self, agreement_id, testbed):
         """Get the enforcement of an agreement.
 
         :param str agreement_id:
-        
+
         :rtype: list[wsag_model.Enforcement]
         """
-        return self.res.getbyid(agreement_id)    
+        return self.res.getbyid(agreement_id, params={"testbed": testbed})
 
 
 def _buildpath_(*paths):
+    if "" in paths:
+        paths = [path for path in paths if path != ""]
+
     return "/".join(paths)
 
 
@@ -440,7 +478,6 @@ def main():
     #
     global rooturl
     rooturl = "http://127.0.0.1:8080/sla-service"
-    
 
     c = Factory.templates()
     #r = c.getall()
@@ -450,12 +487,9 @@ def main():
 
     #r = c.getbyconsumer('RandomClient')
     r = c.getbyid("template02")
-    
 
     print r
 
 
 if __name__ == "__main__":
     main()
-
-
index caecf26..9883098 100755 (executable)
@@ -5,9 +5,9 @@ to sla manager.
 It is intended as backend service for a rest interface.\r
 \r
 The json input must work together with the templates to form a valid template\r
- or agreement for Xifi (be careful!)\r
+ or agreement for fed4fire (be careful!)\r
 \r
-This (very simple) service is coupled to the way xifi is interpreting\r
+This (very simple) service is coupled to the way fed4fire is interpreting\r
 ws-agreement.\r
 \r
 \r
@@ -18,10 +18,13 @@ from sla.slaclient import wsag_model
 from sla.slaclient import restclient\r
 from sla.slaclient.templates.fed4fire.django.factory import Factory as TemplateFactory\r
 import sla.slaclient.templates.fed4fire as fed4fire\r
-from time import localtime, strftime\r
+#from time import localtime, strftime\r
 import uuid\r
+import dateutil.parser\r
+\r
+\r
 class ServiceContext(object):\r
-    def __init__(self, restfactory = None, templatefactory=None):\r
+    def __init__(self, restfactory=None, templatefactory=None):\r
         """\r
         :type restfactory: restclient.Factory\r
         """\r
@@ -101,38 +104,42 @@ def createagreement(json_data, context):
 \r
     # Builds AgreementInput from json\r
     data = jsonparser.agreementinput_from_json(json_data)\r
+\r
     # Read template from manager\r
+    # client_templates.getbyid(provider_id, testbed)\r
     slatemplate, request = client_templates.getbyid(data.template_id)\r
     # Copy (overriding if necessary) from template to AgreementInput\r
     final_data = data.from_template(slatemplate)\r
+\r
     slaagreement = fed4fire.render_slaagreement(final_data)\r
 \r
     client_agreements = context.restfactory.agreements()\r
-    return client_agreements.create(slaagreement)\r
-    \r
-\r
-def createagreementsimplified(template_id, user, expiration_time):\r
-        context = ServiceContext(\r
-            restclient.Factory(),\r
-            TemplateFactory()\r
-        )\r
-        \r
-        agreement = {\r
-            "agreement_id": str(uuid.uuid4()),\r
-            "template_id": template_id,\r
-            "expiration_time": expiration_time,\r
-            "consumer": user,\r
-        }\r
-    \r
-        json_data = json.dumps(agreement)\r
-\r
-        return createagreement(json_data, context)\r
-    \r
-def main():\r
-    createagreementsimplified("iMindsServiceWiLab2", "virtualwall", "2014-04-34T23:12:12")\r
-\r
-\r
-if __name__ == "__main__":\r
-    main()\r
-      \r
-        \r
+    return client_agreements.create(slaagreement, data.template_id)\r
+\r
+\r
+def createagreementsimplified(template_id, user, expiration_time, resources):\r
+    context = ServiceContext(\r
+        restclient.Factory(),\r
+        TemplateFactory()\r
+    )\r
+\r
+    agreement = {\r
+        "agreement_id": str(uuid.uuid4()),\r
+        "template_id": template_id,\r
+        "expiration_time": expiration_time.strftime('%Y-%m-%dT%H:%M:%S%Z'),\r
+        "consumer": user,\r
+        "guarantees": [\r
+            {\r
+                "name": "uptime",\r
+                "bounds": ["0", "1"],\r
+                "scope": {\r
+                    "service_name": "",\r
+                    "scope": resources[template_id]\r
+                }\r
+            }\r
+        ]\r
+    }\r
+\r
+    json_data = json.dumps(agreement)\r
+\r
+    return createagreement(json_data, context)\r
index 3dc8fca..d4a2300 100755 (executable)
@@ -69,8 +69,6 @@ def agreementinput_from_json(json_data):
     }\r
     """\r
     d = json.loads(json_data)\r
-    if "expiration_time" in d:\r
-        d["expiration_time"] = dateutil.parser.parse(d["expiration_time"])\r
 \r
     t = AgreementInput(\r
         agreement_id=d.get("agreement_id", None),\r
@@ -111,10 +109,18 @@ def _json_parse_guarantee_terms(d):
     """\r
     result = []\r
     for term in d.get("guarantees", None) or ():\r
+        gs = AgreementInput.GuaranteeTerm.GuaranteeScope(\r
+            term["scope"].get("service_name", ""),\r
+            term["scope"].get("scope", "")\r
+            )\r
+        print "*******GS****"\r
+        print gs\r
         result.append(\r
             AgreementInput.GuaranteeTerm(\r
                 metric_name=term["name"],\r
-                bounds=tuple(term["bounds"])\r
+                bounds=tuple(term["bounds"]),\r
+                guarantee_scopes=gs\r
             )\r
         )\r
-    return result
\ No newline at end of file
+\r
+    return result\r
index 096a7e3..7cf9a66 100755 (executable)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>\r
 <wsag:Agreement xmlns:wsag="http://www.ggf.org/namespaces/ws-agreement"\r
-    {% if data.agreement_id %}AgreementId="{{data.agreement_id}}"{% endif %}>\r
+    {% if data.agreement_id %}wsag:AgreementId="{{data.agreement_id}}"{% endif %}>\r
     {% if data.agreement_name %}<wsag:Name>{{data.agreement_name}}</wsag:Name>{% endif %}\r
 \r
     <wsag:Context>\r
                 {% endfor %}</wsag:Variables>\r
             </wsag:ServiceProperties>\r
             {% for term in data.guarantee_terms %}\r
-            <wsag:GuaranteeTerm Name="{{term.name}}">\r
-                {# do not need servicescope #}\r
-                   {% for scope in term.scopes %}\r
-                <wsag:ServiceScope ServiceName="{{scope.servicename}}"/>\r
+            <wsag:GuaranteeTerm wsag:Name="{{term.name}}">\r
+                {% for gs in term.scopes %}\r
+                <wsag:ServiceScope wsag:ServiceName="{{gs.servicename}}">\r
+                    {{ gs.scope }}\r
+                </wsag:ServiceScope>\r
                 {% endfor %}\r
                 <wsag:ServiceLevelObjective>\r
                     <wsag:KPITarget>\r
index efb939c..2de5201 100755 (executable)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-\r
-"""Template system for xifi project.\r
+"""Template system for fed4fire project.\r
 \r
 The specific template system is configured with the factory module variable.\r
 \r
@@ -32,7 +32,7 @@ Usage:
     data = sla.slaclient.templates.fed4fire.TemplateInput(template_id="template-test")\r
     slatemplate_xml = sla.slaclient.templates.fed4fire.render_slatemplate(data)\r
 \r
-Notes about agreements in XiFi:\r
+Notes about agreements in fed4fire:\r
     The ws-agreement specification does not address where to place the name/id\r
     of the service (as known outside SLA) being defined in the\r
     agreement/template xml. So, it has been defined an element\r
@@ -43,7 +43,7 @@ Notes about agreements in XiFi:
     The guarantee terms, service description terms, etc, use the attribute\r
     serviceName to reference (internally in the xml) the service. So, there\r
     could be more than one serviceName in a xml (as opposed to the former\r
-    serviceId). In Xifi, there is only one service per agreement, so we\r
+    serviceId). In fed4fire, there is only one service per agreement, so we\r
     can give serviceId and serviceName the same value.\r
 \r
     A ServiceReference defines how a serviceName is known externally: a\r
@@ -68,7 +68,7 @@ Notes about agreements in XiFi:
     (they are used to describe the service to be instantiated), so we can\r
     extrapolate the location as the "abstract location of the metric".\r
 \r
-    In summary, in XiFi, the service properties will hold the metrics being\r
+    In summary, in fed4fire, the service properties will hold the metrics being\r
     monitored for a service.\r
 \r
     And the guarantee terms hold the constraints that are being enforced for\r
@@ -88,11 +88,11 @@ Notes about agreements in XiFi:
             </wsag:ServiceLevelObjective>\r
         </wsag:GuaranteeTerm>\r
 \r
-    * Name is a name for the guarantee term. In Xifi, the name will have the\r
+    * Name is a name for the guarantee term. In fed4fire, the name will have the\r
       value "GT_<metric_name>"\r
     * ServiceName is an internal reference in the agreement to the service\r
       being enforced, as an agreement can created for more than one service.\r
-      In Xifi, to my knowledge, one service: one agreement, so this service\r
+      In fed4fire, to my knowledge, one service: one agreement, so this service\r
       name is not really important.\r
     * KpiName is a name given to the constraint, and I am using the same name\r
       as the service property used in the constraint. This makes more sense\r
@@ -106,7 +106,7 @@ Notes about agreements in XiFi:
 """\r
 \r
 from sla.slaclient import wsag_model\r
-import pdb\r
+import json\r
 \r
 from sla.slaclient.templates.fed4fire.django.factory import Factory\r
 factory = Factory()\r
@@ -133,7 +133,7 @@ def render_slaagreement(data):
     print "render_slaagreement"\r
     template = _getfactory().slaagreement()\r
     #pdb.set_trace()\r
-    rendered = template.render(data) \r
+    rendered = template.render(data)\r
     return rendered\r
 \r
 \r
@@ -196,20 +196,49 @@ class AgreementInput(object):
 \r
     class GuaranteeTerm(object):\r
 \r
+        class GuaranteeScope(object):\r
+\r
+            def __init__(self,\r
+                         servicename="",\r
+                         scope=""):\r
+\r
+                self.servicename = servicename\r
+                self.scope = scope\r
+\r
+            def __repr__(self):\r
+                s = "<GuaranteeScope(servicename={}, scope={})>"\r
+                return s.format(\r
+                    self.servicename,\r
+                    self.scope\r
+                )\r
+\r
         def __init__(self,\r
                      metric_name="",\r
-                     bounds=(0, 0)):\r
+                     bounds=(0, 0),\r
+                     guarantee_scopes=()):\r
             """Creates a GuaranteeTerm.\r
 \r
             Take into account that the GT's name is based on the metric_name.\r
-            :param str metric_name: name of the service property being enforced.\r
-            :param bounds: (lower, upper) bounds of the metric values.\r
+            :param str metric_name: name of the service property being enforced\r
+            :param bounds: (lower, upper) bounds of the metric values\r
             :type bounds: (float, float)\r
             """\r
             self.name = "GT_{}".format(metric_name)\r
             self.metric_name = metric_name\r
             self.kpiname = metric_name\r
             self.bounds = bounds\r
+            self.guarantee_scopes = guarantee_scopes\r
+\r
+        def __repr__(self):\r
+            s = "<GuaranteeTerm(name={}, metric_name={}, " \\r
+                "kpiname={}, bounds={}, guarantee_scopes={})>"\r
+            return s.format(\r
+                self.name,\r
+                self.metric_name,\r
+                self.kpiname,\r
+                self.bounds,\r
+                repr(self.guarantee_scopes)\r
+            )\r
 \r
     def __init__(self,\r
                  agreement_id="",\r
@@ -228,7 +257,7 @@ class AgreementInput(object):
         :param str agreement_name: optional agreement name\r
         :param str service_id: Domain id/name of the service.\r
         :param str consumer: Id of the consumer party in the agreement.\r
-        :param str provider: Resource Id of the provider party in the agreement.\r
+        :param str provider: Resource Id of the provider party in the agreement\r
           The provider must exist previously in the SlaManager.\r
         :param str template_id: TemplateId of the template this agreement is\r
           based on.\r
@@ -248,7 +277,7 @@ class AgreementInput(object):
         self.template_id = template_id\r
         self.expiration_time = expiration_time\r
         self.expiration_time_iso = \\r
-            expiration_time.isoformat() if expiration_time else None\r
+            expiration_time if expiration_time else None\r
         self.service_properties = service_properties\r
         self.guarantee_terms = guarantee_terms\r
 \r
@@ -278,6 +307,11 @@ class AgreementInput(object):
         #\r
         # NOTE: templateinput does not address guaranteeterms (yet)\r
         #\r
+\r
+        for _, gt in slatemplate.guaranteeterms.items():\r
+            gt.scopes[0].scope = self.guarantee_terms[0].guarantee_scopes.scope\r
+            gt.scopes[0].scope = [x.encode('utf-8') for x in gt.scopes[0].scope]\r
+\r
         result = AgreementInput(\r
             agreement_id=self.agreement_id,\r
             agreement_name=self.agreement_name,\r
@@ -287,7 +321,8 @@ class AgreementInput(object):
             template_id=slatemplate.template_id,\r
             expiration_time=self.expiration_time,\r
             service_properties=slatemplate.variables.values(),\r
+            #guarantee_terms=self.guarantee_terms\r
             guarantee_terms=slatemplate.guaranteeterms.values()\r
         )\r
-        print result.guarantee_terms[0]\r
+\r
         return result\r
index f141d6a..271a8f5 100755 (executable)
@@ -1,4 +1,6 @@
 from datetime import datetime
+from dateutil import tz
+import dateutil.parser
 
 """Contains the bean models for the SlaManager xml/json types
 """
@@ -23,7 +25,7 @@ class Agreement(object):
                 repr(self.provider),
                 repr(self.consumer),
                 repr(self.service))
-            
+
         def service_formatted(self):
             return self.service.replace('_', ' ')
 
@@ -31,8 +33,11 @@ class Agreement(object):
             return self.template_id.replace('Service', ' - ')
 
         def time_formatted(self):
-            import dateutil.parser
+            from_zone = tz.tzutc()
+            to_zone = tz.tzlocal()
             time = dateutil.parser.parse(self.expirationtime)
+            time = time.replace(tzinfo=from_zone)
+            time = time.astimezone(to_zone)
             return time.strftime('%d-%m-%Y at %H:%M:%S')
 
     class Property(object):
@@ -43,7 +48,8 @@ class Agreement(object):
             self.location = ""
 
         def __repr__(self):
-            str_ = "<Property(name={}, servicename={}, metric={}, location={})>"
+            str_ = "<Property(name={}, servicename={}, \
+                    metric={}, location={})>"
             return str_.format(
                 repr(self.name),
                 repr(self.servicename),
@@ -69,7 +75,8 @@ class Agreement(object):
                 self.customservicelevel = ""
 
             def __repr__(self):
-                s = "<ServiceLevelObjective(kpiname={}, customservicelevel={})>"
+                s = "<ServiceLevelObjective(kpiname={}, \
+                    customservicelevel={})>"
                 return s.format(
                     repr(self.kpiname),
                     repr(self.customservicelevel)
@@ -113,7 +120,6 @@ class Agreement(object):
 
 
 class Template(Agreement):
-    #egarrido this code has been copied from xifi and has not beeing tested
     def __init__(self):
         super(Template, self).__init__()
         self.template_id = ""
@@ -140,7 +146,8 @@ class Enforcement(object):
         return ("<Enforcement(agreement_id={}, enabled={})>".format(
                 self.agreement_id,
                 self.enabled)
-        )
+                )
+
 
 class AgreementStatus(object):
 
@@ -167,9 +174,9 @@ class AgreementStatus(object):
         return (
             "<AgreementStatus( agreement_id={}, guaranteestatus={}, " +
             "guaranteeterms={})>").format(
-                self.agreement_id,
-                self.guaranteestatus,
-                repr(self.guaranteeterms))
+            self.agreement_id,
+            self.guaranteestatus,
+            repr(self.guaranteeterms))
 
     @staticmethod
     def json_decode(json_obj):
@@ -191,23 +198,25 @@ class Violation(object):
         self.uuid = ""
         self.contract_uuid = ""
         self.service_scope = ""
+        self.service_name = ""
         self.metric_name = ""
         self.datetime = datetime.utcnow()
         self.actual_value = 0
 
     def __repr__(self):
-        return ("<Violation(uuid={}, agremeent_id={}, service_scope={}, " +
-            "metric_name={}, datetime={}, actual_value={})>".format(
+        return ("<Violation(uuid={}, datetime={}, contract_uuid={}, \
+                service_name={}, service_scope={}, metric_name={}, \
+                actual_value={})>\n".format(
                 self.uuid,
+                self.datetime,
                 self.contract_uuid,
+                self.service_name,
                 self.service_scope,
                 self.metric_name,
-                self.datetime,
                 self.actual_value)
-        )
+                )
 
     def format_time(self):
-        # return datetime.strptime(self.datetime.datetime.utcnow,'%Y-%m-%d %H:%M:%S')
         # return str(datetime.fromtimestamp(self.datetime))
         return str(self.datetime)
 
@@ -222,7 +231,8 @@ class Provider(object):
         return ("<Provider(uuid={}, name={})>".format(
                 self.uuid,
                 self.name)
-        )
+                )
+
     def to_xml(self):
         xml = "<provider><uuid>{}</uuid><name>{}</name></provider>""".format(
             self.uuid,
@@ -240,4 +250,4 @@ class Provider(object):
         out = wsag_model.Provider.from_dict(json_obj)
         """
         result = Provider(d["uuid"], d["name"])
-        return result        
+        return result
index 831df53..d32a591 100755 (executable)
@@ -9,7 +9,7 @@ to a more-friendly POJO instances.
 The converters are designed to be pluggable: see ListConverter.
 
 
-Usage: 
+Usage:
 c = AnyConverter() or
 c = ListConverter(AnyOtherConverter())
 
@@ -22,8 +22,14 @@ c.convert(root.getroot())
 
 """
 
-from xml.etree import ElementTree
-from xml.etree.ElementTree import Element
+try:
+    # Much faster and lighter library (C implementation)
+    from xml.etree import cElementTree as ElementTree
+except ImportError:
+    from xml.etree import ElementTree
+
+from xml.etree.ElementTree import QName
+
 import dateutil.parser
 
 from wsag_model import Agreement
@@ -81,7 +87,13 @@ class ListConverter(Converter):
     def convert(self, xmlroot):
         result = []
 
-        for item in xmlroot.find("items"):      # loop through "items" children
+        # Converter for the old xml structure
+        # for item in xmlroot.find("items"): # loop through "items" children
+        #     inner = self.innerconverter.convert(item)
+        #     result.append(inner)
+        # return result
+
+        for item in xmlroot:      # loop through children
             inner = self.innerconverter.convert(item)
             result.append(inner)
         return result
@@ -132,17 +144,19 @@ class EnforcementConverter(Converter):
         result.enabled = xmlroot.find("enabled").text
         return result
 
+
 class ViolationConverter(Converter):
     """Converter for a violation.
 
     Input:
     <violation>
-        <uuid>ce0e148f-dfac-4492-bb26-ad2e9a6965ec</uuid>
-        <contract_uuid>agreement04</contract_uuid>
-        <service_scope></service_scope>
-        <metric_name>Performance</metric_name>
-        <datetime>2014-01-14T11:28:22Z</datetime>
-        <actual_value>0.09555700123360344</actual_value>
+        <uuid>1d94627e-c318-41ba-9c45-42c95b67cc32</uuid>
+        <contract_uuid>26e5d5b6-f5a1-4eb3-bc91-606e8f24fb09</contract_uuid>
+        <service_name>servicename1</service_name>
+        <service_scope>test1</service_scope>
+        <metric_name>UpTime</metric_name>
+        <datetime>2014-07-17T09:32:00+02:00</datetime>
+        <actual_value>0.0</actual_value>
     </violation>
 
     Output:
@@ -155,11 +169,13 @@ class ViolationConverter(Converter):
         result = Violation()
         result.uuid = xmlroot.find("uuid").text
         result.contract_uuid = xmlroot.find("contract_uuid").text
+        result.service_name = xmlroot.find("service_name").text
         result.service_scope = xmlroot.find("service_scope").text
         result.metric_name = xmlroot.find("metric_name").text
         result.actual_value = xmlroot.find("actual_value").text
         dt_str = xmlroot.find("datetime").text
         result.datetime = dateutil.parser.parse(dt_str)
+
         return result
 
 
@@ -168,10 +184,9 @@ class AgreementConverter(Converter):
         """Converter for an ws-agreement agreement or template.
         """
         super(AgreementConverter, self).__init__()
-        self._namespaces = { 
+        self._namespaces = {
             "wsag": "http://www.ggf.org/namespaces/ws-agreement",
             "sla": "http://sla.atos.eu",
-            "xifi": "http://sla.xifi.eu"
         }
         self.agreement_tags = (
             "{{{}}}Agreement".format(self._namespaces["wsag"]),
@@ -185,12 +200,17 @@ class AgreementConverter(Converter):
         :param Element xmlroot: root element of xml to convert.
         :rtype: wsag_model.Agreement
         """
+        for name, value in xmlroot.attrib.items():
+            print '{0}="{1}"'.format(name, value)
+
         if xmlroot.tag in self.agreement_tags:
             result = Agreement()
-            result.agreement_id = xmlroot.attrib["AgreementId"]
+            agreementId = str(QName(self._namespaces["wsag"], "AgreementId"))
+            result.agreement_id = xmlroot.attrib[agreementId]
         elif xmlroot.tag in self.template_tags:
             result = Template()
-            result.template_id = xmlroot.attrib["TemplateId"]
+            templateId = str(QName(self._namespaces["wsag"], "TemplateId"))
+            result.template_id = xmlroot.attrib[templateId]
         else:
             raise ValueError("Not valid root element name: " + xmlroot.tag)
 
@@ -298,7 +318,6 @@ class AgreementConverter(Converter):
         return name, result
 
     def _parse_guarantees(self, elements):
-
         result = {}
         for element in elements:
             key, value = self._parse_guarantee(element)
@@ -341,7 +360,7 @@ def _get_attribute(element, attrname):
     isns = (attrname[0] == '{')
 
     #
-    # Handle qnamed request: 
+    # Handle qnamed request:
     #   attrname = {uri}name
     #
     if isns:
index 1965540..fea71f2 100755 (executable)
@@ -20,6 +20,12 @@ from django.http import HttpResponse
 
 import json
 import traceback
+import re
+from math import ceil
+from datetime import datetime
+from dateutil.relativedelta import relativedelta
+from dateutil.tz import tzlocal
+from django.conf import settings
 
 
 class Rol:
@@ -93,29 +99,56 @@ class SLAView (FreeAccessView, ThemeView):
         agreement_id = None
         enforcements = {}
         violations = {}
+        keys = ['provider','agreement','date','status','result','ok']
+        ag_info = []
 
         filter_ = None
         form = FilterForm(request.GET)
         if form.is_valid():
-             print "IS VALID"
-             filter_ = _get_filter_from_form(form)
+            filter_ = _get_filter_from_form(form)
 
         consumer_id = _get_consumer_id(request)
-        
-        agreements = _get_agreements(agreement_id, consumer_id=consumer_id, filter_=filter_)
-        
+
+        #agreements = _get_agreements(agreement_id, consumer_id=consumer_id, filter_=filter_)
+        agreements = _get_agreements(agreement_id, slice=slicename)
+
         for agreement in agreements:
-            enf = _get_enforcement(agreement.agreement_id)
+            row = []
+            provider = agreement.context.provider
+            row.append(provider) # Provider
+            row.append(agreement) # Agreement
+            row.append(agreement.context.time_formatted()) # Date
+
+            enf = _get_enforcement(agreement.agreement_id, provider)
+
             if enf.enabled == 'true':
-                enforcements[agreement.agreement_id] = "ACTIVE"
-            else:
-                enforcements[agreement.agreement_id] = "UNACTIVE"
-            violations_list = _get_agreement_violations(agreement.agreement_id, "GT_Performance")
-            
-            if len(violations_list):
-                violations[agreement.agreement_id] = float(violations_list[0]["actualValue"])*100
+                row.append('Evaluating') # Status
+                row.append('') # Result
+                row('') # Ok
             else:
-                violations[agreement.agreement_id] = 100
+                if agreement.guaranteestatus == "NON_DETERMINED":
+                    row.append('Provisioned') # Status
+                    row.append('') # Result
+                    row.append('') # Ok
+                
+                else:
+                    row.append('Finished') # Status
+
+                    violations_list = _get_agreement_violations(agreement.agreement_id, provider, "GT_Performance")
+                    
+                    if len(violations_list) > 0:
+                        value = '%.2f'%float(violations_list[0].actual_value)
+                        row.append('%d'%(float(value)*100)) # Result
+                    else:
+                        row.append('100') # Result
+
+                    if agreement.guaranteestatus == "VIOLATED":
+                        row.append('false') # Ok
+
+                    if agreement.guaranteestatus == "FULFILLED":
+                        row.append('true') # Ok
+
+            ag_info.append(dict(zip(keys,row)))
 
         template_env = {}
        # write something of our own instead
@@ -126,13 +159,15 @@ class SLAView (FreeAccessView, ThemeView):
         template_env['slicename'] = slicename
         template_env['enforcements'] = enforcements
         template_env['last_violation_list'] = violations
-       
+        template_env['ag_info'] = ag_info
+
+
        # the prelude object in page contains a summary of the requirements() for all plugins
        # define {js,css}_{files,chunks}
         prelude_env = page.prelude_env()
         template_env.update(prelude_env)
-        
-        return render_to_response (self.template_name, template_env, context_instance=RequestContext(request))
+
+        return render_to_response(self.template_name, template_env, context_instance=RequestContext(request))
 
 
 class AgreementsFilter(object):
@@ -175,8 +210,8 @@ class ContactForm(forms.Form):
     cc_myself = forms.BooleanField(required=False)
 
 
-def _get_agreements_client():
-    return restclient.Factory.agreements()
+def _get_agreements_client(path=""):
+    return restclient.Factory.agreements(path)
 
 
 def _get_violations_client():
@@ -195,10 +230,10 @@ def _get_agreement(agreement_id):
     agreement, response = agreements_client.getbyid(agreement_id)
     return agreement
 
-def _get_enforcement(agreement_id):
+def _get_enforcement(agreement_id, testbed):
 
     enforcements_client = _get_enforcements_client()
-    enforcement, response = enforcements_client.getbyagreement(agreement_id)
+    enforcement, response = enforcements_client.getbyagreement(agreement_id, testbed)
     return enforcement
 
 def _get_filter_from_form(form):
@@ -231,11 +266,7 @@ def agreement_term_violations(request, agreement_id, guarantee_name):
     except EmptyPage:
         # If page is out of range (e.g. 9999), deliver first page.
         violation_page = paginator.page(1)
-    
-    print "\n******************"
-    print violations[-1]
-    print "******************\n"
-
     context = {
         'agreement_id': agreement_id,
         'guarantee_term': agreement.guaranteeterms[guarantee_name],
@@ -274,18 +305,13 @@ def agreement_details(request, agreement_id):
     return render_to_response ('violations_template.html', context, context_instance=RequestContext(request))
     #return render(request, 'agreement_detail.html', context)
 
-
-def _get_agreements_client():
-    return restclient.Factory.agreements()
-
-
 def _get_agreement(agreement_id):
 
     agreements_client = _get_agreements_client()
     agreement, response = agreements_client.getbyid(agreement_id)
     return agreement
 
-def _get_agreements(agreement_id, provider_id=None, consumer_id=None, filter_=None):
+def _get_agreements(agreement_id, slice=None, provider_id=None, consumer_id=None, filter_=None):
 
     agreements_client = _get_agreements_client()
     if agreement_id is None:
@@ -293,6 +319,9 @@ def _get_agreements(agreement_id, provider_id=None, consumer_id=None, filter_=No
             agreements, response = agreements_client.getbyconsumer(consumer_id)
         elif provider_id is not None:
             agreements, response = agreements_client.getbyprovider(provider_id)
+        elif slice is not None:
+            agreements_client = _get_agreements_client("slice")
+            agreements, response = agreements_client.getbyslice(slice)
         else:
             raise ValueError(
                 "Invalid values: consumer_id and provider_id are None")
@@ -303,7 +332,8 @@ def _get_agreements(agreement_id, provider_id=None, consumer_id=None, filter_=No
     annotator = wsag_helper.AgreementAnnotator()
     for agreement in agreements:
         id_ = agreement.agreement_id
-        status = _get_agreement_status(id_)
+        testbed = agreement.context.provider
+        status = _get_agreement_status(id_, testbed)
         annotator.annotate_agreement(agreement, status)
 
     if filter_ is not None:
@@ -320,55 +350,94 @@ def _get_agreements_by_consumer(consumer_id):
     agreements, response = agreements_client.getbyconsumer(consumer_id)
     return agreements
 
-def _get_agreement_status(agreement_id):
+def _get_agreement_status(agreement_id, testbed):
 
     agreements_client = _get_agreements_client()
-    status, response = agreements_client.getstatus(agreement_id)
+    status, response = agreements_client.getstatus(agreement_id, testbed)
     return status
 
-def _get_agreement_violations(agreement_id, term=None):
+def _get_agreement_violations(agreement_id, testbed, term=None):
 
     violations_client = _get_violations_client()
-    violations, response = violations_client.getbyagreement(agreement_id, term)
+    violations, response = violations_client.getbyagreement(agreement_id, testbed, term)
     return violations
 
 
 class AgreementSimple(APIView):
+
+    regex = r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
+
     def build_response(self, code, text):
         response = HttpResponse(text, content_type="text/plain", status=code)
         return response 
 
-    def post( self, request, **kwargs):
+    def post(self, request, **kwargs):
         #import pdb; pdb.set_trace()
         print "------------------------------------------------1"
-        data = {}
-        for key, value in request.DATA.items():
-            new_key = key
-            data[new_key] = value
+        data = request.POST
+
+        url = settings.SLA_MANAGER_URL
+        c = restclient.Client(url)
+        # for key, value in request.DATA.items(): # jgarcia review this
+        #     data[key] = value
         
-        try:
-            template_id = data['template_id']
-        except:
-            return self.build_response(400, 'Invalid template_id')
+        # print "---- DATA: ----"
+        # print "Data type: ", type(data)
+        # for key in data:
+        #     print key, data.getlist(key)
 
         try:
-            user = data['user']
+            # template_id = data['template_id']
+            testbeds = data.getlist("testbeds")
+            user = data["user"]
+            resources = data.getlist("resources")
+            slice_id = data["slice"]
         except:
-            return self.build_response(400, 'Invalid user')
+            print "FAIL!"
+            return self.build_response(400, 'Invalid data')
+
+        selected_resources = {}
+
+        now = datetime.now(tzlocal())
+        expiration_time = now + relativedelta(years=1)
+
+        for testbed in testbeds:
+            selected_resources[testbed] = [r for r in resources if testbed in r]
+            template_id = testbed
+            try:
+                print "Calling createagreementsimplified with template_id:",template_id,"and user:",user
+                result = fed4fireservice.createagreementsimplified(
+                            template_id, user, expiration_time, selected_resources)
+                print result
+            except Exception, e:
+                print traceback.format_exc()
+                print '%s (%s)' % (e, type(e))
+                return self.build_response(400, 'Problem creating agreement')
+
+            agreement_id = re.compile(self.regex).search(result.text).group(0)
+         
+            data = '{{ "id": "{}", \
+                      "slice": "{}", \
+                      "testbed": "{}" }}'.format(agreement_id, slice_id, testbed)
+
+            c.post(
+                "sliver",
+                data,
+                headers = {
+                    "content-type": "application/json",
+                    "accept": "application/xml"
+                }
+            )   
 
-        try:
-            expiration_time = data['expiration_time']
-        except:
-            return self.build_response(400, 'Invalid expiration_time')
+        return self.build_response(200, result)            
 
-        try:
-            print "Calling createagreementsimplified with template_id:",template_id,"and user:",user
-            result = fed4fireservice.createagreementsimplified(template_id, user, expiration_time)
-            print result
-        except Exception, e:
-            print traceback.format_exc()
-            print '%s (%s)' % (e, type(e))
-            
-            return self.build_response(400, 'Problem creating agreement')
+class Testbeds(APIView):
+    def get(self, request, **kwargs):
+        c = restclient.Client("http://157.193.215.125:4001/sla-collector")
+        #url = settings.SLA_MANAGER_URL.replace("/sla","")
+        #c = restclient.Client(url)
+        print "**** URL ******", url
+        SLAtestbeds = c.get("testbeds")
+        # Future work: get SLA description for each testbed
 
-        return self.build_response(200, result)            
+        return HttpResponse(SLAtestbeds.text, content_type="application/json", status=SLAtestbeds.status_code)
diff --git a/sla/static/images/sort_asc.png b/sla/static/images/sort_asc.png
new file mode 100644 (file)
index 0000000..a88d797
Binary files /dev/null and b/sla/static/images/sort_asc.png differ
diff --git a/sla/static/images/sort_both.png b/sla/static/images/sort_both.png
new file mode 100644 (file)
index 0000000..8222cdb
Binary files /dev/null and b/sla/static/images/sort_both.png differ
diff --git a/sla/static/images/sort_desc.png b/sla/static/images/sort_desc.png
new file mode 100644 (file)
index 0000000..def071e
Binary files /dev/null and b/sla/static/images/sort_desc.png differ
index f09aa8d..725d7d9 100755 (executable)
@@ -3,32 +3,13 @@
 </div>
 
  <div class="col-md-9">
-   <div class="row" id="agreements">
-    <table class="table dataTable" id="sla_table" >
-        <thead>
-        <tr class="header">
-            <th colspan="2">Provider</th>
-            <!-- <th>Testbed</th>
-            <th>Slice_Id</th>
-            <th>Agreement</th>
-            <th>Metric</th>
-            <th>Violations</th>
-            <th>Result</th> -->
-        </tr>
-        </thead>
-        <tbody>
+   <div class="row" id="agreements" style="padding-top:1em;">
+    
         
-       <tr class="header">
-                       <td><span class="glyphicon glyphicon-chevron-down"></span></td>
-                       <td>iMinds</td>
-       </tr>
-       
-       
-        {% for a in agreements %}
-
+{% for row in ag_info %}
 
 <!-- Modal - columns selector -->
-<div class="modal fade" id="agreementModal{{a.agreement_id}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+<div class="modal fade" id="agreementModal{{row.agreement.agreement_id}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
                        
 <style type="text/css" scoped>
         .modal-lg {
                        </div>
                        <div class="modal-body">
 
-                 <dt>Agreement Id</dt>
-                 <dd>{{ a.agreement_id|default:"&nbsp;" }}</dd>
-                 <dt>Provider</dt>
-                 <dd>{{ a.context.provider|default:"&nbsp;" }}</dd>
-                 <dt>Experimenter</dt>
-                 <dd>{{ a.context.consumer|default:"&nbsp;" }}</dd>
-                 <dt>Service</dt>
-                 <dd>Testbed guarantees 0.99 Uptime rate for 0.99 rate of the resources during the sliver lifetime</dd>
-                 <dt>Testbed</dt>
-                 <dd>{{ a.context.testbed_formatted }}</dd>
-                 <dt>Accepted on:</dt>
-                 <dd>{{ a.context.time_formatted|default:"&nbsp;" }}</dd>
+                <dt>Agreement Id</dt>
+                <dd>{{ row.agreement.agreement_id|default:"&nbsp;" }}</dd>
+                <dt>Provider</dt>
+                <dd>{{ row.provider|default:"&nbsp;" }}</dd>
+                <dt>Experimenter</dt>
+                <dd>{{ row.agreement.context.consumer|default:"&nbsp;" }}</dd>
+                <dt>Service</dt>
+                <dd>Testbed guarantees 0.99 Uptime rate for 0.99 rate of the resources during the sliver lifetime</dd>
+                <dt>Testbed</dt>
+                <dd>{{ row.agreement.context.testbed_formatted }}</dd>
+                <dt>Expiration date:</dt>
+                <dd>{{ row.date|default:"&nbsp;" }}</dd>
                        </div>
                        <div class="modal-footer">
                                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                </div>
        </div>
 </div>
-       
-       <tr>
-                       {% if a.guaranteestatus == "VIOLATED" %}
-                       <td class="glyphicon glyphicon-remove-sign" style="color:red;"></td>
-               {% elif a.guaranteestatus == "FULFILLED" %}
-               <td class="glyphicon glyphicon-ok-sign" style="color:green;"></td>
+
+{% endfor %}
+
+      <table class="table table-striped table-bordered" id="sla_table">
+      
+        <thead>
+          <tr> 
+            <th>Provider</th>
+            <th>Agreement</th>
+            <th>Date</th>
+            <th>Status</th>
+            <th>Result</th>
+          </tr>
+        </thead>
+
+        <tbody>
+        {% for row in ag_info %}
+
+        <tr>
+               
+          <td>{{ row.provider }}</td>
+
+          <td><a class="agreement-detail" data-toggle="modal" data-target="#agreementModal{{row.agreement.agreement_id}}">{{ row.agreement.context.template_id }}</a></td>
+                 
+          <td>{{ row.date }}</td>
+          <td>{{ row.status }}</td>
+          {% if row.ok == "true" %}
+          <td class="success">99% uptime for {{ row.result }}% resources</td>
+          {% elif row.ok == "false" %}
+          <td class="danger">99% uptime for {{ row.result }}% resources</td>
           {% else %}
           <td></td>
-               {% endif %}
-                 <td>{{ a.context.template_id }}</td>
-          <td>{{ a.context.time_formatted }}</td>
-          
-          {% with a.agreement_id as key %}
-          
-          <td>
-              <!-- <a class="agreement-detail" href="{% url "agreement_details" a.agreement_id %}" data-toggle="modal" data-target="#agreementModal">View Agreement</a> -->
-              <!-- <a class="agreement-detail" href="#" data-agreement="{{ a.agreement_id }}">View Agreement</a> -->
-              <a class="agreement-detail" data-toggle="modal" data-target="#agreementModal{{a.agreement_id}}">View Agreement</a>
-          </td>
-
-          {% for k,v in enforcements.items %}
-            {% if key == k %}
-              <td>
-              {% if v == "ACTIVE" %}
-                In progress
-              {% elif v == "UNACTIVE" %}
-                Disabled
-              {% endif %}
-              </td>
-
-              {% if a.guaranteestatus == "VIOLATED" and v == "UNACTIVE" %}
-              <td style="font-weight: bold">
-                Result: 99% uptime for
-                {% for vi, value in last_violation_list.items %}
-                  {% if a.agreement_id == vi %}
-                      {{ value }}%
-                  {% endif %}
-                {% endfor %}
-                resources
-              </td>
-              {% elif a.guaranteestatus == "FULFILLED" and v == "UNACTIVE" %}
-              <td style="font-weight: bold">
-                Result: 99% uptime for
-                {% for vi, value in last_violation_list.items %}
-                  {% if a.agreement_id == vi %}
-                      {{ value }}%
-                  {% endif %}
-                {% endfor %}
-                resources
-              </td>
-              {% endif %}
-            {% endif %}
-
-          {% endfor %}
-          
-          <!-- <td>{{slicename}}</td> -->
-
-          
+          {% endif %}
+          <!-- {% if row.ok == "false" %}
+          <td class="glyphicon glyphicon-remove-sign" style="color:red;"></td>
+          {% elif row.ok == "true" %}
+          <td class="glyphicon glyphicon-ok-sign" style="color:green;"></td>
+          {% else %}
+          <td></td>
+          {% endif %} -->
 
           
-              
-
-            {% endwith %}
-            <!-- {% for tname,t in a.guaranteeterms.items %}
-            <td> {{ t.servicelevelobjective.kpiname }}</td>
-            <td>
-                {% if t.status == "VIOLATED" %}
-
-                  <a class="violation-detail" href="{% url "agreement_term_violations" a.agreement_id t.name %}" data-toggle="modal" data-target="#violationModal">View Violations</a>
-                  <a class="violation-detail" href="#"
-                                       data-agreement="{{ a.agreement_id }}" 
-                                       data-violation="{{ t.name }}">View Violations</a>
-                  <a class="violation-detail" href="#" data-agreement="{{ a.agreement_id }}" data-violation="{{ t.name }}">{{last_violation_list}}</a>
-                  {{ t.name }}
-
-                {% endif %}
-            </td>
-            <td id="status" style="display:none;">
-                {{ a.statusclass }}
-            </td>
-            {% endfor %} -->
-
-
-            
         </tr>
         
-        
         {% endfor %}
         </tbody>
 
 
 <script>
 $(document).ready(function() {
+
+  $('#sla_table').dataTable({
+        "aoColumns": [
+            null,
+            null,
+            null,
+            null,
+            { "orderSequence": [ "desc", "asc" ] }
+        ]
+    });
+
        $('a.violation-detail').click(function () {
                var a = $(this).data('agreement');
                var v = $(this).data('violation');
index 5bc087c..e385baf 100755 (executable)
@@ -3,10 +3,10 @@ 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'^(?P<slicename>[^/]+)/?$', slicetabsla.SLAView.as_view(), name="agreements_summary"),
-    url(r'^agreements/(?P<agreement_id>[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<agreement_id>[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/guarantees/(?P<guarantee_name>\w+)/violations$', slicetabsla.agreement_term_violations, name='agreement_term_violations'),
-    url(r'^agreements/simplecreate/?$', slicetabsla.AgreementSimple.as_view(), name="agreementsimple"),
-)
-
+       url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
+       url(r'^testbeds/', slicetabsla.Testbeds.as_view(), name="testbeds"),
+       url(r'^(?P<slicename>[^/]+)/?$', slicetabsla.SLAView.as_view(), name="agreements_summary"),
+       url(r'^agreements/(?P<agreement_id>[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<agreement_id>[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/guarantees/(?P<guarantee_name>\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