From: Thierry Parmentelat Date: Fri, 20 Nov 2009 09:58:49 +0000 (+0000) Subject: add a non-primary interface : user to select for virtual or physical interface (set... X-Git-Tag: PLEWWW-4.3-39~4 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=25d98634e8ff1509901a8f1b44882e452b9131b7;p=plewww.git add a non-primary interface : user to select for virtual or physical interface (set ifname/alias) thoroughly rewrote the add-interface add-node javascript helpers form interface has changed, method now passed as part of an options hash, new options now supported more focused redirections after actions (prrof-of-concept, needs more work) node view mentions the number of tags for each interface for faster checks --- diff --git a/planetlab/common/actions.php b/planetlab/common/actions.php index b3a34ba..c93a326 100644 --- a/planetlab/common/actions.php +++ b/planetlab/common/actions.php @@ -421,8 +421,22 @@ switch ($action) { } else { $ip=$interface['ip']; drupal_set_message ("Interface $ip added into node $node_id"); + if ($_POST['is-virtual']) { + $ifname=$_POST['ifname']; + if ($api->AddInterfaceTag($interface_id,"ifname",$ifname) <= 0) + drupal_set_error ("Could not set tag 'ifname'=$ifname"); + else + drupal_set_message ("Set tag 'ifname'=$ifname"); + $alias=$_POST['alias']; + // deafult to interface_id + if ( ! $alias ) $alias=strval($interface_id); + if ($api->AddInterfaceTag($interface_id,"alias",$alias) <= 0) + drupal_set_error ("Could not set tag 'alias'=$alias"); + else + drupal_set_message ("Set tag 'alias'=$alias"); + } } - plc_redirect (l_node($node_id)); + plc_redirect (l_node_interfaces($node_id)); } case 'update-interface': { @@ -825,9 +839,9 @@ Our support team will be glad to answer any question that you might have. } if ($node_mode) - plc_redirect (l_node($node_id)); + plc_redirect (l_node_tags($node_id)); else - plc_redirect (l_interface($interface_id)); + plc_redirect (l_interface_tags($interface_id)); } case 'delete-node-tags' : @@ -862,9 +876,9 @@ Our support team will be glad to answer any question that you might have. else drupal_set_error ("Could not delete all selected tags, only $counter were removed"); if ($node_mode) - plc_redirect(l_node($_POST['node_id'])); + plc_redirect(l_node_tags($_POST['node_id'])); else - plc_redirect(l_interface($_POST['interface_id'])); + plc_redirect(l_interface_tags($_POST['interface_id'])); } //////////////////////////////////////// nodegroups diff --git a/planetlab/css/plc_style.css b/planetlab/css/plc_style.css index 4715bea..7e5472e 100644 --- a/planetlab/css/plc_style.css +++ b/planetlab/css/plc_style.css @@ -70,7 +70,7 @@ p.node_add { font-style: italic; padding: 20px 40px; text-align: center; - font-size: larger; +/* font-size: smaller; */ } p.node_download { @@ -149,3 +149,7 @@ div#toggle-area-create-slice-persons { div#toggle-area-create-slice-details>table.plc_details { margin:0 ; } +div#toggle-container-add-node, +div#toggle-container-add-interface { + background-color: #e0d0ff; +} diff --git a/planetlab/events/events_choser.php b/planetlab/events/events_choser.php index da53366..875f757 100644 --- a/planetlab/events/events_choser.php +++ b/planetlab/events/events_choser.php @@ -43,7 +43,7 @@ $from_picker->today(); $until_picker = new PlekitDatepicker ('until_date','Until (inclusive)',array('inline'=>true)); $until_picker->today(); -$form=new PlekitForm(l_events(),array(),'GET'); +$form=new PlekitForm(l_events(),array(),array('method'=>'get')); $form->start(); $details = new PlekitDetails (true); diff --git a/planetlab/includes/plc_functions.php b/planetlab/includes/plc_functions.php index 76c81e7..658cc86 100644 --- a/planetlab/includes/plc_functions.php +++ b/planetlab/includes/plc_functions.php @@ -78,6 +78,8 @@ function l_pcu ($pcu_id) { return "/db/sites/pcu.php?id=$pcu_id"; } function l_nodes () { return "/db/nodes/index.php"; } function l_nodes_peer ($peer_id) { return "/db/nodes/index.php?peerscope=$peer_id"; } function l_node ($node_id) { return "/db/nodes/node.php?id=$node_id"; } +function l_node_interfaces ($node_id) { return "/db/nodes/node.php?id=$node_id%show_details=0&show_interfaces=1"; } +function l_node_tags ($node_id) { return "/db/nodes/node.php?id=$node_id%show_details=0&show_tags=1"; } function l_node_t ($node_id,$text) { return href (l_node($node_id),$text); } function l_node_obj($node) { return href(l_node($node['node_id']),$node['hostname']); } function l_node_add () { return "/db/nodes/node_add.php"; } diff --git a/planetlab/nodes/interface.js b/planetlab/nodes/interface.js index 434333e..9e5c496 100644 --- a/planetlab/nodes/interface.js +++ b/planetlab/nodes/interface.js @@ -2,25 +2,8 @@ /* using prototype.js */ -/* disable/enable input fields according to the selected method */ -function updateMethodFields() { - var method=$('method'); - var index = method.selectedIndex; - var selectedText = method[index].text; - - var is_static = selectedText == 'Static'; - var is_tap = selectedText == 'TUN/TAP'; - - $('netmask').disabled= !is_static; - $('network').disabled= !is_static; - $('gateway').disabled= !is_static && !is_tap; - $('broadcast').disabled= !is_static; - $('dns1').disabled= !is_static; - $('dns2').disabled= !is_static; -} - -/* updates broadcast & network from IP and netmask, as long as they are reasonably set */ - +//////////////////// +// basic IP arithmetic /* a is assumed to be a 4-items array text.split('.') */ function arr_to_int (as) { /*a=as.map(parseInt);*/ @@ -51,9 +34,9 @@ function mask (masklen) { // input is the user-typed text // return the number of bits in the mask (like 24 for a /24) or -1 if the mask is wrong -function get_masklen (nm) { - var a = nm.split('.'); - if ( 4 != a.length ) return -1; +function get_masklen (netmask) { + var a = netmask.split('.'); + if ( IPCheckerAtom (netmask,'netmask')) return -1; var n = arr_to_int (a); var bits = int_to_bits (n); var masklen=0; @@ -63,7 +46,6 @@ function get_masklen (nm) { return (n == n_mask) ? masklen : -1; } - // returns network and broadcast from ip and masklen function get_derived (n,masklen) { var n_mask = mask(masklen); @@ -79,29 +61,52 @@ function same_subnet (ip1,ip2,masklen) { return (n1&mask(masklen)) == (n2 & mask(masklen)); } -function networkHelper () { - window.console.log('networkHelper'); - var ip=$('ip').value; - var nm=$('netmask').value; - - var ip_a = ip.split('.'); - var nm_a = ip.split('.'); - - /* don't trigger if the input does not make sense */ - if (ip_a.length != 4) return; - if (ip_a[3] == "") return; - if (nm_a.length != 4) return; - if (nm_a[3] == "") return; +//////////////////// basic chackers +function IPCheckerAtom (ip,id) { + if ( ! ip ) return "Empty field " + id; + ip_a = ip.split('.'); + if ( ip_a.length != 4) return "Invalid IP (" + id + ") "+ ip; + for (var i=0; i<4; i++) if (ip_a[i]<0 || ip_a[i]>256) return "Invalid IP (" + id + ") "+ ip; + return ""; +} - /*check netmask*/ - var masklen=get_masklen (nm); - if (masklen < 0) return; +function IPCheckerSilent (id) { return IPCheckerAtom ( $(id).value, id); } + +function netmaskCheckerSilent (id) { + var netmask=$(id).value; + var check_ip = IPCheckerAtom (netmask,'netmask'); + if (check_ip) return check_ip; + var masklen = get_masklen (netmask); + if (masklen <= 0) return "Invalid netmask " + netmask; + return ""; +} - var ip_n=arr_to_int(ip_a); - var derived = get_derived(ip_n,masklen); +// focus on the field to check, other ones checked already +function subnetChecker(id, optional) { + var error= subnetCheckerSilent($(id).value); + if (error) { + Form.Element.focus($(id)); + alert(error); + } +} - $('network').value=derived[0]; - $('broadcast').value=derived[1]; +function subnetCheckerSilent (id, optional) { + + var subnet=$(id).value; + // skip this field if optional + if (optional && (subnet=="")) return ""; + var check_ip = IPCheckerAtom (subnet,id); + if (check_ip) return check_ip; + + var masklen = get_masklen ($('netmask').value); + if (masklen < 0) return "Could not check " + id; + + var ip=$('ip').value; + + if ( ! same_subnet (ip,subnet,masklen) ) + return id + ' ' + subnet + ' is not in the /' + masklen + ' subnet range'; + + return ""; } function macChecker(id, optional) { @@ -113,53 +118,79 @@ function macChecker(id, optional) { } function macCheckerSilent(macAdd) { - var RegExPattern = /^[0-9a-fA-F:]+$/; - - if (!(macAdd.match(RegExPattern)) || macAdd.length != 17) - { - return "Invalid MAC Address"; - } else { - return ""; - } -} - -/* check one */ -function subnetChecker (id, optional) { - var error= subnetCheckerSilent([id,optional]); - if (error) { - Form.Element.focus($(id)); - alert(error); + var RegExPattern = /^[0-9a-fA-F:]+$/; + + if (!(macAdd.match(RegExPattern)) || macAdd.length != 17) { + return "Invalid MAC Address"; + } else { + return ""; } } -function subnetCheckerSilent (args) { +//////////////////// +// updates broadcast & network from IP and netmask, as long as they are reasonably set +function networkHelper () { + var ip=$('ip').value; + var netmask=$('netmask').value; + + /* don't trigger if the input does not make sense */ + if (IPCheckerAtom (ip,'ip')) return; + if (IPCheckerAtom (netmask,'netmask')) return; - id=args[0]; - optional=args[1]; + /*check netmask*/ + var masklen=get_masklen (netmask); + if (masklen <= 0) return; - var ip2=$(id).value; - if (optional && (ip2=="")) return ""; - if ( ip2.split(".").length != 4) return "Inconsistent value for " + id; + var ip_a = ip.split('.'); + var ip_n=arr_to_int(ip_a); + var derived = get_derived(ip_n,masklen); - var masklen = get_masklen ($('netmask').value); - if (masklen < 0) return "Inconsistent netmask"; + $('network').value=derived[0]; + $('broadcast').value=derived[1]; +} - var ip=$('ip').value; - if ( ip.split(".").length != 4) return "Inconsistent IP"; +// disable/enable input fields according to the selected method +function updateMethodFields() { + var method=$('method'); + var index = method.selectedIndex; + var selectedText = method[index].text; + var is_static = selectedText == 'Static'; + var is_tap = selectedText == 'TUN/TAP'; - if ( ! same_subnet (ip,ip2,masklen) ) - return id + ' ' + ip2 + ' is not in the /' + masklen + ' subnet range'; - - return ""; + $('netmask').disabled= !is_static; + $('network').disabled= !is_static; + $('gateway').disabled= !is_static && !is_tap; + $('broadcast').disabled= !is_static; + $('dns1').disabled= !is_static; + $('dns2').disabled= !is_static; } +// check inputs and prevent submit in case s/t is wrong function interfaceSubmit () { - alert ('submitting'); - // get error strings, and remove the empty ones - // dns2 is optional - var errors=['gateway','dns1','dns2'].zip ([true,true,false],subnetCheckerSilent).reject( function (s) {return s.length==0;} ); - if ( ! errors.length) - $('ip').up('form').submit(); - else - alert(errors.join("\n")); + + var method=$('method'); + var index = method.selectedIndex; + var selectedText = method[index].text; + var is_static = selectedText == 'Static'; + var is_tap = selectedText == 'TUN/TAP'; + + var errors=""; + var counter=0; + var error; + error = IPCheckerSilent ('ip'); if (error) errors += error + "\n" ; + if ( ! $('netmask').disabled ) { error = netmaskCheckerSilent ('netmask'); if (error) errors += error + "\n" ; } + if ( ! $('network').disabled ) { error = IPCheckerSilent ('network'); if (error) errors += error + "\n" ; } + if ( ! $('gateway').disabled ) { error = subnetCheckerSilent ('gateway',false); if (error) errors += error + "\n" ; } + if ( ! $('broadcast').disabled ) { error = subnetCheckerSilent ('broadcast',false); if (error) errors += error + "\n" ; } + if ( ! $('dns1').disabled ) { error = subnetCheckerSilent ('dns1',false); if (error) errors += error + "\n" ; } + if ( ! $('dns2').disabled ) { error = subnetCheckerSilent ('dns2',true); if (error) errors += error + "\n" ; } + + if ( ! errors.length) { + return true; + } else { + alert("-- Cannot create interface --\n" + errors); + return false; + } } + + diff --git a/planetlab/nodes/interface.php b/planetlab/nodes/interface.php index f9676ac..338b9b8 100644 --- a/planetlab/nodes/interface.php +++ b/planetlab/nodes/interface.php @@ -57,7 +57,8 @@ $fields=array( 'method', 'type', 'ip', 'gateway', 'network', 'broadcast', 'netma 'dns1', 'dns2', 'hostname', 'mac', 'bwlimit', 'node_id' ); ////////////////////////////// -$nodes= $api->GetNodes( array( intval($node_id) ), array( 'node_id', 'hostname', 'site_id' ) ); +$node_columns = array( 'node_id', 'hostname', 'site_id', 'interface_ids' ); +$nodes= $api->GetNodes( array( intval($node_id) ), $node_columns); $node= $nodes[0]; $site_id=$node['site_id']; @@ -71,7 +72,8 @@ drupal_set_html_head (' '); -$toggle = new PlekitToggle ('interface',"Details", +$nifty_id = ($mode == 'add' ) ? 'add-interface' : 'interface'; +$toggle = new PlekitToggle ($nifty_id,"Details", array('bubble'=>'Display and modify details for that interface', 'visible'=>get_arg('show_details',true))); $toggle->start(); @@ -81,12 +83,18 @@ $details=new PlekitDetails($can_update); // xxx hardwire network type for now $form_variables = array('node_id'=>$node_id,'type'=>"ipv4"); if ($mode == "update") $form_variables['interface_id']=$interface_id; -$form=$details->form_start(l_actions(),$form_variables); +$form=$details->form_start(l_actions(),$form_variables, + array('onSubmit'=>'return interfaceSubmit()')); $details->start(); +if ($mode == 'add') + // would have preferred 'dhcp' as a default but could not figure how to trigger updateMethodFields on startup + $method_default = 'static'; +else + $method_default = $interface['method']; $method_select = $form->select_html ("method", - interface_method_selectors($api,$interface['method'],false), + interface_method_selectors($api,$method_default,false), array('id'=>'method','onChange'=>'updateMethodFields()')); $details->th_td("Method",$method_select,"method",array('input_type'=>'select','value'=>$interface['method'])); @@ -113,17 +121,21 @@ $details->th_td("BW limit (bps)",$interface['bwlimit'],"bwlimit",array('width'=> $details->th_td("Hostname",$interface['hostname'],"hostname"); $details->th_td("Mac address",$interface['mac'],"mac", array('onChange'=>'macChecker("mac", true)')); -# xxx should the user be allowed to change this ? -//$mac=$interface['mac']; -//if ($mac) $details->th_td("MAC address",$mac); - // the buttons -$update_button = $form->submit_html ("update-interface","Update", - array('onSubmit'=>'interfaceSubmit()')); +$update_button = $form->submit_html ("update-interface","Update"); $add_button = $form->submit_html ("add-interface","Add as new", array('onSubmit'=>'interfaceSubmit()')); switch ($mode) { case 'add': + // primary interfaces can't be virtual + $is_primary = (count($node['interface_ids']) == 0); + if ( ! $is_primary) { + // default is to create virtual interfaces + $details->th_th($form->checkbox_html('is-virtual','yes',array('checked'=>'checked')), + "Virtual Interface"); + $details->th_td("Interface name","eth0",'ifname'); + $details->th_td("alias (leave empty if unsure)","",'alias'); + } $details->tr($add_button,"right"); break; case 'update': @@ -142,7 +154,7 @@ if ($mode == 'add') return; //////////////////////////////////////// tags $tags=$api->GetInterfaceTags (array('interface_id'=>$interface_id)); $toggle=new PlekitToggle ('tags',count_english($tags,'tag'), - array('visible'=>get_arg('show_tags',false))); + array('visible'=>get_arg('show_tags',true))); $toggle->start(); $form = new PlekitForm (l_actions(),array('interface_id'=>$interface_id)); diff --git a/planetlab/nodes/node.php b/planetlab/nodes/node.php index 11df5b8..7a863f9 100644 --- a/planetlab/nodes/node.php +++ b/planetlab/nodes/node.php @@ -349,7 +349,7 @@ if ( $local_peer ) { $tagnames = array_map ("get_tagname",$tags); $nodegroups_hash=plc_nodegroup_global_hash($api,$tagnames); - $toggle = new PlekitToggle ('tags',count_english_warning($tags,'tag'), + $toggle = new PlekitToggle ('tags',count_english($tags,'tag'), array('bubble'=>'Inspect and set tags on that node', 'visible'=>get_arg('show_tags',false))); $toggle->start(); @@ -432,6 +432,8 @@ if ( $local_peer ) { $headers["Type"]="string"; $headers["MAC"]="string"; $headers["bw limit"]="sortBandwidth"; + $headers["tags"]=array('type'=>'int', + 'title'=>"number of tags set on interface"); // a single symbol, marking 'p' for primary and a delete button for non-primary if ( $privileges ) $headers[plc_delete_icon()]='string'; @@ -451,6 +453,8 @@ if ( $local_peer ) { $table->cell($interface['type']); $table->cell($interface['mac']); $table->cell(pretty_bandwidth($interface['bwlimit'])); + $table->cell(href(l_interface_tags($interface_id), + count($interface['interface_tag_ids']))); if ( $privileges ) { if ($interface['is_primary']) { $table->cell(plc_bubble("p","Cannot delete a primary interface")); diff --git a/planetlab/nodes/node_add.php b/planetlab/nodes/node_add.php index 78b5e3b..63b9fd5 100644 --- a/planetlab/nodes/node_add.php +++ b/planetlab/nodes/node_add.php @@ -11,6 +11,7 @@ global $plc, $api; // Common functions require_once 'plc_functions.php'; +require_once 'toggle.php'; require_once 'details.php'; require_once 'form.php'; @@ -152,18 +153,28 @@ if( ! $model ) $model= "Custom"; print <<< EOF

This page lets you declare a new machine in your site. -This must be done before the machine is turned on, as it will allow you to download a boot image when complete for this node.
-You must enter an IP address even if you use DHCP. +This must be done before the machine is turned on, +as it will allow you to download a boot image when complete for this node. +
+ It is now reserved to admins, as regular users are supposed to use the register wizard, that among other things enforces PCU deployment. +
+An IP address is required even if you use DHCP.

EOF; +$toggle = new PlekitToggle ('add-node',"Add Node", + array('bubble'=>'Add a node - does not enforce PCU - for admins only !', + 'visible'=>get_arg('show_details',true))); +$toggle->start(); + $details=new PlekitDetails($has_privileges); // xxx hardwire network type for now $form_variables = array('type'=>"ipv4"); //$form=$details->form_start(l_actions(),$form_variables); -$form=$details->form_start('/db/nodes/node_add.php',$form_variables); +$form=$details->form_start('/db/nodes/node_add.php',$form_variables, + array('onSubmit'=>'return interfaceSubmit()')); $details->start(); @@ -198,12 +209,12 @@ $details->space(); $details->th_td("BW limit (bps)",$bwlimit,"bwlimit",array('width'=>11)); // the buttons -$add_button = $form->submit_html ("add-node","Add New Node", - array('onSubmit'=>'interfaceSubmit()')); +$add_button = $form->submit_html ("add-node","Add New Node"); $details->tr($add_button,"right"); -$details->end(); $form->end(); +$details->end(); +$toggle->end(); // Print footer include 'plc_footer.php'; diff --git a/planetlab/slices/slice_add.php b/planetlab/slices/slice_add.php index 4558e84..053f5cb 100644 --- a/planetlab/slices/slice_add.php +++ b/planetlab/slices/slice_add.php @@ -172,7 +172,7 @@ if ($multiple_sites) { $selectors []= $selector; } - $site_form = new PleKitForm (l_slice_add(),array(),'get'); + $site_form = new PleKitForm (l_slice_add(),array(),array('method'=>'get')); $site_form->start(); print $site_form->label_html('site_id','Or choose some other site'); print $site_form->select_html('site_id',$selectors,array('autosubmit'=>true, diff --git a/plekit/php/details.php b/plekit/php/details.php index 91dc7b7..bee9b5c 100644 --- a/plekit/php/details.php +++ b/plekit/php/details.php @@ -60,9 +60,9 @@ class PlekitDetails { // starts an inner form if the details are editable // accpets same args as PlekitForm - function form_start ($url,$values,$method="POST") { print $this->form_start_html($url,$values,$method); return $this->form; } - function form_start_html ($url,$values,$method="POST") { - $this->form = new PlekitForm ($url,$values,$method); + function form_start ($url,$values,$options=NULL) { print $this->form_start_html($url,$values,$options); return $this->form; } + function form_start_html ($url,$values,$options=NULL) { + $this->form = new PlekitForm ($url,$values,$options); return $this->form->start_html(); } diff --git a/plekit/php/form.php b/plekit/php/form.php index 4d5e9fd..f12d53e 100644 --- a/plekit/php/form.php +++ b/plekit/php/form.php @@ -12,9 +12,11 @@ class PlekitForm { // mandatory var $url; var $values; // a hash var=>value - default is empty array - var $method; // default is POST + var $method; // default is POST, can be changed with options + var $onSubmit; // can be set with options + var $onReset; // can be set with options - function PlekitForm ($full_url, $values, $method="POST") { + function PlekitForm ($full_url, $values, $options=NULL) { // so we can use the various l_* functions: // we parse the url to extract var-values pairs, // and add them to the 'values' argument if any @@ -29,12 +31,17 @@ class PlekitForm { $this->values=$values; // make strict xhtml happy - $this->method=strtolower($method); + $this->method="post"; if ($options['method']) $this->method=strtolower($options['method']); + $this->onSubmit=NULL; if ($options['onSubmit']) $this->onSubmit=$options['onSubmit']; + $this->onReset=NULL; if ($options['onReset']) $this->onReset=$options['onReset']; } function start () { print $this->start_html(); } function start_html () { - $html="
"; + $html="onSubmit) $html .= " onSubmit='$this->onSubmit'"; + if ($this->onReset) $html .= " onReset='$this->onReset'"; + $html .= ">"; if ($this->values) foreach ($this->values as $key=>$value) $html .= $this->hidden_html($key,$value);