Cloud plugin: OK
[myslice.git] / portal / templates / slice-tab-cloud.html
1 {% extends "layout_wide.html" %}
2
3 {% block head %}
4 <script type="text/javascript">
5
6 var global_list = {};
7 var data = Array(); 
8 var ad_rspec = Array(); 
9 var request_rspec = Array(); 
10 var manifest_rspec = Array(); 
11 var deleted_nodes = {}; 
12 var added_nodes = {}; 
13
14 var len_platforms = {{len_platforms}};
15
16 /* render_flavor & render_image */
17 function render_option(obj){
18     var option = document.createElement("option");
19     option.text = obj["@name"];
20     option.value = obj["@name"];
21     return option;
22 }
23 function render_description(platform, obj, type){
24     if($('#'+platform+'_'+type).length==0){
25         $('#'+platform+'_add').append("<div id='"+platform+"_"+type+"'>");
26     }
27     var d = platform+'_'+type+'_'+obj['@name'];
28     d = d.replace(/ /g, '');
29     id = d.replace( /(:|\.|\[|\])/g, "\\$1" );
30     if($('#'+id).length==0){
31         $('#'+platform+'_'+type).append("<div id='"+d+"' class='alert-success col-md-5' style='margin-top:10px;display:none;border-style:solid;border-color:#f1f1f1;border-width:2px;'></div>");
32     }
33     if($('#'+id+' div').length==0){
34         jQuery.each(obj, function(key,val){
35             if (key != 'openstack:image'){
36                 $('#'+id).append("<div>"+key.replace('@','')+": "+val+"</div>");
37             }
38         });
39     }
40 }
41 function toogle_div(platform, value, type){
42     $("#"+platform+"_add").show();
43     // show the add button only if image is selected
44     if($("#"+platform+"_selectImage").val()!=null && $("#"+platform+"_selectImage").val()!=0 && value!=0){
45         $("#"+platform+"_add_button").show();
46     }else{
47         $("#"+platform+"_add_button").hide();
48     }
49     $("[id^='"+platform+"_"+type+"_"+"']").hide();
50     d = platform+'_'+type+'_'+value;
51     d = d.replace(/ /g, '');
52     id = d.replace( /(:|\.|\[|\])/g, "\\$1" );
53     $('#'+id).show();
54 }
55 function render_cloud(platform, node){
56     elm = document.getElementById(platform+'_select');
57     //newElement = document.createElement('p');
58     //elm.appendChild(newElement); 
59     global_list[platform]={};
60     if('openstack:sliver' in node){
61         selectFlavor = document.createElement('select');
62         selectFlavor.id = platform+"_selectFlavor";
63         selectFlavor.name = platform+"_selectFlavor";
64         selectFlavor.onchange = function(){
65             /* 1) Display corresponding Flavor div - hide others - reset selectImage value */
66             $("#"+platform+"_selectImage option[value=0]").prop('selected', true);
67             toogle_div(platform, this.value, 'flavor');
68             /* 3) Disable Images, Enable only compatible ones in selectImage */
69             $("[id^='"+platform+"_image_"+"']").hide();
70             $("#"+platform+"_selectImage option").attr("disabled",true);
71             $.each(global_list[platform][this.value], function (i,v){
72                 $("#"+platform+"_selectImage option[value='" + v + "']").attr("disabled",false);
73             });
74             $("#"+platform+"_selectImage").attr("disabled",false);
75         }
76         var option = document.createElement("option");
77         option.text = "-- select a flavor --";
78         option.value = 0;
79         selectFlavor.appendChild(option);
80         jQuery.each( node['openstack:sliver'], function( i, sliver ) {
81             if('openstack:flavor' in sliver){
82                 f = render_option(sliver['openstack:flavor']);
83                 selectFlavor.appendChild(f);
84                 flavor = sliver["openstack:flavor"];
85                 /* 1) create hidden div to explain caracteristics of the flavor */
86                 render_description(platform, flavor, 'flavor');
87                 flavor_name = flavor['@name'];
88                 global_list[platform][flavor_name]=[];
89                 if ("openstack:image" in flavor){
90                     selectImage = document.createElement('select');
91                     selectImage.id = platform+"_selectImage";
92                     selectImage.name = platform+"_selectImage";
93                     selectImage.onchange = function(){
94                         /* 2) display corresponding Image div - hide others */
95                         toogle_div(platform, this.value, 'image');
96                     }
97                     var option = document.createElement("option");
98                     option.text = "-- select an image --";
99                     option.value = 0;
100                     selectImage.appendChild(option);
101                     if(flavor["openstack:image"] instanceof Array){
102                         jQuery.each( flavor["openstack:image"], function( i, img ) {
103                            image = render_option(img);
104                            image.disabled = true;
105                            selectImage.appendChild(image);
106                            /* 2) create hidden div to explain caracteristics of the image */
107                            render_description(platform, img, 'image');
108                            global_list[platform][flavor_name].push(img['@name']);
109                         });
110                     }else{
111                         image = render_option(flavor["openstack:image"]);
112                         image.disabled = true;
113                         selectImage.appendChild(image);
114                         /* 2) create hidden div to explain caracteristics of the image */
115                         render_description(platform, flavor["openstack:image"], 'image');
116                         global_list[platform][flavor_name].push(flavor['openstack:image']['@name']);
117                     }
118                 }
119
120             }
121         });
122         elm.appendChild(selectFlavor); 
123         elm.appendChild(selectImage); 
124     }
125     $("#"+platform+"_selectFlavor").css("width","100px");
126     $("#"+platform+"_selectFlavor").css("height","30px");
127     $("#"+platform+"_selectImage").css("width","30px");
128     $("#"+platform+"_selectImage").css("height","30px");
129 }
130 function is_finished(len_platforms, pf_status){
131     if(len_platforms == pf_status){
132         return true;
133     }else{
134         return false;
135     }
136 }
137 function sliver_name_exists(sliver_name){
138     if(sliver_name in added_nodes){
139         return true;
140     }
141     /*
142     if (sliver_name in deleted_nodes){
143         return true;
144     }
145     */
146     return false;
147 }
148 function find_sliver_name(sliver_name, num){
149     for (j=Object.keys(added_nodes).length; j<Object.keys(added_nodes).length+num; i++){
150         vm_name = sliver_name+'_'+j;
151         if(!sliver_name_exists(vm_name)){
152             return vm_name
153         }
154     }
155 }
156
157 function send_add(platform){ 
158     $('#'+platform+'_pending_add').show();
159     sliver_name = $('#'+platform+'_sliver_name').val();
160     sliver_name = sliver_name.replace(' ','_');
161     flavor_name = $('#'+platform+'_selectFlavor').val();
162     image_name = $('#'+platform+'_selectImage').val();
163
164     num = $('#'+platform+'_number').val();
165     if (num > 1){
166         for (i = 0; i < num; i++){
167             // XXX Check if the name already exist in existing VMs and added_nodes
168             vm_name = sliver_name+"_"+i;
169             if (sliver_name_exists(vm_name)){
170                 vm_name = find_sliver_name(sliver_name, num);
171             }
172             node = get_node(vm_name, flavor_name, image_name);
173             request_rspec['rspec']['node'].push(node);
174             render_node(platform, node, 'pending_add');
175             added_nodes[vm_name]=node;
176         }
177     }else{
178         if (sliver_name_exists(sliver_name)){
179             sliver_name = find_sliver_name(sliver_name, num);
180         }
181         node = get_node(sliver_name, flavor_name, image_name);
182         request_rspec['rspec']['node'].push(node);
183         render_node(platform, node, 'pending_add');
184         added_nodes[sliver_name]=node;
185     }
186     toogle_div(platform, flavor_name, 'flavor');
187     toogle_div(platform, image_name, 'image');
188     flavor_name = $('#'+platform+'_selectFlavor').val(0);
189     image_name = $('#'+platform+'_selectImage').val(0);
190     $('#'+platform+'_add').hide();
191     $('#'+platform+'_add_button').hide();
192     $('#'+platform+'_div_pending').show();
193     console.log(request_rspec);
194     //jQuery('#'+platform+'_form_delete').submit();
195 }
196 function get_node(vm_name, flavor_name, image_name){
197         var node = {};
198         if(ad_rspec['rspec']['node'] instanceof Array) {
199             // Deep copy of the Array to avoid reference
200             node = jQuery.extend(true, {}, ad_rspec['rspec']['node'][0]);
201         }else{
202             // Deep copy of the Array to avoid reference
203             node = jQuery.extend(true, {}, ad_rspec['rspec']['node']);
204         }
205         if(node['openstack:sliver'] instanceof Array) {
206             node['openstack:sliver'] = node['openstack:sliver'][0];
207         }
208         node['openstack:sliver']['@sliver_name'] = vm_name;
209         console.log(vm_name);
210
211         if(node['openstack:sliver']['openstack:flavor'] instanceof Array) {
212             node['openstack:sliver']['openstack:flavor'] = node['openstack:sliver']['openstack:flavor'][0];
213         }
214         node['openstack:sliver']['openstack:flavor'] = Array();
215         node['openstack:sliver']['openstack:flavor'] = {'@name':flavor_name,'openstack:image':{'@name':image_name}};
216
217         $.each(node['openstack:sliver']['openstack:security_group'], function(i, group){
218             if(group['@name']=='default'){
219                 node['openstack:sliver']['openstack:security_group'] = group;
220                 return false;
221             }
222         });
223         return node;
224
225 }
226 function send_delete(platform, sliver_name){
227     $('#'+platform+'_pending_delete').show();
228     jQuery('#'+platform+'_vm').val(sliver_name);
229     jQuery('#'+platform+'_existing_'+sliver_name).hide();
230     node = remove_node_from_request_rspec(sliver_name);
231     deleted_nodes[sliver_name]=node;
232     render_node(platform, node, 'pending_delete');
233     $('#'+platform+'_div_pending').show();
234     console.log(request_rspec);
235 }
236 function remove_node_from_request_rspec(sliver_name){
237     var save_node = Array();
238     jQuery.each( request_rspec['rspec']['node'], function( i, node ) {
239         if(node['openstack:sliver']['@sliver_name']==sliver_name){
240             request_rspec['rspec']['node'].splice(i,1);
241             save_node = node;
242             return false;
243         }
244     });
245     return save_node;
246 }
247 function cancel_add(platform,sliver_name){
248     // remove the canceled node from the pending list
249     $('#'+platform+'_pending_add_'+sliver_name).remove();
250     // remove the canceled node from the request rspec
251     node = remove_node_from_request_rspec(sliver_name);
252     delete added_nodes[sliver_name];
253     // hide the pending div if there are no more nodes
254     if ($('#'+platform+'_pending_add div').length==0){
255         $('#'+platform+'_pending_add').hide();
256         if ($('#'+platform+'_pending_delete div').length==0){
257             $('#'+platform+'_div_pending').hide();
258         }
259     }
260 }
261 function cancel_delete(platform,sliver_name){
262     // display the canceled node back in existing nodes
263     $('#'+platform+'_existing_'+sliver_name).show();
264     // remove the canceled node from the pending list
265     $('#'+platform+'_pending_delete_'+sliver_name).remove();
266     // Cancel the deletion of an existing node -> push it back to the request rspec
267     request_rspec['rspec']['node'].push(deleted_nodes[sliver_name]);
268     delete deleted_nodes[sliver_name];
269     // hide the pending div if there are no more nodes
270     if ($('#'+platform+'_pending_delete div').length==0){
271         $('#'+platform+'_pending_delete').hide();
272         if ($('#'+platform+'_pending_add div').length==0){
273             $('#'+platform+'_div_pending').hide();
274         }
275     }
276 }
277
278 function public_ip(platform,sliver_name,is_public){
279     // XXX Change ip status in request_rspec
280     if(is_public){
281         // external_ip="true"
282         node = remove_node_from_request_rspec(sliver_name);
283         node['external_ip']="true";
284         added_nodes[sliver_name]['external_ip']="true";
285         request_rspec['rspec']['node'].push(node);        
286     }else{
287         console.log(sliver_name+' NOT public ');
288         // external_ip="false"
289         node = remove_node_from_request_rspec(sliver_name);
290         node['external_ip']="false";
291         added_nodes[sliver_name]['external_ip']="false";
292         request_rspec['rspec']['node'].push(node);        
293     }
294 }
295
296 function render_node(platform, node, state){
297     if('openstack:sliver' in node){
298         sliver = node['openstack:sliver']
299         var d = platform+'_'+state+'_'+sliver['@sliver_name'];
300         d = d.replace(/ /g, '');
301         id = d.replace( /(:|\.|\[|\])/g, "\\$1" );
302         $("#"+platform+"_"+state).append("<div id='"+platform+'_'+state+'_'+sliver['@sliver_name']+"' class='row'></div>");
303         //$("#"+id).append("<input type='hidden' name='"+platform+"_"+sliver['@sliver_name']+"' value='"+sliver['@sliver_name']+"'>");
304         if(state=='pending_add'){
305             $("#"+id).append("<div class='col-md-1' style='margin-left:0px;!important;'><input type='checkbox' id='publicip_"+platform+"_"+sliver['@sliver_name']+"' onclick=public_ip('"+platform+"','"+sliver['@sliver_name']+"',this.checked);></div>");
306         }else{
307             $("#"+id).append("<div class='col-md-1' style='margin-left:0px;!important;'>&nbsp;</div>");
308         }
309         $("#"+id).append("<div class='col-md-2' style='padding-left:0px;'>"+sliver['@sliver_name']+"</div>");
310         $("#"+id).append("<div class='col-md-3'>"+sliver['openstack:flavor']['@name']+"</div>");
311         $("#"+id).append("<div class='col-md-3'>"+sliver['openstack:flavor']['openstack:image']['@name']+"</div>");
312
313         if(state=='existing'){
314             $("#"+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>");
315         }else if(state=='pending_add'){
316             $("#"+id).append("<div class='col-md-1'><input id='"+platform+"_cancel_"+sliver['@sliver_name']+"' type='submit' form='"+platform+"_form_cancel' value='Cancel' onclick=cancel_add('"+platform+"','"+sliver['@sliver_name']+"');></div>");
317         }else if (state=='pending_delete'){
318             $("#"+id).append("<div class='col-md-1'><input id='"+platform+"_cancel_"+sliver['@sliver_name']+"' type='submit' form='"+platform+"_form_cancel' value='Cancel' onclick=cancel_delete('"+platform+"','"+sliver['@sliver_name']+"');></div>");
319         }else{
320             console.log("state: "+state+" not impemented");
321         }
322         /*
323         sliver['openstack:address']
324         sliver['openstack:flavor']
325         */
326     }
327 }
328
329 function allocate(platform, slicename){
330     $.post("/sfa/Allocate",{'hrn':slicename, 'type':'slice', 'platform':[platform], 'rspec':JSON.stringify(request_rspec)}, function( result ) {
331         console.log(result);
332         clear_data(platform);
333         load_data(platform,slicename);
334         mysliceAlert('Success: changes applied','success', true);
335     });
336 }
337 function clear_data(platform){
338     $('#'+platform+'_existing').children().remove();
339     $('#'+platform+'_pending_delete').children().remove();
340     $("#"+platform+"_selectFlavor").remove();
341     $("#"+platform+"_selectImage").remove();
342     $('#'+platform+'_pending_add').children().remove();
343     $('#'+platform+'_div_pending').hide();
344 }
345 function load_data(platform, slicename){
346     var platform_status = Array();
347     var platform_empty = Array();
348
349     $.post("/sfa/Describe",{'hrn':slicename, 'type':'slice', 'platform':[platform]}, function( d ) {
350         data = d;
351         console.log(data);
352         if('parsed' in data[platform] && 'rspec' in data[platform]['parsed']){
353            manifest_rspec = data[platform]['parsed']['rspec'];
354            request_rspec = data[platform]['parsed'];
355            request_rspec['rspec']['@type']='request';
356            if('node' in manifest_rspec){
357                if(manifest_rspec['node'] instanceof Array) {
358                    jQuery.each( manifest_rspec['node'], function( i, node ) {
359                        render_node(platform,node, 'existing');
360                    });
361                }else{
362                    render_node(platform,manifest_rspec['node'], 'existing');
363                }
364                $('#'+platform+'_existing').show();
365            }
366         }
367     });
368     $.post("/sfa/ListResources",{'platform':[platform]}, function( d ) {
369         //$.extend(data,d);
370         //console.log(data);
371         if('parsed' in d[platform] && 'rspec' in d[platform]['parsed']){
372            ad_rspec = d[platform]['parsed'];
373            if('node' in ad_rspec['rspec']){
374                if(ad_rspec['rspec']['node'] instanceof Array) {
375                    jQuery.each( ad_rspec['rspec']['node'], function( i, node ) {
376                        render_cloud(platform,node);
377                    });
378                }else{
379                    render_cloud(platform,ad_rspec['rspec']['node']);
380                }
381            }else{
382                platform_empty.push(platform);
383            }
384         }else{
385             platform_empty.push(platform);
386         }
387         platform_status.push(platform);
388         if(is_finished(len_platforms,platform_status.length)){
389             $("#loading").hide();
390             if(platform_empty.length == len_platforms){
391                 $("#warning_message").show();
392             }
393         }
394     });
395 }
396 $(document).ready(function() {
397 {% for platform in platforms %}
398     {% if platform in cloud_platforms %}
399     load_data('{{platform}}', '{{slicename}}');
400     {% endif %}
401 {% endfor %}
402 });
403 </script>
404 {% endblock %}
405
406 {% block content %}
407 {{post_values}}
408 {% for platform in platforms %}
409     {% if platform in cloud_platforms %}
410     <div style="padding-left:20px;padding-top:20px;padding-right:20px;padding-bottom:20px;border-style:solid;border-width:1px;width:700px;">
411         <h2>{{ platform }}</h2>
412         // display only if VMs already in slice
413         <h4>VMs in slice {{slicename}}</h4>
414         <form id="{{platform}}_form_delete" method="post">
415         {% csrf_token %}
416         <div id="{{platform}}_existing" class="row alert alert-info" style="display:none;">
417         <input type="hidden" name="{{platform}}_vm" id="{{platform}}_vm">
418         <input type="hidden" name="action" id="action" value="delete">
419         <input type="hidden" name="platform" id="platform" value="{{platform}}">
420         </div> 
421         </form>
422         <h4><a href="#" onclick="$('#{{platform}}_div_add').toggle();"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Create new VMs</a></h4>
423         <div id="{{platform}}_div_add" class="alert" style="background-color:#f1f1f1;display:none;margin-bottom:0px !important;padding-bottom:6px !important;">
424         <form id="{{platform}}_form_add" method="post" class="form-inline">
425         {% csrf_token %}
426         <div id="{{platform}}_input" class="row">
427             <div class="col-md-1"></div>
428             <div class="col-md-3"><label for="{{platform}}_number">number:</label>
429             <input type="text" maxlength="2" id="{{platform}}_number" name="{{platform}}_number" style="width:2.2em;min-width:2.2em;height:30px;" value="1" class="form-control" required>
430             </div>
431             <div class="col-md-8"><label for="{{platform}}_sliver_name">name:</label>
432             <div class="form-group">
433             <input type="text" name="{{platform}}_sliver_name" id="{{platform}}_sliver_name" value="VM" maxlength="12" class="form-control" style="height:30px;" required>
434             </div>
435             </div>
436             <div class="col-md-1"></div>
437             <div id="{{platform}}_select" class="col-md-11"></div>
438         </div>
439         <div id="{{platform}}_add" class="row">
440             <div class="col-md-1">&nbsp; 
441             <input type="hidden" name="action" id="action" value="add">
442             <input type="hidden" name="platform" id="platform" value="{{platform}}">
443             </div>
444         </div>
445         <div class="row" style="padding-top:6px;">
446             <div class="col-md-1">&nbsp;</div>
447             <div class="col-md-11" id="{{platform}}_add_button" style="display:none;">
448             <input type="submit" form="{{platform}}_form_add" value="Add" onclick="send_add('{{platform}}');">
449             </div>
450         </div>
451         </form>
452         </div>
453         <br>
454         <div id="{{platform}}_div_pending" style="display:none;">
455         // display only pending changes
456         <h4>Pending changes</h4>
457         <form id="{{platform}}_form_reserve" method="post">
458         {% csrf_token %}
459         <div id="{{platform}}_pending_add" class="row alert alert-success" style="display:none;margin-bottom:3px !important;"></div> 
460         <div id="{{platform}}_pending_delete" class="row alert alert-danger" style="display:none;margin-bottom:3px !important;"></div> 
461         <br>
462         <input type="hidden" name="action" id="action" value="reserve">
463         <input type="hidden" name="platform" id="platform" value="{{platform}}">
464         <input type="submit" form="{{platform}}_form_reserve" value="Apply changes" onclick="allocate('{{platform}}','{{slicename}}');">
465         </form>
466         </div>
467     </div>
468     {% endif %}
469 {% endfor %}
470 {% endblock %}