Cloud plugin style
[myslice.git] / portal / templates / slice-tab-cloud.html
1 {% extends "layout_wide.html" %}
2 {% load portal_filters %}
3
4 {% block head %}
5 <style>
6 .disabled {
7     z-index: 1000;
8     background-color: #999999;
9 opacity: 0.3;
10          pointer-events: none;
11 }
12 </style>
13 <script type="text/javascript">
14
15 var global_list = {};
16 var data = Array(); 
17 var ad_rspec = Object(); 
18 var request_rspec = Object();
19 var manifest_rspec = Object(); 
20 var deleted_nodes = {}; 
21 var added_nodes = {}; 
22 var len_platforms = {{len_platforms}};
23
24 var key_sliver = '';
25 var key_slivername = '';
26 var key_image = '';
27
28 /* render_flavor & render_image */
29 function render_option(obj){
30     var option = document.createElement("option");
31     if(obj instanceof Object){
32         obj_name = obj["@name"];
33     }else{
34         obj_name = obj;
35     }
36     option.text = obj_name;
37     option.value = obj_name;
38     return option;
39 }
40 function render_description(platform, obj, type, node_name){
41     if($('#'+platform+'_'+type).length==0){
42         $('#'+platform+'_add_'+node_name).append("<div id='"+platform+"_"+type+"'>");
43     }
44     if(obj instanceof Array){
45         obj_name = obj["@name"];
46     }else{
47         obj_name = obj;
48     }
49     var d = platform+'_'+type+'_'+obj_name;
50     d = d.replace(/ /g, '');
51     id = d.replace( /(:|\.|\[|\])/g, "\\$1" );
52     if($('#'+id).length==0){
53         $('#'+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>");
54     }
55     if($('#'+id+' div').length==0){
56         if(obj instanceof Array){
57              jQuery.each(obj, function(key,val){
58                     if (key != 'openstack:image' && key != 'disk_image'){
59                         $('#'+id).append("<div>"+key.replace('@','')+": "+val+"</div>");
60                     }
61             });
62         }else{
63             // What do we do?
64         }
65     }
66 }
67 function toogle_div(platform, value, type, node_name){
68     $("#"+platform+"_add_"+node_name).show();
69     if ( $("#"+platform+"_selectImage_"+node_name).length ) {
70         // show the add button only if image is selected
71         if($("#"+platform+"_selectImage_"+node_name).val()!=null && $("#"+platform+"_selectImage").val()!=0 && value!=0){
72             $("#"+platform+"_add_button_"+node_name).show();
73         }else{
74             $("#"+platform+"_add_button_"+node_name).hide();
75         }
76     }else{
77         $("#"+platform+"_add_button_"+node_name).show();
78     }
79     $("[id^='"+platform+"_"+type+"_"+"']").hide();
80     d = platform+'_'+type+'_'+value;
81     d = d.replace(/ /g, '');
82     id = d.replace( /(:|\.|\[|\])/g, "\\$1" );
83     $('#'+id).show();
84 }
85 function render_cloud(platform, node){
86     console.log(node);
87     if ('@component_name' in node){
88         node_name = node['@component_name']
89     }else{
90         node_name = node['@component_id'].split('+').pop();
91     }
92     elm = document.getElementById(platform+'_select_'+node_name);
93     //newElement = document.createElement('p');
94     //elm.appendChild(newElement); 
95     global_list[platform][node_name]={};
96     if('openstack:sliver' in node){
97         key_sliver = 'openstack:sliver';
98         key_slivername = '@sliver_name';
99     }else if('sliver_type' in node){
100         key_sliver = 'sliver_type';
101         key_slivername = '@name';
102     }
103     if (key_sliver != ''){
104         selectFlavor = document.createElement('select');
105         selectFlavor.id = platform+"_selectFlavor_-_"+node_name;
106         selectFlavor.name = platform+"_selectFlavor_-_"+node_name;
107         selectFlavor.onchange = function(){
108             /* 1) Display corresponding Flavor div - hide others - reset selectImage value */
109             name = this.id.split("_-_").pop();
110             toogle_div(platform, this.value, 'flavor', name);
111             if ( $("#"+platform+"_selectImage_"+name).length ) {
112                 $("#"+platform+"_selectImage_"+name+" option[value=0]").prop('selected', true);
113                 /* 3) Disable Images, Enable only compatible ones in selectImage */
114                 $("[id^='"+platform+"_image_"+name+"']").hide();
115                 $("#"+platform+"_selectImage_"+name+" option").attr("disabled",true);
116                 $.each(global_list[platform][name][this.value], function (i,v){
117                     $("#"+platform+"_selectImage_"+name+" option[value='" + v + "']").attr("disabled",false);
118                 });
119                 $("#"+platform+"_selectImage_"+name).attr("disabled",false);
120             }
121         }
122         var option = document.createElement("option");
123         option.text = "-- select a flavor --";
124         option.value = 0;
125         selectFlavor.appendChild(option);
126         jQuery.each( node[key_sliver], function( i, sliver ) {
127                 flavor = get_flavor(sliver);
128                 f = render_option(flavor);
129                 selectFlavor.appendChild(f);
130                 /* 1) create hidden div to explain caracteristics of the flavor */
131                 render_description(platform, flavor, 'flavor', node_name);
132                 if(flavor instanceof Object){
133                     flavor_name = flavor['@name'];
134                 }else{
135                     flavor_name = flavor;
136                 }
137                 global_list[platform][node_name][flavor_name]=[];
138                 if(flavor instanceof Object){
139                     if ("openstack:image" in flavor){
140                         images = flavor['openstack:image'];
141                         key_image = 'openstack:image';
142                     }else if("disk_image" in flavor){
143                         images = flavor['disk_image'];
144                         key_image = 'disk_image';
145                     }else{
146                         key_image = false;
147                     }
148                 }else{
149                     key_image = false;
150                 }
151                 if(key_image){
152                     selectImage = document.createElement('select');
153                     selectImage.id = platform+"_selectImage_"+node_name;
154                     selectImage.name = platform+"_selectImage_"+node_name;
155                     selectImage.onchange = function(){
156                         /* 2) display corresponding Image div - hide others */
157                         toogle_div(platform, this.value, 'image', node_name);
158                     }
159                     var option = document.createElement("option");
160                     option.text = "-- select an image --";
161                     option.value = 0;
162                     selectImage.appendChild(option);
163                     if(images instanceof Array){
164                         jQuery.each( images, function( i, img ) {
165                                 image = render_option(img);
166                                 image.disabled = true;
167                                 selectImage.appendChild(image);
168                                 /* 2) create hidden div to explain caracteristics of the image */
169                                 render_description(platform, img, 'image', node_name);
170                                 global_list[platform][node_name][flavor_name].push(img['@name']);
171                         });
172                     }else{
173                         image = render_option(images);
174                         image.disabled = true;
175                         selectImage.appendChild(image);
176                         /* 2) create hidden div to explain caracteristics of the image */
177                         render_description(platform, images, 'image', node_name);
178                         global_list[platform][node_name][flavor_name].push(images['@name']);
179                     }
180                 }
181         });
182         elm.appendChild(selectFlavor); 
183         if(key_image){
184             elm.appendChild(selectImage); 
185         }
186     }
187     $("#"+platform+"_selectFlavor_-_"+node_name).css("width","100px");
188     $("#"+platform+"_selectFlavor_-_"+node_name).css("height","30px");
189     if(key_image){
190         $("#"+platform+"_selectImage_"+node_name).css("width","100px");
191         $("#"+platform+"_selectImage_"+node_name).css("height","30px");
192     }
193 }
194 function get_flavor(sliver){
195     if(typeof sliver === 'string' || sliver instanceof String){
196         return sliver
197     } else if('openstack:flavor' in sliver){
198         return sliver['openstack:flavor'];
199     }else{
200         return sliver;
201     }
202 }
203 function is_finished(len_platforms, pf_status){
204     if(len_platforms == pf_status){
205         return true;
206     }else{
207         return false;
208     }
209 }
210 function sliver_name_exists(sliver_name){
211     if(sliver_name in added_nodes){
212         return true;
213     }
214     /*
215        if (sliver_name in deleted_nodes){
216        return true;
217        }
218      */
219     return false;
220 }
221 function find_sliver_name(sliver_name, num){
222     for (j=Object.keys(added_nodes).length; j<Object.keys(added_nodes).length+num; i++){
223         vm_name = sliver_name+'_'+j;
224         if(!sliver_name_exists(vm_name)){
225             return vm_name
226         }
227     }
228 }
229
230 function send_add(platform, node_name){ 
231     $('#'+platform+'_pending_add').show();
232     sliver_name = $('#'+platform+'_sliver_name_'+node_name).val();
233     sliver_name = sliver_name.replace(' ','_');
234     flavor_name = $('#'+platform+'_selectFlavor_-_'+node_name).val();
235     image_name = $('#'+platform+'_selectImage_'+node_name).val();
236
237     num = $('#'+platform+'_number_'+node_name).val();
238     if (num > 1){
239         for (i = 0; i < num; i++){
240             // XXX Check if the name already exist in existing VMs and added_nodes
241             vm_name = sliver_name+"_"+i;
242             if (sliver_name_exists(vm_name)){
243                 vm_name = find_sliver_name(sliver_name, num);
244             }
245             node = get_node(vm_name, flavor_name, image_name, node_name);
246             add_to_request_rspec(node);
247             render_node(platform, node, 'pending_add');
248             added_nodes[vm_name]=node;
249         }
250     }else{
251         if (sliver_name_exists(sliver_name)){
252             sliver_name = find_sliver_name(sliver_name, num);
253         }
254         node = get_node(sliver_name, flavor_name, image_name, node_name);
255         add_to_request_rspec(node);
256         render_node(platform, node, 'pending_add');
257         added_nodes[sliver_name]=node;
258     }
259     toogle_div(platform, flavor_name, 'flavor', node_name);
260     toogle_div(platform, image_name, 'image', node_name);
261     flavor_name = $('#'+platform+'_selectFlavor_-_'+node_name).val(0);
262     image_name = $('#'+platform+'_selectImage_'+node_name).val(0);
263     $('#'+platform+'_add_'+node_name).hide();
264     $('#'+platform+'_add_button_'+node_name).hide();
265     $('#'+platform+'_div_pending').show();
266     console.log(request_rspec);
267     //jQuery('#'+platform+'_form_delete').submit();
268 }
269 function get_node(vm_name, flavor_name, image_name, node_name){
270     var node = {};
271     if(ad_rspec['rspec']['node'] instanceof Array) {
272         // Deep copy of the Array to avoid reference
273         var i=0;
274         jQuery.each(ad_rspec['rspec']['node'], function(x, n){
275             if(n['@component_name']==node_name){
276                 i = x;
277                 return;
278             }
279         });
280         node = jQuery.extend(true, {}, ad_rspec['rspec']['node'][i]);
281     }else{
282         // Deep copy of the Array to avoid reference
283         node = jQuery.extend(true, {}, ad_rspec['rspec']['node']);
284     }
285     if(node[key_sliver] instanceof Array) {
286         node[key_sliver] = node[key_sliver][0];
287     }
288     node[key_sliver][key_slivername] = vm_name;
289     node["@client_id"] = vm_name;
290     console.log(vm_name);
291
292     flavor = Array();
293
294     if('openstack:flavor' in node[key_sliver]){
295         flavor = {'@name':flavor_name,'openstack:image':{'@name':image_name}};
296         node[key_sliver]['openstack:flavor']=flavor;
297     }else{
298         if(typeof image_name === "undefined"){
299             flavor = {'@name':flavor_name};
300         }else{
301             flavor = {'@name':flavor_name,'disk_image':{'@name':image_name}};
302         }
303         node[key_sliver]=flavor;
304     }
305
306     if('openstack:security_group' in node[key_sliver]){
307         $.each(node[key_sliver]['openstack:security_group'], function(i, group){
308                 if(group['@name']=='default'){
309                 node[key_sliver]['openstack:security_group'] = group;
310                 return false;
311                 }
312                 });
313     }
314     return node;
315 }
316 function send_delete(platform, sliver_name){
317     $('#'+platform+'_pending_delete').show();
318     jQuery('#'+platform+'_vm').val(sliver_name);
319     jQuery('#'+platform+'_existing_'+sliver_name).hide();
320     node = remove_node_from_request_rspec(sliver_name);
321     deleted_nodes[sliver_name]=node;
322     render_node(platform, node, 'pending_delete');
323     $('#'+platform+'_div_pending').show();
324     console.log(request_rspec);
325 }
326 function add_to_request_rspec(node){
327     if(request_rspec['rspec']['node'] instanceof Array) {
328         request_rspec['rspec']['node'].push(node);
329     }else{
330         n = request_rspec['rspec']['node'];
331         request_rspec['rspec']['node'] = Array();
332         request_rspec['rspec']['node'].push(n);
333         request_rspec['rspec']['node'].push(node);
334     }
335 }
336 function remove_node_from_request_rspec(sliver_name){
337     var save_node = Array();
338     jQuery.each( request_rspec['rspec']['node'], function( i, node ) {
339             if(node[key_sliver][key_slivername]==sliver_name){
340             request_rspec['rspec']['node'].splice(i,1);
341             save_node = node;
342             return false;
343             }
344             });
345     return save_node;
346 }
347 function cancel_add(platform,sliver_name){
348     // remove the canceled node from the pending list
349     $('#'+platform+'_pending_add_'+sliver_name).remove();
350     // remove the canceled node from the request rspec
351     node = remove_node_from_request_rspec(sliver_name);
352     delete added_nodes[sliver_name];
353     // hide the pending div if there are no more nodes
354     if ($('#'+platform+'_pending_add div').length==0){
355         $('#'+platform+'_pending_add').hide();
356         if ($('#'+platform+'_pending_delete div').length==0){
357             $('#'+platform+'_div_pending').hide();
358             $('#'+platform+'_pending_delete').hide();
359         }
360     }
361 }
362 function cancel_delete(platform,sliver_name){
363     // display the canceled node back in existing nodes
364     $('#'+platform+'_existing_'+sliver_name).show();
365     // remove the canceled node from the pending list
366     $('#'+platform+'_pending_delete_'+sliver_name).remove();
367     // Cancel the deletion of an existing node -> push it back to the request rspec
368     request_rspec['rspec']['node'].push(deleted_nodes[sliver_name]);
369     delete deleted_nodes[sliver_name];
370     // hide the pending div if there are no more nodes
371     if ($('#'+platform+'_pending_delete div').length==0){
372         $('#'+platform+'_pending_delete').hide();
373         if ($('#'+platform+'_pending_add div').length==0){
374             $('#'+platform+'_div_pending').hide();
375             $('#'+platform+'_pending_add').hide();
376         }
377     }
378 }
379
380 function public_ip(platform,sliver_name,is_public){
381     // XXX Change ip status in request_rspec
382     if(is_public){
383         // external_ip="true"
384         node = remove_node_from_request_rspec(sliver_name);
385         node['external_ip']="true";
386         added_nodes[sliver_name]['external_ip']="true";
387         request_rspec['rspec']['node'].push(node);        
388     }else{
389         console.log(sliver_name+' NOT public ');
390         // external_ip="false"
391         node = remove_node_from_request_rspec(sliver_name);
392         node['external_ip']="false";
393         added_nodes[sliver_name]['external_ip']="false";
394         request_rspec['rspec']['node'].push(node);        
395     }
396 }
397
398 function render_node(platform, node, state){
399     if(key_sliver in node){
400         sliver = node[key_sliver];
401         if(sliver instanceof Array){
402             client_id = sliver['@name'];
403         }else{
404             if ('@sliver_name' in sliver){
405                 client_id = sliver['@sliver_name'];
406             }else{
407                 client_id = node['@client_id'];
408             }
409         }
410         if ('@component_name' in node){
411             node_name = node['@component_name']
412         }else{
413             node_name = node['@component_id'].split('+').pop();
414         }
415
416         var d = platform+'_'+state+'_'+client_id;
417         d = d.replace(/ /g, '');
418         id = d.replace( /(:|\.|\[|\])/g, "\\$1" );
419         $("#"+platform+"_"+state).append("<div id='"+platform+'_'+state+'_'+client_id+"' class='row'></div>");
420         //$("#"+id).append("<input type='hidden' name='"+platform+"_"+client_id+"' value='"+client_id+"'>");
421         if(state=='pending_add'){
422             $("#"+id).append("<div class='col-md-1' style='width:40px;margin-left:0px;!important;'><input type='checkbox' id='publicip_"+platform+"_"+client_id+"' onclick=public_ip('"+platform+"','"+client_id+"',this.checked);></div>");
423         }else{
424             $("#"+id).append("<div class='col-md-1' style='width:40px;margin-left:0px;!important;'>&nbsp;</div>");
425         }
426         $("#"+id).append("<div class='col-md-2'>"+node_name+"</div>");
427         $("#"+id).append("<div class='col-md-2'>"+client_id+"</div>");
428         if('openstack:flavor' in node[key_sliver]){
429             $("#"+id).append("<div class='col-md-2'>"+sliver['openstack:flavor']['@name']+"</div>");
430             $("#"+id).append("<div class='col-md-3'>"+sliver['openstack:flavor']['openstack:image']['@name']+"</div>");
431         }else{
432             $("#"+id).append("<div class='col-md-2'>"+sliver['@name']+"</div>");
433             if('disk_image' in sliver){
434                 $("#"+id).append("<div class='col-md-3'>"+sliver['disk_image']['@name']+"</div>");
435             }else{
436                 $("#"+id).append("<div class='col-md-3'>&nbsp;</div>");
437             }
438         }
439
440         if(state=='existing'){
441             $("#"+id).append("<div class='col-md-1'><input id='"+platform+"_delete_"+client_id+"' type='submit' form='"+platform+"_form_delete' value='Delete' onclick=send_delete('"+platform+"','"+client_id+"');></div>");
442         }else if(state=='pending_add'){
443             $("#"+id).append("<div class='col-md-1'><input id='"+platform+"_cancel_"+client_id+"' type='submit' form='"+platform+"_form_cancel' value='Cancel' onclick=cancel_add('"+platform+"','"+client_id+"');></div>");
444         }else if (state=='pending_delete'){
445             $("#"+id).append("<div class='col-md-1'><input id='"+platform+"_cancel_"+client_id+"' type='submit' form='"+platform+"_form_cancel' value='Cancel' onclick=cancel_delete('"+platform+"','"+client_id+"');></div>");
446         }else{
447             console.log("state: "+state+" not impemented");
448         }
449         /*
450            sliver['openstack:address']
451            sliver['openstack:flavor']
452          */
453     }
454 }
455
456 function allocate(platform, slicename){
457     $("#"+platform+"_main").addClass("disabled");
458     $("#"+platform+"_wait").show();
459     $("#"+platform+"_wait").spin();
460     console.log("allocate rspec = ")
461     console.log(request_rspec);
462     console.log("allocate json = ")
463     console.log(JSON.stringify(request_rspec));
464     $.post("/sfa/Allocate",{'hrn':slicename, 'type':'slice', 'platform':[platform], 'rspec':JSON.stringify(request_rspec)}, function( result ) {
465             console.log(result);
466             clear_data(platform);
467             load_data(platform,slicename);
468             $("#"+platform+"_main").removeClass("disabled");
469             $("#"+platform+"_wait").hide();
470             if('error' in result[platform]){
471                 mysliceAlert('Error: '+result[platform]['error_msg'],'danger', true);
472             }else if('code' in result[platform] && result[platform]['code']['am_code']==-1){
473                 mysliceAlert('Error: '+result[platform]['output'],'danger', true);
474             }else{
475                 mysliceAlert('Success: changes applied','success', true);
476             }
477     });
478 }
479 function clear_data(platform){
480     $('#'+platform+'_existing').children().remove();
481     $('#'+platform+'_pending_delete').children().remove();
482     $('#'+platform+'_pending_delete').hide();
483     $("[id^="+platform+"_selectFlavor]").remove();
484     $("[id^="+platform+"_selectImage]").remove();
485     $('#'+platform+'_pending_add').children().remove();
486     $('#'+platform+'_pending_add').hide();
487     $('#'+platform+'_div_pending').hide();
488 }
489 function load_data(platform, slicename){
490     var platform_status = Array();
491     var platform_empty = Array();
492
493     $.post("/sfa/Describe",{'hrn':slicename, 'type':'slice', 'platform':[platform]}, function( d ) {
494        console.log(data);
495        $("#"+platform+"_main").spin(false);
496        data = d;
497        if('parsed' in data[platform] && 'rspec' in data[platform]['parsed']){
498            manifest_rspec = data[platform]['parsed']['rspec'];
499            request_rspec = data[platform]['parsed'];
500            request_rspec['rspec']['@type']='request';
501            if('node' in manifest_rspec){
502                if(manifest_rspec['node'] instanceof Array) {
503                    jQuery.each( manifest_rspec['node'], function( i, node ) {
504                        render_node(platform, node, 'existing');
505                    });
506                }else{
507                    render_node(platform, manifest_rspec['node'], 'existing');
508                }
509                $('#'+platform+'_existing').show();
510            }
511        }else{
512            // Let's build a default request_rspec
513            request_rspec['rspec']=Object();
514            request_rspec['rspec']['@type']='request';
515            request_rspec['rspec']['node']=Array();
516        }
517     });
518     $.post("/sfa/ListResources",{'platform':[platform]}, function( d ) {
519             //$.extend(data,d);
520             console.log(data);
521             global_list[platform]={};
522             if('parsed' in d[platform] && 'rspec' in d[platform]['parsed']){
523             ad_rspec = d[platform]['parsed'];
524             if('node' in ad_rspec['rspec']){
525             if(ad_rspec['rspec']['node'] instanceof Array) {
526             jQuery.each( ad_rspec['rspec']['node'], function( i, node ) {
527                 render_cloud(platform,node);
528                 });
529             }else{
530             render_cloud(platform,ad_rspec['rspec']['node']);
531             }
532             }else{
533             platform_empty.push(platform);
534             }
535             }else{
536             platform_empty.push(platform);
537             }
538             platform_status.push(platform);
539             if(is_finished(len_platforms,platform_status.length)){
540                 $("#loading").hide();
541                 if(platform_empty.length == len_platforms){
542                     $("#warning_message").show();
543                 }
544             }
545     });
546 }
547 $(document).ready(function() {
548         {% for platform in platforms %}
549         {% if platform in cloud_platforms %}
550         $("#{{platform}}_main").spin();
551         load_data('{{platform}}', '{{slicename}}');
552         {% endif %}
553         {% endfor %}
554         });
555 </script>
556 {% endblock %}
557
558 {% block content %}
559 {{post_values}}
560 {% for platform in platforms %}
561     {% if platform in cloud_platforms %}
562
563     <div id="{{platform}}_wait" style="display:none;margin-top:35px;position:absolute;margin-left:50%;"></div>
564     <div id="{{platform}}_main" style="padding-left:20px;padding-top:20px;padding-right:20px;padding-bottom:20px;border-style:solid;border-width:1px;">
565         <h2>{{ platform }}</h2>
566         // display only if VMs already in slice
567         <h4>VMs in slice {{slicename}}</h4>
568         <div id="{{platform}}_existing" class="row alert alert-info" style='display:none;margin-left:0px;!important;margin-right:0px;!important;'>
569         <input type="hidden" name="{{platform}}_vm" id="{{platform}}_vm">
570         <input type="hidden" name="action" id="action" value="delete">
571         <input type="hidden" name="platform" id="platform" value="{{platform}}">
572         </div> 
573         <div id="{{platform}}_div_nodes">
574         {% for key, value in result.items %} 
575           {% if key == platform %}
576             {% if value.parsed.rspec.node|get_type == 'list' %}
577                 {% for node in value.parsed.rspec.node %}
578                     {% for k,node_urn in node.items %} 
579                         {% if k == '@component_id' %}
580                         {% widget '_widget-cloud-node.html' %}
581                         {% endif %}
582                     {% endfor %}
583                 {% endfor %}
584             {% else %}
585                 {% for k,node_urn in value.parsed.rspec.node.items %}
586                     {% if k == '@component_id' %}
587                     {% widget '_widget-cloud-node.html' %}
588                     {% endif %}
589                 {% endfor %}
590             {% endif %}
591           {% endif %}
592         {% endfor %}
593         </div>
594         <br>
595         <div id="{{platform}}_div_pending" style="display:none;">
596             // display only pending changes
597             <h4>Pending changes</h4>
598             <form id="{{platform}}_form_reserve" method="post">
599             {% csrf_token %}
600             <div id="{{platform}}_pending_add" class="row alert alert-success" style="display:none;margin-bottom:3px !important;margin-left:0px;!important;margin-right:0px;!important;"></div> 
601             <div id="{{platform}}_pending_delete" class="row alert alert-danger" style="display:none;margin-bottom:3px !important;margin-left:0px;!important;margin-right:0px;!important;"></div> 
602             <br>
603             <input type="hidden" name="action" id="action" value="reserve">
604             <input type="hidden" name="platform" id="platform" value="{{platform}}">
605             <input type="submit" form="{{platform}}_form_reserve" value="Apply changes" onclick="allocate('{{platform}}','{{slicename}}');">
606             </form>
607         </div>
608     </div>
609     {% endif %}
610 {% endfor %}
611 {% endblock %}