} 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': {
}
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' :
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
font-style: italic;
padding: 20px 40px;
text-align: center;
- font-size: larger;
+/* font-size: smaller; */
}
p.node_download {
div#toggle-area-create-slice-details>table.plc_details {
margin:0 ;
}
+div#toggle-container-add-node,
+div#toggle-container-add-interface {
+ background-color: #e0d0ff;
+}
$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);
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"; }
/* 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);*/
// 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;
return (n == n_mask) ? masklen : -1;
}
-
// returns network and broadcast from ip and masklen
function get_derived (n,masklen) {
var n_mask = mask(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) {
}
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;
+ }
}
+
+
'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'];
<script type="text/javascript" src="/planetlab/nodes/interface.js"></script>
');
-$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();
// 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']));
$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':
//////////////////////////////////////// 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));
$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();
$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';
$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"));
// Common functions
require_once 'plc_functions.php';
+require_once 'toggle.php';
require_once 'details.php';
require_once 'form.php';
print <<< EOF
<p class='node_add'>
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.
<br/>
-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.
+<br/>
+ It is now reserved to admins, as regular users are supposed to use the register wizard, that among other things enforces PCU deployment.
+<br/>
+An IP address is required even if you use DHCP.
</p>
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();
$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';
$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,
// 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();
}
// 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
$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="<form method='$this->method' action='$this->url' enctype='multipart/form-data'>";
+ $html="<form method='$this->method' action='$this->url' enctype='multipart/form-data'";
+ if ($this->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);