Plugin Cloud wip
authorLoic Baron <loic.baron@lip6.fr>
Wed, 4 Nov 2015 11:30:24 +0000 (12:30 +0100)
committerLoic Baron <loic.baron@lip6.fr>
Wed, 4 Nov 2015 11:30:24 +0000 (12:30 +0100)
myslice/urls.py
portal/slicetabcloud.py [new file with mode: 0644]
portal/templates/slice-tab-cloud.html [new file with mode: 0644]

index 61f779f..b2e88bb 100644 (file)
@@ -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<slicename>[^/]+)/?$', portal.slicetabtestbeds.SliceTabTestbeds.as_view()),
     (r'^measurements/(?P<slicename>[^/]+)/?$', portal.slicetabmeasurements.SliceTabMeasurements.as_view()),
     (r'^experiment/(?P<slicename>[^/]+)/?$', portal.slicetabexperiment.ExperimentView.as_view()),
+    (r'^cloud/(?P<slicename>[^/]+)/?$', portal.slicetabcloud.CloudView.as_view()),
     
     
     url(r'^about/?$', portal.about.AboutView.as_view(), name='about'),
diff --git a/portal/slicetabcloud.py b/portal/slicetabcloud.py
new file mode 100644 (file)
index 0000000..5526a18
--- /dev/null
@@ -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 FreeAccessView
+
+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 (FreeAccessView, 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/slice-tab-cloud.html b/portal/templates/slice-tab-cloud.html
new file mode 100644 (file)
index 0000000..913b6dd
--- /dev/null
@@ -0,0 +1,244 @@
+{% extends "layout_wide.html" %}
+
+{% block head %}
+<script type="text/javascript">
+
+var global_list = {};
+
+/* render_flavor & render_image */
+function render_option(obj){
+    var option = document.createElement("option");
+    option.text = obj["@name"];
+    option.value = obj["@name"];
+    return option;
+}
+function render_description(platform, obj, type){
+    if($('#'+platform+'_'+type).length==0){
+        $('#'+platform+'_add').append("<div id='"+platform+"_"+type+"'>");
+    }
+    var d = platform+'_'+type+'_'+obj['@name'];
+    d = d.replace(/ /g, '');
+    id = d.replace( /(:|\.|\[|\])/g, "\\$1" );
+    if($('#'+id).length==0){
+        $('#'+platform+'_'+type).append("<div id='"+d+"' class='alert-success col-md-5' style='margin-top:10px;display:none;border-style:solid;border-color:white;border-width:2px;'></div>");
+    }
+    if($('#'+id+' div').length==0){
+        jQuery.each(obj, function(key,val){
+            if (key != 'openstack:image'){
+                $('#'+id).append("<div>"+key.replace('@','')+": "+val+"</div>");
+            }
+        });
+    }
+}
+function toogle_div(platform, value, type){
+    $("#"+platform+"_add").show();
+    $("[id^='"+platform+"_"+type+"_"+"']").hide();
+    d = platform+'_'+type+'_'+value;
+    d = d.replace(/ /g, '');
+    id = d.replace( /(:|\.|\[|\])/g, "\\$1" );
+    $('#'+id).show();
+}
+function render_cloud(platform, node){
+    elm = document.getElementById(platform+'_select');
+    //newElement = document.createElement('p');
+    //elm.appendChild(newElement); 
+    global_list[platform]={};
+    if('openstack:sliver' in node){
+        selectFlavor = document.createElement('select');
+        selectFlavor.id = platform+"_selectFlavor";
+        selectFlavor.name = platform+"_selectFlavor";
+        selectFlavor.onchange = function(){
+            /* 1) Display corresponding Flavor div - hide others - reset selectImage value */
+            toogle_div(platform, this.value, 'flavor');
+            /* 3) Disable Images, Enable only compatible ones in selectImage */
+            console.log(this.value);
+            console.log(global_list[platform][this.value]);
+            $("#"+platform+"_selectImage option[value=0]").prop('selected', true);
+            $("[id^='"+platform+"_image_"+"']").hide();
+            $("#"+platform+"_selectImage option").attr("disabled",true);
+            $.each(global_list[platform][this.value], function (i,v){
+                $("#"+platform+"_selectImage option[value='" + v + "']").attr("disabled",false);
+            });
+        }
+        var option = document.createElement("option");
+        option.text = "-- select a flavor --";
+        option.value = 0;
+        selectFlavor.appendChild(option);
+        jQuery.each( node['openstack:sliver'], function( i, sliver ) {
+            if('openstack:flavor' in sliver){
+                f = render_option(sliver['openstack:flavor']);
+                selectFlavor.appendChild(f);
+                flavor = sliver["openstack:flavor"];
+                /* 1) create hidden div to explain caracteristics of the flavor */
+                render_description(platform, flavor, 'flavor');
+                flavor_name = flavor['@name'];
+                global_list[platform][flavor_name]=[];
+                if ("openstack:image" in flavor){
+                    selectImage = document.createElement('select');
+                    selectImage.id = platform+"_selectImage";
+                    selectImage.name = platform+"_selectImage";
+                    selectImage.onchange = function(){
+                        /* 2) display corresponding Image div - hide others */
+                        toogle_div(platform, this.value, 'image');
+                    }
+                    var option = document.createElement("option");
+                    option.text = "-- select an image --";
+                    option.value = 0;
+                    selectImage.appendChild(option);
+                    if(flavor["openstack:image"] instanceof Array){
+                        jQuery.each( flavor["openstack:image"], function( i, img ) {
+                           image = render_option(img);
+                           selectImage.appendChild(image);
+                           /* 2) create hidden div to explain caracteristics of the image */
+                           render_description(platform, img, 'image');
+                           global_list[platform][flavor_name].push(img['@name']);
+                        });
+                    }else{
+                        image = render_option(flavor["openstack:image"]);
+                        selectImage.appendChild(image);
+                        /* 2) create hidden div to explain caracteristics of the image */
+                        render_description(platform, flavor["openstack:image"], 'image');
+                        global_list[platform][flavor_name].push(flavor['openstack:image']['@name']);
+                    }
+                }
+
+            }
+        });
+        elm.appendChild(selectFlavor); 
+        elm.appendChild(selectImage); 
+    }
+    //$("#"+platform+"_selectFlavor").css("width","50%");
+    //$("#"+platform+"_selectImage").css("width","50%");
+}
+function is_finished(len_platforms, pf_status){
+    if(len_platforms == pf_status){
+        return true;
+    }else{
+        return false;
+    }
+}
+function send_delete(platform, sliver_name){
+    jQuery('#'+platform+'_vm').val(sliver_name);
+    jQuery('#'+platform+'_form_delete').submit();
+}
+function render_node(platform, node){
+    if('openstack:sliver' in node){
+        sliver = node['openstack:sliver']
+        var d = platform+'_existing_'+sliver['@sliver_name'];
+        d = d.replace(/ /g, '');
+        id = d.replace( /(:|\.|\[|\])/g, "\\$1" );
+        $("#"+platform+"_existing").append("<div id='"+platform+'_existing_'+sliver['@sliver_name']+"' class='row'></div>");
+        //$("#"+id).append("<input type='hidden' name='"+platform+"_"+sliver['@sliver_name']+"' value='"+sliver['@sliver_name']+"'>");
+        $("#"+id).append("<div class='col-md-2' style='margin-left:15px;'>"+sliver['@sliver_name']+"</div>");
+        $("#"+id).append("<div class='col-md-4'>"+sliver['openstack:flavor']['@name']+"</div>");
+        $("#"+id).append("<div class='col-md-4'>"+sliver['openstack:flavor']['openstack:image']['@name']+"</div>");
+        $("#"+id).append("<div class='col-md-1'><input id='"+platform+"_delete_"+sliver['@sliver_name']+"' type='submit' form='"+platform+"_form_delete' value='Delete' onclick=send_delete('"+platform+"','"+sliver['@sliver_name']+"');></div>");
+        /*
+        sliver['openstack:address']
+        sliver['openstack:flavor']
+        */
+    }
+}
+
+$(document).ready(function() {
+    var data = Array(); 
+    var platform_status = Array();
+    var platform_empty = Array();
+{% for platform in platforms %}
+    console.log('{{platform}}');
+    {% if platform in cloud_platforms %}
+    $.post("/sfa/Describe",{'hrn':'{{slicename}}', 'type':'slice', 'platform':['{{platform}}']}, function( data ) {
+        console.log(data);
+        if('parsed' in data['{{platform}}'] && 'rspec' in data['{{platform}}']['parsed']){
+           rspec = data['{{platform}}']['parsed']['rspec'];
+           if('node' in rspec){
+               if(rspec['node'] instanceof Array) {
+                   jQuery.each( rspec['node'], function( i, node ) {
+                       render_node('{{platform}}',node);
+                   });
+               }else{
+                   render_node('{{platform}}',rspec['node']);
+               }
+           }
+        }
+    });
+    $.post("/sfa/ListResources",{'platform':['{{platform}}']}, function( d ) {
+        $.extend(data,d);
+        console.log(data);
+        if('parsed' in data['{{platform}}'] && 'rspec' in data['{{platform}}']['parsed']){
+           rspec = data['{{platform}}']['parsed']['rspec'];
+           if('node' in rspec){
+               if(rspec['node'] instanceof Array) {
+                   jQuery.each( rspec['node'], function( i, node ) {
+                       render_cloud('{{platform}}',node);
+                   });
+               }else{
+                   render_cloud('{{platform}}',rspec['node']);
+               }
+           }else{
+               platform_empty.push('{{platform}}');
+           }
+        }else{
+            platform_empty.push('{{platform}}');
+        }
+        platform_status.push('{{platform}}');
+        if(is_finished({{len_platforms}},platform_status.length)){
+            $("#loading").hide();
+            if(platform_empty.length == {{len_platforms}}){
+                $("#warning_message").show();
+            }
+        }
+    });
+
+    {% endif %}
+{% endfor %}
+});
+</script>
+{% endblock %}
+
+{% block content %}
+{{post_values}}
+{% for platform in platforms %}
+    {% if platform in cloud_platforms %}
+    <div style="padding-left:20px;padding-top:20px;padding-right:20px;padding-bottom:20px;border-style:solid;border-width:1px;width:700px;">
+        <h2>{{ platform }}</h2>
+        <form id="{{platform}}_form_add" method="post">
+        {% csrf_token %}
+        <div id="{{platform}}_input" class="row">
+            <div class="col-md-1">
+            <input type="text" maxlength="2" id="{{platform}}_number" name="{{platform}}_number" style="width:2.2em;min-width:2.2em;">
+            </div>
+            <div id="{{platform}}_select" class="col-md-11"></div>
+        </div>
+        <div id="{{platform}}_add" class="row" style="display:none;">
+            <div class="col-md-1" style="padding-top:50px;">
+            <input type="hidden" name="action" id="action" value="add">
+            <input type="hidden" name="platform" id="platform" value="{{platform}}">
+            <input type="submit" form="{{platform}}_form_add" value="Add" onclick="this.form.submit();">
+            </div>
+        </div>
+        </form>
+        <br>
+        // display only if VMs already in slice
+        <form id="{{platform}}_form_delete" method="post">
+        {% csrf_token %}
+        <div id="{{platform}}_existing" class="row">
+        <input type="hidden" name="{{platform}}_vm" id="{{platform}}_vm">
+        <input type="hidden" name="action" id="action" value="delete">
+        <input type="hidden" name="platform" id="platform" value="{{platform}}">
+        </div> 
+        </form>
+        <br>
+        // display only pending changes
+        <br>
+        <form id="{{platform}}_form_reserve" method="post">
+        {% csrf_token %}
+        <div id="{{platform}}_pending" class="row"></div> 
+        <input type="hidden" name="action" id="action" value="reserve">
+        <input type="hidden" name="platform" id="platform" value="{{platform}}">
+        <input type="submit" form="{{platform}}_form_reserve" value="Reserve" onclick="this.form.submit();">
+        </form>
+    </div>
+    {% endif %}
+{% endfor %}
+{% endblock %}