From 638c7772a6ec67f3dea26d9bd2cd4fa2c3e479c6 Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> Date: Sat, 28 Aug 2010 22:13:49 +0200 Subject: [PATCH] ongoing tweaks in the reservation frontend --- planetlab/common/actions.php | 41 +++++++++++++++++ planetlab/slices/leases.js | 86 +++++++++++++++++++++++++++--------- planetlab/slices/slice.php | 26 ++++++----- 3 files changed, 121 insertions(+), 32 deletions(-) diff --git a/planetlab/common/actions.php b/planetlab/common/actions.php index ffb6bc1..5f3994d 100644 --- a/planetlab/common/actions.php +++ b/planetlab/common/actions.php @@ -116,6 +116,12 @@ $known_actions []= "add-nodegroup"; $known_actions []= 'delete-nodegroups'; // expects nodegroup_ids +//////////////////////////////////////// leases +$known_actions []= "manage-leases"; +// expects as 'actions' a list of 'action' of the form +// either [ 'add-leases', [nodenames], slicename, t_from, t_until ] +// or [ 'delete-leases', lease_id ] + //////////////////////////////////////////////////////////// $interface_details= array ('method','type', 'ip', 'gateway', 'network', 'broadcast', 'netmask', 'dns1', 'dns2', @@ -944,6 +950,41 @@ Our support team will be glad to answer any question that you might have. break; } +//////////////////////////////////////// leases + case 'manage-leases': { + $actions=json_decode($_POST['actions']); + foreach ($actions as $action) { + $todo=$action[0]; + switch ($todo) { + case 'add-leases': { + plc_debug('(add) action',$action); + break; + } + case 'delete-leases': { + plc_debug('(delete) action',$action); + break; + } + default: { + plc_debug('wrong entry',$action); + } + } + } + + /* + plc_debug('POST',$_POST); + $slicename=$_POST['slicename']; + $nodenames=$_POST['nodenames']; + $t_from=intval($_POST['t_from']); + $t_until=intval($_POST['t_until']); + foreach ($nodenames as $nodename) plc_debug('nodename',$nodename); + $json=json_decode($_POST['nodenames_json']); + plc_debug('json_decode',$json); + $api->AddLeases(); + */ + + break; + } + //////////////////////////////////////// case 'debug': { diff --git a/planetlab/slices/leases.js b/planetlab/slices/leases.js index 96b695a..439ec0e 100644 --- a/planetlab/slices/leases.js +++ b/planetlab/slices/leases.js @@ -1,7 +1,7 @@ /* need to put some place else in CSS ? */ // space for the nodenames -var x_nodelabel = 200; +var x_nodelabel = 120; // right space after the nodename - removed from the above var x_sep=20; // height for the (two) rows of timelabels @@ -26,6 +26,8 @@ var txt_nodelabel = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-se var attr_timebutton = {'fill':'#bbf', 'stroke': '#338','stroke-width':2, 'stroke-linecap':'round', 'stroke-linejoin':'miter', 'stroke-miterlimit':3}; +// keep consistent with sizes above - need for something nicer +var timebutton_path = "M1,0L23,0L12,13L1,0"; /* lease dimensions and colors */ /* refrain from using gradient color, seems to not be animated properly */ @@ -40,14 +42,15 @@ var attr_lease_mine_free={'fill':"white", 'stroke-width':1, 'stroke-dasharray':' var attr_lease_other={'fill':"#f88"}; /* other slices name */ -var txt_slice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-serif', stroke: "none", fill: "#444", - "font-size": 15 }; +var txt_otherslice = {"font": '"Trebuchet MS", Verdana, Arial, Helvetica, sans-serif', stroke: "none", fill: "#444", + "font-size": 12 }; //////////////////////////////////////////////////////////// // the scheduler object -function Scheduler (slicename, axisx, axisy, data) { +function Scheduler (sliceid, slicename, axisx, axisy, data) { - // the data only contain slice names, we need this to find our own leases (mine) + // the data contains slice names, and lease_id, we need this to find our own leases (mine) + this.sliceid=sliceid; this.slicename=slicename; this.axisx=axisx; this.axisy=axisy; @@ -106,11 +109,7 @@ function Scheduler (slicename, axisx, axisy, data) { allnodes.click(allnodes_methods.click); // timeslot buttons for (var i=0, len=axisx.length; i < len; ++i) { - var pathspec="M"+left+","+top; - pathspec+="L"+(left+x_grain)+","+top; - pathspec+="L"+(left+x_grain/2)+","+(top+y_node); - pathspec+="L"+left+","+top; - var timebutton=paper.path(pathspec).attr(attr_timebutton); + var timebutton=paper.path(timebutton_path).attr({'translation':left+','+top}).attr(attr_timebutton); timebutton.from_time=axisx[i][0]; timebutton.scheduler=this; timebutton.click(timebutton_methods.click); @@ -132,9 +131,11 @@ function Scheduler (slicename, axisx, axisy, data) { left += x_nodelabel; var grain=0; while (grain < this.nb_grains()) { - slicename=data[data_index][0]; - duration=data[data_index][1]; + lease_id=data[data_index][0]; + slicename=data[data_index][1]; + duration=data[data_index][2]; var lease=paper.rect (left,top,x_grain*duration,y_node,radius); + lease.lease_id=lease_id; lease.nodename=nodename; lease.nodelabel=nodelabel; if (slicename == "") { @@ -163,6 +164,8 @@ function Scheduler (slicename, axisx, axisy, data) { } this.submit = function () { + document.body.style.cursor = "wait"; + var actions=new Array(); for (var i=0, len=this.leases.length; i<len; ++i) { var lease=this.leases[i]; if (lease.current != lease.initial) { @@ -175,14 +178,40 @@ function Scheduler (slicename, axisx, axisy, data) { until_time=this.leases[j].until_time; ++j; ++i; } - var method=(lease.current=='free') ? 'DeleteLeases' : 'AddLeases'; - window.console.log(method + "(" + - "[" + lease.nodename + "]," + - this.slicename + "," + - from_time + "," + - until_time + ')'); + if (lease.current!='free') { // lease to add + actions.push(new Array('add-leases', + new Array(lease.nodename), + this.slicename, + from_time, + until_time)); + } else { // lease to delete + actions.push(new Array ('delete-leases', + lease.lease_id)); + } } } + sliceid=this.sliceid; + // once we're done with the side-effect performed in actions.php, we need to refresh this view + redirect = function (sliceid) { + window.location = '/db/slices/slice.php?id=' + sliceid + '&show_details=0&show_nodes=1&show_nodes_resa=1'; + } + // Ajax.Request comes with prototype + var ajax=new Ajax.Request('/planetlab/common/actions.php', + {method:'post', + parameters:{'action':'manage-leases', + 'actions':actions.toJSON()}, + onSuccess: function(transport) { + var response = transport.responseText || "no response text"; + document.body.style.cursor = "default"; + alert("Success (sliceid=" + sliceid + ")\n\n" + response); + redirect(sliceid); + }, + onFailure: function(){ + document.body.style.cursor = "default"; + alert('Something went wrong...') + redirect(sliceid); + }, + }); } this.clear = function () { @@ -318,7 +347,7 @@ var lease_methods = { /* a text obj to display the name of the slice that owns that lease */ var otherslicelabel = paper.text (lease.attr("x")+lease.attr("width")/2, // xxx - lease.attr("y")+lease.attr("height")/2,slicename).attr(txt_slice); + lease.attr("y")+lease.attr("height")/2,slicename).attr(txt_otherslice); /* hide it right away */ otherslicelabel.hide(); /* record it */ @@ -344,11 +373,24 @@ function init_scheduler () { axisx.push(getInnerText(cell).split("&")); }); // leases - expect colspan to describe length in grains + // the text contents is expected to be lease_id & slicename table.getElementsBySelector("tbody>tr>td").each(function (cell) { - data.push(new Array (getInnerText(cell),cell.colSpan)); + var cell_data; + slice_attributes=getInnerText(cell).split('&'); + // booked leases come with lease id and slice name + if (slice_attributes.length == 2) { + // leases is booked : slice_id, slice_name, duration in grains + cell_data=new Array (slice_attributes[0], slice_attributes[1], cell.colSpan); + } else { + cell_data = new Array ('','',cell.colSpan); + } + data.push(cell_data); }); - // slicename : the upper-left cell - var scheduler = new Scheduler (getInnerText(table.getElementsBySelector("thead>tr>td")[0]), axisx, axisy, data); + // sliceid & slicename : the upper-left cell + var slice_attributes = getInnerText(table.getElementsBySelector("thead>tr>td")[0]).split('&'); + var sliceid=slice_attributes[0]; + var slicename=slice_attributes[1]; + var scheduler = new Scheduler (sliceid,slicename, axisx, axisy, data); table.hide(); // leases_area is a <div> created by slice.php as a placeholder scheduler.init ("leases_area"); diff --git a/planetlab/slices/slice.php b/planetlab/slices/slice.php index 74edc83..fbcc6d7 100644 --- a/planetlab/slices/slice.php +++ b/planetlab/slices/slice.php @@ -387,7 +387,8 @@ $toggle->end(); // (.) type is passed to the javascript table, for sorting (default is 'string') // minimal list as a start -$node_fixed_columns = array('hostname','node_id','peer_id','slice_ids_whitelist','run_level','boot_state','last_contact','node_type'); +$node_fixed_columns = array('hostname','node_id','peer_id','slice_ids_whitelist', + 'run_level','boot_state','last_contact','node_type'); // create a VisibleTags object : basically the list of tag columns to show $visibletags = new VisibleTags ($api, 'node'); $visiblecolumns = $visibletags->column_names(); @@ -398,9 +399,14 @@ $potential_nodes=$api->GetNodes(array('~node_id'=>$slice['node_ids']),$node_colu $reservable_nodes=array(); foreach ($nodes as $node) { if ($node['node_type']=='reservable') $reservable_nodes[]=$node; } +$reservable_mark="-R-"; +$reservable_legend="reservable nodes are marked with " . $reservable_mark; + //////////////////// -$count=count($nodes); -$toggle=new PlekitToggle ('my-slice-nodes',"$count Nodes", +// outline the number of reservable nodes +$nodes_message=count_english($nodes,"node"); +if (count($reservable_nodes)) $nodes_message .= " (" . count($reservable_nodes) . " reservable)"; +$toggle=new PlekitToggle ('my-slice-nodes',$nodes_message, array('bubble'=> 'Manage nodes attached to this slice', 'visible'=>get_arg('show_nodes',false))); @@ -418,7 +424,7 @@ $headers['peer']='string'; $headers['hostname']='string'; $short="ST"; $long=Node::status_footnote(); $type='string'; $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long"; -$short="R"; $long="reservable nodes"; $type='string'; +$short="R"; $long=$reservable_legend; $type='string'; $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long"; // the extra tags, configured for the UI $headers=array_merge($headers,$visibletags->headers()); @@ -441,7 +447,7 @@ if ($nodes) foreach ($nodes as $node) { $run_level=$node['run_level']; list($label,$class) = Node::status_label_class_($node); $table->cell ($label,array('class'=>$class)); - $table->cell( ($node['node_type']=='reservable')?"-R-":"" ); + $table->cell( ($node['node_type']=='reservable')?$reservable_mark:"" ); foreach ($visiblecolumns as $tagname) $table->cell($node[$tagname]); if ($privileges) $table->cell ($form->checkbox_html('node_ids[]',$node['node_id'])); @@ -485,7 +491,7 @@ if ($privileges) { $headers['hostname']='string'; $short="ST"; $long=Node::status_footnote(); $type='string'; $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long"; - $short="R"; $long="reservable nodes"; $type='string'; + $short="R"; $long=$reservable_legend; $type='string'; $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long"; // the extra tags, configured for the UI $headers=array_merge($headers,$visibletags->headers()); @@ -503,7 +509,7 @@ if ($privileges) { $table->cell(l_node_obj($node)); list($label,$class) = Node::status_label_class_($node); $table->cell ($label,array('class'=>$class)); - $table->cell( ($node['node_type']=='reservable')?"-R-":"" ); + $table->cell( ($node['node_type']=='reservable')?$reservable_mark:"" ); foreach ($visiblecolumns as $tagname) $table->cell($node[$tagname]); $table->cell ($form->checkbox_html('node_ids[]',$node['node_id'])); $table->row_end(); @@ -536,7 +542,7 @@ if ($count && $privileges) { $steps=$duration/$grain; $start=intval($now/$grain)*$grain; $end=$now+$duration; - $lease_columns=array('name','t_from','t_until','hostname','name'); + $lease_columns=array('lease_id','name','t_from','t_until','hostname','name'); $leases=$api->GetLeases(array(']t_until'=>$now,'[t_from'=>$end,'-SORT'=>'t_from'),$lease_columns); // hash nodes -> leases $host_hash=array(); @@ -553,7 +559,7 @@ if ($count && $privileges) { # leases_data is the name used by leases.js to locate this table echo "<table id='leases_data'>"; # pass the slicename as the [0,0] coordinate as thead>tr>td - echo "<thead><tr><td>" . $slice['name'] . "</td>"; + echo "<thead><tr><td>" . $slice['slice_id'] . '&' . $slice['name'] . "</td>"; for ($i=0; $i<$steps; $i++) // expose in each header cell the full timestamp, and how to display it - use & as a separator*/ echo "<th>" . ($start+$i*$grain) . "&" . strftime("%H:%M",$start+$i*$grain). "</th>"; @@ -576,7 +582,7 @@ if ($count && $privileges) { array_shift($leases); }*/ $duration=$lease['nuntil']-$counter; - echo "<td colspan='$duration'>" . $lease['name'] . "</td>"; + echo "<td colspan='$duration'>" . $lease['lease_id'] . '&' . $lease['name'] . "</td>"; $counter=$lease['nuntil']; } else { echo "<td></td>"; -- 2.47.0