From: Loic Baron Date: Mon, 23 Nov 2015 16:15:11 +0000 (+0100) Subject: Merge branch 'onelab' of ssh://git.onelab.eu/git/myslice into onelab X-Git-Url: http://git.onelab.eu/?p=myslice.git;a=commitdiff_plain;h=12a2d143c35a8365d55bf4bc56443d401e511ac7;hp=6e280cdab22606a8b5e646a37d18fb993fbed0d8 Merge branch 'onelab' of ssh://git.onelab.eu/git/myslice into onelab --- diff --git a/manifoldapi/static/js/manifold.js b/manifoldapi/static/js/manifold.js index f8d299a1..5b5e6afb 100644 --- a/manifoldapi/static/js/manifold.js +++ b/manifoldapi/static/js/manifold.js @@ -1703,6 +1703,8 @@ case TYPE_LIST_OF_VALUES: query = query_ext.query; + var testbeds_with_sla = localStorage.getItem("sla_testbeds").split(","); + switch(query.object) { case 'resource': @@ -1748,9 +1750,9 @@ case TYPE_LIST_OF_VALUES: } } - /*var urn_regexp = /\+(.*?)\+/; + var urn_regexp = /\+(.*?)\+/; var testbed_urn = urn_regexp.exec(record.urn)[1]; - var has_sla = $.inArray(testbed_urn, localStorage.getItem("sla_testbeds").split(",")) != -1; + var has_sla = $.inArray(testbed_urn, testbeds_with_sla) != -1; if (has_sla) { // var warnings = manifold.query_store.get_record_state(query.query_uuid, record_key, STATE_WARNINGS); @@ -1761,7 +1763,7 @@ case TYPE_LIST_OF_VALUES: } else { delete warnings[CONSTRAINT_SLA]; } - }*/ + } manifold.query_store.set_record_state(query.query_uuid, record_key, STATE_WARNINGS, warnings); // Signal the change to plugins (even if the constraint does not apply, so that the plugin can display a checkmark) diff --git a/myslice/urls.py b/myslice/urls.py index 61f779f3..b2e88bb6 100644 --- a/myslice/urls.py +++ b/myslice/urls.py @@ -46,6 +46,7 @@ import portal.sliceresourceview import portal.resources import portal.slicetabexperiment +import portal.slicetabcloud import portal.slicetabinfo import portal.slicetabtestbeds import portal.slicetabusers @@ -116,6 +117,7 @@ urls = [ (r'^testbeds/(?P[^/]+)/?$', portal.slicetabtestbeds.SliceTabTestbeds.as_view()), (r'^measurements/(?P[^/]+)/?$', portal.slicetabmeasurements.SliceTabMeasurements.as_view()), (r'^experiment/(?P[^/]+)/?$', portal.slicetabexperiment.ExperimentView.as_view()), + (r'^cloud/(?P[^/]+)/?$', portal.slicetabcloud.CloudView.as_view()), url(r'^about/?$', portal.about.AboutView.as_view(), name='about'), diff --git a/plugins/sladialog/static/js/sladialog.js b/plugins/sladialog/static/js/sladialog.js index 2773df09..01eb0afd 100644 --- a/plugins/sladialog/static/js/sladialog.js +++ b/plugins/sladialog/static/js/sladialog.js @@ -1,13 +1,10 @@ /** - * MyPlugin: demonstration plugin - * Version: 0.1 - * Description: Template for writing new plugins and illustrating the different - * possibilities of the plugin API. - * This file is part of the Manifold project + * SlaDialog + * Description: Plugin to allow SLA acceptance and creation to MySlice portal + * in Fed4FIRE * Requires: js/plugin.js - * URL: http://www.myslice.info - * Author: Jordan Augé - * Copyright: Copyright 2012-2013 UPMC Sorbonne Universités + * Author: Javier García Lloreda + * Copyright: Copyright Atos Spain S.A. * License: GPLv3 */ @@ -18,17 +15,8 @@ accepted_slas: {}, queries: [], - /** XXX to check - * @brief Plugin constructor - * @param options : an associative array of setting values - * @param element : - * @return : a jQuery collection of objects on which the plugin is - * applied, which allows to maintain chainability of calls - */ init: function(options, element) { - // for debugging tools - this.classname="SlaDialog"; - // Call the parent constructor, see FAQ when forgotten + this.classname = "SlaDialog"; this._super(options, element); /* Member variables */ @@ -36,22 +24,18 @@ /* Plugin events */ /* Setup query and record handlers */ - - // Explain this will allow query events to be handled - // What happens when we don't define some events ? - // Some can be less efficient this.listen_query(options.query_uuid); /* GUI setup and event binding */ - // call function - this.button_binding(); - // Get testbeds with sla and store them in localStorage - //this.get_testbeds_with_sla(); + this.get_testbeds_with_sla(); + // call function + //this.button_binding(); }, get_testbeds_with_sla: function () { + var self = this; return $.get('/sla/testbeds/', function(data) { if (typeof(Storage) !== "undefined") { if (!localStorage.getItem("sla_testbeds")) { @@ -59,24 +43,47 @@ localStorage.setItem("sla_testbeds", testbeds); } } + }).done(function(data) { + self.get_sla_templates(data); }); }, - find_row: function(key) - { - // key in third position, column id = 2 - var KEY_POS = 2; - - var cols = $.grep(this.table.fnSettings().aoData, function(col) { - return (col._aData[KEY_POS] == key); - } ); - - if (cols.length == 0) - return null; - if (cols.length > 1) - throw "Too many same-key rows in ResourceSelected plugin"; + get_sla_templates: function (testbeds) { + var self = this; - return cols[0]; + testbeds.forEach(function(testbed, index, array) { + + if(testbed=="omf:netmode") { // TODO: Remove + + $.ajax('/sla/agreements/templates/' + testbed) + .always(function(data) { + $(".modal-body #sla_template").html(data.responseText.replace(/<|>/g, "")); + + var content = + ""; + + $("#sla_offers").append(content); + + self.button_binding(); + }); + } + }); }, check_template_status: function() { @@ -88,8 +95,6 @@ }, /* PLUGIN EVENTS */ - // on_show like in querytable - /* GUI EVENTS */ @@ -107,7 +112,16 @@ if (is_ok) { // remove warnings - // var warnings = manifold.query_store.get_record_state(resource_query.query_uuid, resource_key, STATE_WARNINGS); + $('#' + id).data("urns").forEach(function (urn, index, array) { + data = { + state: STATE_SET, + key : "resource", + op : STATE_SET_REMOVE, + value: urn + } + + manifold.raise_event(self.query_uuid, STATUS_REMOVE_WARNING, data); + }); } }); @@ -131,7 +145,7 @@ var data = { "SLIVER_INFO_AGGREGATE_URN": record.resource[0].component_manager_id, - "SLIVER_INFO_EXPIRATION": record.lease[0].end_time, // FIXME: only working with leases + "SLIVER_INFO_EXPIRATION": record.lease[0].end_time, // FIXME: only working with leases "SLIVER_INFO_SLICE_URN": record.slice_urn, "SLIVER_INFO_CREATOR_URN": record.users[0], "SLIVER_INFO_URN": urns, @@ -155,43 +169,6 @@ // }); }, - // a function to bind events here: click change - // how to raise manifold events - set_state: function(data, username) - { - - }, - - post_agreement: function() - { - console.log(this.options.user); - }, - - /* GUI MANIPULATION */ - - // We advise you to write function to change behaviour of the GUI - // Will use naming helpers to access content _inside_ the plugin - // always refer to these functions in the remaining of the code - - show_hide_button: function() - { - // this.id, this.el, this.cl, this.elts - // same output as a jquery selector with some guarantees - }, - - /* TEMPLATES */ - - // see in the html template - // How to load a template, use of mustache - - /* QUERY HANDLERS */ - - // How to make sure the plugin is not desynchronized - // He should manifest its interest in filters, fields or records - // functions triggered only if the proper listen is done - - // no prefix - on_filter_added: function(filter) { @@ -200,6 +177,10 @@ on_field_state_changed: function(data) { var self = this; + self.query_uuid = self.options.query_uuid; + + var testbeds = localStorage.getItem("sla_testbeds").split(","); + var urn_regexp = /\+(.*?)\+/; // this.set_state(result, this.options.username); switch(data.state) { @@ -208,48 +189,40 @@ case STATE_SET_IN_PENDING: if (typeof(data.value) == 'string') { // data.value = urn - this._supports_sla(data.value) - .done( function(testbeds) { - var urn_regexp = /\+(.*?)\+/; - var urn = urn_regexp.exec(data.value)[1]; - var pos = $.inArray(urn, testbeds); - if ( pos != -1) { - var id_ref = testbeds[pos].replace(/\.|:/g, "-"); - $("#" + id_ref).data("urns").push(data.value); - $("#" + id_ref).show(); - self.accepted_slas[id_ref] = false; - //$( "#sla_offers_list" ).append( - // $("
  • ").text("Testbed " + testbeds[pos] + " offers SLA for its resources") - //); - } - }); + var urn = urn_regexp.exec(data.value)[1]; + var pos = $.inArray(urn, testbeds); + if ( pos != -1) { + var id_ref = testbeds[pos].replace(/\.|:/g, "-"); + $("#" + id_ref).data("urns").push(data.value); + $("#" + id_ref).show(); + self.accepted_slas[id_ref] = false; + //$( "#sla_offers_list" ).append( + // $("
  • ").text("Testbed " + testbeds[pos] + " offers SLA for its resources") + //); + } } break; case STATE_SET_OUT: // data.value = urn if (typeof(data.value) == 'string') { // data.value = urn - this._supports_sla(data.value) - .done( function(testbeds) { - var urn_regexp = /\+(.*?)\+/; - var urn = urn_regexp.exec(data.value)[1]; - var pos = $.inArray(urn, testbeds); - if ( pos != -1) { - var id_ref = testbeds[pos].replace(/\.|:/g, "-"); - var array = $("#" + id_ref).data("urns"); - array.splice(array.indexOf(data.value), 1); - - if ($("#" + id_ref).data("urns").length == 0) { - $("#" + id_ref).hide(); - delete self.accepted_slas[id_ref]; - $(".sla-accept-button").button("reset"); - $(".sla-accept-button").prop("disabled", false); - } - //$( "#sla_offers_list" ).append( - // $("
  • ").text("Testbed " + testbeds[pos] + " offers SLA for its resources") - //); - } - }); + var urn = urn_regexp.exec(data.value)[1]; + var pos = $.inArray(urn, testbeds); + if ( pos != -1) { + var id_ref = testbeds[pos].replace(/\.|:/g, "-"); + var array = $("#" + id_ref).data("urns"); + array.splice(array.indexOf(data.value), 1); + + if ($("#" + id_ref).data("urns").length == 0) { + $("#" + id_ref).hide(); + delete self.accepted_slas[id_ref]; + $(".sla-accept-button").button("reset"); + $(".sla-accept-button").prop("disabled", false); + } + //$( "#sla_offers_list" ).append( + // $("
  • ").text("Testbed " + testbeds[pos] + " offers SLA for its resources") + //); + } } break; } @@ -264,8 +237,6 @@ } }, - // ... be sure to list all events here - /* RECORD HANDLERS */ on_all_new_record: function(record) { @@ -278,16 +249,11 @@ }, /* INTERNAL FUNCTIONS */ - _dummy: function() { - // only convention, not strictly enforced at the moment - }, _supports_sla: function(resource_urn) { return $.ajax("/sla/testbeds/"); }, - - _getUUID: function() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8); @@ -300,6 +266,4 @@ /* Plugin registration */ $.plugin('SlaDialog', SlaDialog); - // TODO Here use cases for instanciating plugins in different ways like in the pastie. - })(jQuery); diff --git a/plugins/sladialog/templates/sladialog.html b/plugins/sladialog/templates/sladialog.html index b1a9ab25..8886ae38 100644 --- a/plugins/sladialog/templates/sladialog.html +++ b/plugins/sladialog/templates/sladialog.html @@ -8,7 +8,7 @@ -
    - - - - -
    +
    \ No newline at end of file diff --git a/portal/projectrequestview.py b/portal/projectrequestview.py index 1f6e921b..2757b94a 100644 --- a/portal/projectrequestview.py +++ b/portal/projectrequestview.py @@ -106,6 +106,7 @@ class ProjectRequestView(LoginRequiredAutoLogoutView, ThemeView): 'authority_hrn' : wsgi_request.POST.get('authority_name', ''), 'project_name' : project_name, 'purpose' : wsgi_request.POST.get('purpose', ''), + 'url' : wsgi_request.POST.get('url', ''), } # for new projects max project_name length is 10 diff --git a/portal/slicerequestview.py b/portal/slicerequestview.py index a2b0dd04..9ccaf763 100644 --- a/portal/slicerequestview.py +++ b/portal/slicerequestview.py @@ -39,8 +39,8 @@ class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView): errors = [] slice_name ='' - purpose='' - url='' + #purpose='' + #url='' authority_hrn = None authority_name = None # Retrieve the list of authorities @@ -138,8 +138,8 @@ class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView): 'authority_hrn' : authority_hrn, 'organization' : request.POST.get('org_name', ''), 'slice_name' : slice_name, - 'url' : request.POST.get('url', ''), - 'purpose' : request.POST.get('purpose', ''), + #'url' : request.POST.get('url', ''), + #'purpose' : request.POST.get('purpose', ''), 'current_site' : current_site } @@ -174,11 +174,11 @@ class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView): - purpose = slice_request['purpose'] - if purpose is None or purpose == '': - errors.append('Experiment purpose is mandatory') + # purpose = slice_request['purpose'] + # if purpose is None or purpose == '': + # errors.append('Experiment purpose is mandatory') - url = slice_request['url'] + #url = slice_request['url'] if not errors: if is_pi(request, user_hrn, authority_hrn): @@ -203,10 +203,10 @@ class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView): 'topmenu_items': topmenu_items_live('Request a slice', page), 'errors': errors, 'slice_name': slice_name, - 'purpose': purpose, + #'purpose': purpose, 'email': user_email, 'user_hrn': user_hrn, - 'url': url, + #'url': url, 'pi': pi, 'authority_name': authority_name, 'authority_hrn': user_authority, diff --git a/portal/slicetabcloud.py b/portal/slicetabcloud.py new file mode 100644 index 00000000..ce1dc31d --- /dev/null +++ b/portal/slicetabcloud.py @@ -0,0 +1,86 @@ +# this somehow is not used anymore - should it not be ? +from django.core.context_processors import csrf +from django.http import HttpResponseRedirect +from django.contrib.auth import authenticate, login, logout +from django.template import RequestContext +from django.shortcuts import render_to_response +from django.shortcuts import render + +from unfold.loginrequired import LoginRequiredView + +from manifold.core.query import Query +from manifoldapi.manifoldapi import execute_query +from manifoldapi.manifoldresult import ManifoldResult +from ui.topmenu import topmenu_items, the_user +from myslice.configengine import ConfigEngine + +from myslice.theme import ThemeView +from myslice.configengine import ConfigEngine +from myslice.settings import logger + +from sfa.planetlab.plxrn import hash_loginbase + +import urllib2,json + +class CloudView (LoginRequiredView, ThemeView): + # parent View is portal/sliceview.py + + def get_platforms (self, request): + username = self.request.user + + pf_query = Query().get('local:platform').filter_by('disabled', '==', '0').filter_by('gateway_type', '==', 'sfa').select('platform') + res_platforms = execute_query(request, pf_query) + platforms = [p['platform'] for p in res_platforms] + return platforms + + + template_name = 'slice-tab-cloud.html' + def post (self, request, slicename): + logger.debug("---------------- POST CloudView ------------------") + logger.debug(request.POST) + + username = self.request.user + platforms = self.get_platforms(request) + cloud_platforms = ["onelab-cloud"] + len_platforms = len(platforms) + + #if 'action' in request.POST: + # if request.POST['action'] == 'add': + + # elif request.POST['action'] == 'delete': + # for key,val in request.POST: + # if key.endswith('_vm'): + # request.POST['platform'] + # + # elif request.POST['action'] == 'reserve': + # + # else: + # log.error("action %s not supported" % request.POST['action']) + + env = { 'theme' : self.theme, + 'slicename':slicename, + 'platforms':platforms, + 'cloud_platforms':cloud_platforms, + 'len_platforms': len_platforms, + 'post_values': request.POST, + 'request':self.request, + } + return render_to_response(self.template, env, context_instance=RequestContext(request)) + + + def get (self, request, slicename, state=None): + + username = self.request.user + platforms = self.get_platforms(request) + cloud_platforms = ["onelab-cloud"] + len_platforms = len(platforms) + + env = { 'theme' : self.theme, + 'slicename':slicename, + 'platforms':platforms, + 'cloud_platforms':cloud_platforms, + 'len_platforms': len_platforms, + 'request':self.request, + } + return render_to_response(self.template, env, context_instance=RequestContext(request)) + diff --git a/portal/templates/projectrequest_view.html b/portal/templates/projectrequest_view.html index 85582280..aabda751 100644 --- a/portal/templates/projectrequest_view.html +++ b/portal/templates/projectrequest_view.html @@ -73,7 +73,13 @@ {% endif %} - +
    + + +
    diff --git a/portal/templates/slice-tab-cloud.html b/portal/templates/slice-tab-cloud.html new file mode 100644 index 00000000..436af696 --- /dev/null +++ b/portal/templates/slice-tab-cloud.html @@ -0,0 +1,484 @@ +{% extends "layout_wide.html" %} + +{% block head %} + + +{% endblock %} + +{% block content %} +{{post_values}} +{% for platform in platforms %} + {% if platform in cloud_platforms %} + +
    +

    {{ platform }}

    + // display only if VMs already in slice +

    VMs in slice {{slicename}}

    +
    + {% csrf_token %} + +
    +

    Create new VMs

    + +
    + +
    + {% endif %} +{% endfor %} +{% endblock %} diff --git a/portal/templates/slice-tab-info.html b/portal/templates/slice-tab-info.html index 7dfddc97..96e9fc85 100644 --- a/portal/templates/slice-tab-info.html +++ b/portal/templates/slice-tab-info.html @@ -79,7 +79,9 @@ + diff --git a/portal/templates/slicerequest_view.html b/portal/templates/slicerequest_view.html index 07a45971..fbbd2b11 100644 --- a/portal/templates/slicerequest_view.html +++ b/portal/templates/slicerequest_view.html @@ -44,11 +44,12 @@ + diff --git a/rest/sfa_api.py b/rest/sfa_api.py index 6030c6b5..45e30a19 100644 --- a/rest/sfa_api.py +++ b/rest/sfa_api.py @@ -2,36 +2,44 @@ import os import json import ConfigParser import datetime -from time import mktime +from time import mktime +import time import xmltodict -from django.shortcuts import render_to_response -from django.http import HttpResponse +from django.shortcuts import render_to_response +from django.http import HttpResponse,QueryDict -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 sfa.trust.certificate import Keypair, Certificate +from sfa.client.sfaserverproxy import SfaServerProxy +from manifold.gateways.sfa.proxy import SFAProxy +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.core.query import Query -from manifoldapi.manifoldapi import execute_admin_query +from manifoldapi.manifoldapi import execute_admin_query -from unfold.loginrequired import LoginRequiredView +from unfold.loginrequired import LoginRequiredView -from myslice.settings import logger, config +from myslice.settings import logger, config -from rest.json_encoder import MyEncoder +from repoze.lru import lru_cache +from rest.json_encoder import MyEncoder + +import uuid +def unique_call_id(): return uuid.uuid4().urn def dispatch(request, method): - hrn = '' - urn = '' - object_type = '' - rspec = '' + hrn = None + urn = None + object_type = None + rspec = None + output_format = None recursive = False - options = dict() - platforms = list() + # Have to be hashable for lru_cache + options = frozenset() # dict() + platforms = frozenset() # list() results = dict() display = None @@ -41,28 +49,45 @@ def dispatch(request, method): elif request.method == 'GET': req_items = request.GET - for el in req_items.items(): - if el[0].startswith('rspec'): - rspec += el[1] - elif el[0].startswith('platform'): - platforms = req_items.getlist('platform[]') - #elif el[0].startswith('options'): - # options += req_items.getlist('options[]') - elif el[0].startswith('hrn'): - hrn = el[1] - elif el[0].startswith('urn'): - urn = el[1] - elif el[0].startswith('type'): - object_type = el[1] - elif el[0].startswith('recursive'): - if el[1] == '1': + logger.debug("dispatch got = %s" % req_items.dict()) + #t = dict(req_items.iterlists()) + #rspec = req_items.getlist('rspec') + #logger.debug("dispatch got = %s" % t) + + platforms = req_items.getlist('platform[]') + for k in req_items.dict(): + logger.debug("key = %s - value = %s" % (k,req_items.get(k))) + if k == 'rspec': + rspec = req_items.get(k) + if k == 'options': + options = req_items.get(k) + if k == 'output_format': + output_format = req_items.get(k) + if k == 'hrn': + hrn = req_items.get(k) + if k == 'urn': + urn = req_items.get(k) + if k == 'type': + object_type = req_items.get(k) + if k == 'recursive': + if v == '1': recursive = True else: recursive = False - elif el[0].startswith('display'): - display = el[1] + if k == 'display': + display = req_items.get(k) - results = sfa_client(request, method, hrn=hrn, urn=urn, object_type=object_type, recursive=recursive, options=options, platforms=platforms) + if rspec is not None: + try: + rspec = json.loads(rspec) + except Exception,e: + logger.debug("rspec type = %s" % type(rspec)) + if type(rspec) is dict: + rspec = xmltodict.unparse(rspec) + + start_time = time.time() + results = sfa_client(request, method, hrn=hrn, urn=urn, object_type=object_type, rspec=rspec, recursive=recursive, options=options, platforms=platforms, output_format=output_format, admin=False) + logger.debug("EXEC TIME - sfa_client() - %s sec." % (time.time() - start_time)) if display == 'table': return render_to_response('table-default.html', {'data' : data, 'fields' : columns, 'id' : '@component_id', 'options' : None}) else: @@ -90,7 +115,8 @@ def get_user_account(request, user_email, platform_name): return accounts[0] -def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None, recursive=None, options=None, platforms=None, admin=False): +#@lru_cache(100) +def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None, recursive=False, options=None, platforms=None, output_format=None, admin=False): Config = ConfigParser.ConfigParser() monitor_file = os.path.abspath(os.path.dirname(__file__) + '/../myslice/monitor.ini') @@ -112,6 +138,8 @@ def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None object_type = '' if rspec is None: rspec = '' + else: + logger.debug("RSPEC = %s" % rspec) if recursive is None: recursive = False if options is None: @@ -139,22 +167,21 @@ def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None data = [] columns = [] api_options = {} - api_options['geni_rspec_version'] = {'type': 'GENI', 'version': '3'} api_options['list_leases'] = 'all' server_am = False for pf in platforms: platform = get_platform_config(request, pf) - logger.debug("platform={}".format(platform)) + if 'rspec_type' in platform and 'rspec_version' in platform: + api_options['geni_rspec_version'] = {'type': platform['rspec_type'],'version': platform['rspec_version']} + else: + api_options['geni_rspec_version'] = {'type': 'GENI', 'version': '3'} if 'sm' in platform and len(platform['sm']) > 0: - logger.debug('sm') server_am = True server_url = platform['sm'] if 'rm' in platform and len(platform['rm']) > 0: - logger.debug('rm') server_am = False server_url = platform['rm'] if 'registry' in platform and len(platform['registry']) > 0: - logger.debug('registry') server_am = False server_url = platform['registry'] @@ -177,13 +204,31 @@ def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None return {'error' : '-2'} server = SfaServerProxy(server_url, pkey, cert) + #server = SFAProxy(server_url, pkey, cert) + if 'geni_rspec_version' in options: + # GetVersion to know if the AM supports the requested version + # if not ask for the default GENI v3 + start_time = time.time() + result = server.GetVersion() + logger.debug("EXEC TIME - GetVersion() - %s sec." % (time.time() - start_time)) + if 'geni_ad_rspec_versions' in result['value']: + for v in result['value']['geni_ad_rspec_versions']: + if v['type'] == options['geni_rspec_version']: + api_options['geni_rspec_version'] = {'type': options['geni_rspec_version']} + break + else: + api_options['geni_rspec_version'] = {'type': 'GENI', 'version': '3'} + else: + api_options['geni_rspec_version'] = {'type': 'GENI', 'version': '3'} try: # Get user config from Manifold user_config = get_user_config(request, user_email, pf) if 'delegated_user_credential' in user_config: + logger.debug('delegated_user_credential') user_cred = user_config['delegated_user_credential'] elif 'user_credential' in user_config: + logger.debug('user_credential') user_cred = user_config['user_credential'] else: logger.error("no user credentials for user = ", user_email) @@ -191,10 +236,12 @@ def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None if object_type: if 'delegated_%s_credentials'%object_type in user_config: + logger.debug('delegated_%s_credentials'%object_type) for obj_name, cred in user_config['delegated_%s_credentials'%object_type].items(): if obj_name == hrn: object_cred = cred elif '%s_credentials'%object_type in user_config: + logger.debug('%s_credentials'%object_type) for obj_name, cred in user_config['%s_credentials'%object_type].items(): if obj_name == hrn: object_cred = cred @@ -206,13 +253,19 @@ def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None # Both AM & Registry if method == "GetVersion": + start_time = time.time() result = server.GetVersion() + logger.debug("EXEC TIME - GetVersion() - %s sec." % (time.time() - start_time)) else: # AM API Calls if server_am: if method == "ListResources": + logger.debug(api_options) + #logger.debug(user_cred) + start_time = time.time() result = server.ListResources([user_cred], api_options) - logger.debug(result) + logger.debug("EXEC TIME - ListResources() - %s sec." % (time.time() - start_time)) + #logger.debug(result) dict_result = xmltodict.parse(result['value']) result['parsed'] = dict_result if isinstance(dict_result['rspec']['node'], list): @@ -221,7 +274,9 @@ def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None columns.extend(dict_result['rspec']['node'].keys()) elif method == "Describe": + start_time = time.time() version = server.GetVersion() + logger.debug("EXEC TIME - GetVersion() - %s sec." % (time.time() - start_time)) logger.debug(version['geni_api']) # if GetVersion = v2 if version['geni_api'] == 2: @@ -254,24 +309,26 @@ def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None elif method == 'Allocate': api_options['call_id'] = unique_call_id() # List of users comes from the Registry - api_options['sfa_users'] = sfa_users - api_options['geni_users'] = geni_users + users = get_users_in_slice(request, hrn) + api_options['sfa_users'] = users + api_options['geni_users'] = users # if GetVersion = v2 version = server.GetVersion() if version['geni_api'] == 2: result = server.CreateSliver([urn] ,[object_cred], rspec, api_options) # else GetVersion = v3 else: - result = server.Allocate([urn] ,[object_cred], rspec, api_options) + result = server.Allocate(urn ,[object_cred], rspec, api_options) elif method == 'Provision': # if GetVersion = v2 # Nothing it is not supported by v2 AMs version = server.GetVersion() + # List of users comes from the Registry + users = get_users_in_slice(request, hrn) + api_options['sfa_users'] = users + api_options['geni_users'] = users if version['geni_api'] == 3: api_options['call_id'] = unique_call_id() - # List of users comes from the Registry - api_options['sfa_users'] = sfa_users - api_options['geni_users'] = geni_users result = server.Provision([urn] ,[object_cred], api_options) elif method == 'Status': result = server.Status([urn] ,[object_cred], api_options) @@ -322,6 +379,14 @@ def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None #return HttpResponse(json.dumps({'error' : '-3','msg':'method not supported by Registry'}), content_type="application/json") logger.debug('method %s not handled by Registry' % method) result = [] + if output_format is not None: + logger.debug("result = " % result) + if 'value' in result: + # TODO Python Caching + # to avoid translating the same RSpec in the same format several times + start_time = time.time() + result = translate(result['value'],output_format) + logger.debug("EXEC TIME - translate() - %s sec." % (time.time() - start_time)) results[pf] = result if dict_result: @@ -334,11 +399,47 @@ def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None import traceback logger.error(traceback.format_exc()) logger.error(e) - results[pf] = {'error':'-3', 'error_msg': str(e)} + results[pf] = {'error':'-3', 'result':result,'error_msg': str(e)} results['columns'] = columns return results +@lru_cache(100) +def translate(rspec, output_format): + import urllib + import urllib2 + + values = {'content' : rspec} + url = 'https://demo.fiteagle.org/omnweb/convert/to/' + output_format + data = urllib.urlencode(values) + req = urllib2.Request(url, data) + response = urllib2.urlopen(req) + return response.read() + +def rename(self,key,new_key): + ind = self._keys.index(key) #get the index of old key, O(N) operation + self._keys[ind] = new_key #replace old key with new key in self._keys + self[new_key] = self[key] #add the new key, this is added at the end of self._keys + self._keys.pop(-1) #pop the last item in self._keys + +def get_users_in_slice(request, slice_hrn): + # select users.user_hrn, users.user_email, users.keys + # from myslice:slice + # where slice_hrn=='onelab.upmc.r2d2.slice1' + users_query = Query().get('myslice:slice').filter_by('slice_hrn', '==', slice_hrn).select('users.user_hrn', 'users.user_urn', 'users.user_email','users.keys') + users = execute_admin_query(request, users_query) + rmap = {'user_urn':'urn','user_email':'email','user_hrn':'hrn'} + res = list() + for u in users[0]['users']: + r_user = dict() + for k,v in u.items(): + if k in rmap.keys(): + r_user[rmap[k]] = v + else: + r_user[k]=v + res.append(r_user) + return res + def get_user_config(request, user_email, platform_name): account = get_user_account(request, user_email, platform_name) return json.loads(account['config']) if account['config'] else {} diff --git a/sla/slaclient/restclient.py b/sla/slaclient/restclient.py index c3dc0134..0f08a993 100755 --- a/sla/slaclient/restclient.py +++ b/sla/slaclient/restclient.py @@ -166,7 +166,7 @@ class Client(object): kwargs["auth"] = HTTPBasicAuth(settings.SLA_COLLECTOR_USER, settings.SLA_COLLECTOR_PASSWORD) - result = requests.post(url, data, **kwargs) + result = requests.post(url, data, verify=False, **kwargs) location = result.headers["location"] \ if "location" in result.headers else "" print "POST {} {} - Location: {}".format( @@ -343,12 +343,12 @@ class Templates(object): converter = xmlconverter.AgreementConverter() self.res = _Resource(resourceurl, converter) - def getall(self): + def getall(self, provider_id): """ Get all templates :rtype : list[wsag_model.Template] """ - return self.res.getall() + return self.res.get(path="", params={"testbed": provider_id}) def getbyid(self, provider_id): """Get a template diff --git a/sla/slicetabsla.py b/sla/slicetabsla.py index c9043f67..1dbb428a 100755 --- a/sla/slicetabsla.py +++ b/sla/slicetabsla.py @@ -26,62 +26,6 @@ from django.http import HttpResponse from myslice.settings import logger, SLA_COLLECTOR_URL - -# class AgreementsFilter(object): -# def __init__(self, status=None, provider=None, consumer=None): -# self.status = status -# self.provider = provider -# self.consumer = consumer -# -# def __repr__(self): -# return "".format( -# self.status, self.provider, self.consumer -# ) -# -# @staticmethod -# def _check(expectedvalue, actualvalue): -# if expectedvalue is None or expectedvalue == '': -# return True -# else: -# return actualvalue == expectedvalue -# -# def check(self, agreement): -# """Check if this agreement satisfy the filter. -# -# The agreement must be previously annotated -# """ -# guaranteestatus = agreement.guaranteestatus -# provider = agreement.context.provider -# consumer = agreement.context.consumer -# return ( -# AgreementsFilter._check(self.status, guaranteestatus) and -# AgreementsFilter._check(self.provider, provider) and -# AgreementsFilter._check(self.consumer, consumer) -# ) - - -# class FilterForm(forms.Form): -# _attrs = {'class': 'form-control'} -# exclude = () -# status = forms.ChoiceField( -# choices=[ -# ('', 'All'), -# (wsag_model.AgreementStatus.StatusEnum.FULFILLED, 'Fulfilled'), -# (wsag_model.AgreementStatus.StatusEnum.VIOLATED, 'Violated'), -# (wsag_model.AgreementStatus.StatusEnum.NON_DETERMINED, 'Non determined')], -# widget=forms.Select(attrs=_attrs), -# required=False -# ) -# provider = forms.CharField( -# widget=forms.TextInput(attrs=_attrs), -# required=False -# ) -# consumer = forms.CharField( -# widget=forms.TextInput(attrs=_attrs), -# required=False -# ) - - class SLAView(FreeAccessView, ThemeView): template_name = 'slice-tab-sla.html' @@ -89,9 +33,6 @@ class SLAView(FreeAccessView, ThemeView): page = Page(request) - # logger.debug("SLA slice name: {}".format(slicename)) - - # consumer_id = None agreement_id = None enforcements = {} violations = {} @@ -100,14 +41,6 @@ class SLAView(FreeAccessView, ThemeView): 'ok', 'slivers'] ag_info = [] - # filter_ = None - # form = FilterForm(request.GET) - # if form.is_valid(): - # 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_by_slice(slicename) for agreement in agreements: @@ -118,8 +51,6 @@ class SLAView(FreeAccessView, ThemeView): row.append(agreement.context.time_formatted()) # Date enf = _get_enforcement(agreement.agreement_id, provider) - # logger.debug("SLA guarantee status {}: {}".format(agreement.agreement_id, - # agreement.guaranteestatus)) if enf.enabled == 'true': row.append('Evaluating') # Status @@ -178,46 +109,6 @@ class SLAView(FreeAccessView, ThemeView): return render_to_response(self.template_name, template_env, context_instance=RequestContext(request)) -# class AgreementsFilter(object): -# def __init__(self, status=None, provider=None, consumer=None): -# self.status = status -# self.provider = provider -# self.consumer = consumer -# -# def __repr__(self): -# return "".format( -# self.status, self.provider, self.consumer -# ) -# -# @staticmethod -# def _check(expectedvalue, actualvalue): -# if expectedvalue is None or expectedvalue == '': -# return True -# else: -# return actualvalue == expectedvalue -# -# def check(self, agreement): -# """Check if this agreement satisfy the filter. -# -# The agreement must be previously annotated -# """ -# guaranteestatus = agreement.guaranteestatus -# provider = agreement.context.provider -# consumer = agreement.context.consumer -# return ( -# AgreementsFilter._check(self.status, guaranteestatus) and -# AgreementsFilter._check(self.provider, provider) and -# AgreementsFilter._check(self.consumer, consumer) -# ) - - -# class ContactForm(forms.Form): -# subject = forms.CharField(max_length=100) -# message = forms.CharField() -# sender = forms.EmailField() -# cc_myself = forms.BooleanField(required=False) - - def _get_agreements_client(): return restclient.Factory.agreements() @@ -246,13 +137,6 @@ def _get_enforcement(agreement_id, testbed): return enforcement -# def _get_filter_from_form(form): -# -# data = form.cleaned_data -# result = AgreementsFilter( -# data["status"], data["provider"], data["consumer"]) -# return result - def agreement_term_violations(request, agreement_id, guarantee_name): page = Page(request) prelude_env = page.prelude_env() @@ -290,9 +174,6 @@ def agreement_term_violations(request, agreement_id, guarantee_name): return render_to_response('violations_template.html', context, context_instance=RequestContext(request)) -# return render(request, 'violations_template.html', context) - - # TODO Change function to class def agreement_details(request, agreement_id): page = Page(request) @@ -318,38 +199,6 @@ def agreement_details(request, agreement_id): #return render(request, 'agreement_detail.html', context) -# 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: -# if consumer_id is not None: -# 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") -# else: -# agreement, response = agreements_client.getbyid(agreement_id) -# agreements = [agreement] -# -# annotator = wsag_helper.AgreementAnnotator() -# for agreement in agreements: -# id_ = agreement.agreement_id -# testbed = agreement.context.provider -# status = _get_agreement_status(id_, testbed) -# annotator.annotate_agreement(agreement, status) -# -# if filter_ is not None: -# print "FILTERING ", repr(filter_) -# agreements = filter(filter_.check, agreements) -# else: -# print "NOT FILTERING" -# return agreements - def _get_agreements_by_slice(slice): agreements_client = _get_agreements_client() agreements, response = agreements_client.getbyslice(slice) @@ -364,12 +213,6 @@ def _get_agreements_by_slice(slice): return agreements -# def _get_agreements_by_consumer(consumer_id): -# -# agreements_client = _get_agreements_client() -# agreements, response = agreements_client.getbyconsumer(consumer_id) -# return agreements - def _get_agreement_status(agreement_id, testbed): agreements_client = _get_agreements_client() status, response = agreements_client.getstatus(agreement_id, testbed) @@ -394,6 +237,20 @@ class Testbeds(FreeAccessView, ThemeView): return HttpResponse(SLAtestbeds.text, content_type="application/json", status=SLAtestbeds.status_code) +class AgreementTemplates(FreeAccessView, ThemeView): + def get(self, request, *args, **kwargs): + c = restclient.Templates(SLA_COLLECTOR_URL) + testbed = kwargs.get('testbed', None) + + templates, response = c.getall(testbed) + service_level_objectives = [] + + for template in templates: + service_level_objectives.append( + [v.servicelevelobjective for v in template.guaranteeterms.values()]) + + return HttpResponse(service_level_objectives, content_type="application/json", status=response.status_code) + class CreateAgreement(LoginRequiredView, ThemeView): def post(self, request, *args, **kwargs): @@ -414,7 +271,7 @@ class CreateAgreement(LoginRequiredView, ThemeView): dt = datetime.fromtimestamp(float(tstmp)) # gmt_2 = pytz.timezone("Etc/GMT-2") # dlocal = gmt_2.localize(dt).isoformat() - dlocal = dt.isoformat() + "CET" # FIXME: hardcoded for demo purposes + dlocal = dt.isoformat() + "CET" data["SLIVER_INFO_EXPIRATION"] = dlocal # logger.debug("SLA Agreement parameters: {}".format(data.dict())) diff --git a/sla/urls.py b/sla/urls.py index 03ab14f9..87363ee1 100755 --- a/sla/urls.py +++ b/sla/urls.py @@ -13,6 +13,8 @@ urlpatterns = patterns('', slicetabsla.agreement_details, name='agreement_details'), url(r'^agreements/(?P[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/guarantees/(?P\w+)/violations$', slicetabsla.agreement_term_violations, name='agreement_term_violations'), + url(r'^agreements/templates/(?P[^/]+)', + slicetabsla.AgreementTemplates.as_view(), name='agreement_templates'), url(r'^agreements/create/$', slicetabsla.CreateAgreement.as_view(), name="agreement_create"), # url(r'^agreements/simplecreate/?$',