+ $new_potential_nodes = array();
+ if ($potential_nodes) {
+ foreach ($potential_nodes as $node) {
+ $emptywl = empty($node['slice_ids_whitelist']);
+ $inwl = (!$emptywl) and in_array($slice['slice_id'], $node['slice_ids_whitelist']);
+ if ($emptywl or $inwl) {
+ $new_potential_nodes[] = $node;
+ }
+
+ }
+ }
+
+ $potential_nodes = $new_potential_nodes;
+
+ $count = count($potential_nodes);
+ $toggle_nodes = new PlekitToggle('my-slice-nodes-add',
+ count_english($potential_nodes, "more node") . " available",
+ array('visible' => get_arg('show_nodes_add')));
+ $toggle_nodes->start();
+
+ if ($potential_nodes) {
+ $headers = array();
+ $notes = array();
+
+/*
+$headers['peer']='string';
+$headers['hostname']='string';
+$short="-S-"; $long=Node::status_footnote(); $type='string';
+$headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
+$short=reservable_mark(); $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());
+$headers['+']="none";
+ */
+
+ $add_header = array();
+ $add_header['+'] = "none";
+ $headers = array_merge($ConfigureColumns->get_headers(), $add_header);
+
+ //$notes=array_merge($notes,$visibletags->notes());
+ $notes[] = "For information about the different columns please see the <b>node table layout</b> tab above or <b>mouse over</b> the column headers";
+
+ $table = new PlekitTable('add_nodes', $headers, null, $table_options);
+ $form = new PlekitForm(l_actions(),
+ array('slice_id' => $slice['slice_id']));
+ $form->start();
+ $table->start();
+ if ($potential_nodes) {
+ foreach ($potential_nodes as $node) {
+ $table->row_start();
+
+ $table->cell($node['node_id'], array('display' => 'none'));
+
+ $table->cell(l_node_obj($node));
+ $peers->cell($table, $node['peer_id']);
+ list($label, $class) = Node::status_label_class_($node);
+ $table->cell($label, array('class' => $class));
+ $table->cell(($node['node_type'] == 'reservable') ? reservable_mark() : "");
+
+ //extra columns
+ $hostname = $node['hostname'];
+ $ip = $interface_hash[$node['node_id']]['ip'];
+ $interface_id = $interface_hash[$node['node_id']]['interface_id'];
+ $node['domain'] = topdomain($hostname);
+ $node['sitename'] = l_site_t($node['site_id'], $site_hash[$node['site_id']]);
+ $node['ipaddress'] = l_interface_t($interface_id, $ip);
+
+ //foreach ($visiblecolumns as $tagname) $table->cell($node[$tagname]);
+ $ConfigureColumns->cells($table, $node);
+
+ $table->cell($form->checkbox_html('node_ids[]', $node['node_id']));
+ $table->row_end();
+ }
+ }
+
+ // add nodes
+ $table->tfoot_start();
+ $table->row_start();
+ $table->cell($form->submit_html("add-nodes-in-slice", "Add selected"),
+ array('hfill' => true, 'align' => 'right'));
+ $table->row_end();
+ $table->end();
+ $form->end();
+ }
+ $toggle_nodes->end();
+}
+
+$toggle->end();
+
+if ($profiling) {
+ plc_debug_prof('12: nodes to add', count($potential_nodes));
+}
+
+//////////////////////////////////////// retrieve all slice tags
+$tags = $api->GetSliceTags(array('slice_id' => $slice_id));
+//////////////////////////////////////////////////////////// tab:initscripts
+// xxx fixme
+// * add a message on how to use this:
+// * explain the 2 mechanisms (initscript_code, initscript)
+// * explain the interface : initscript start|stop|restart slicename
+// xxx fixme
+
+$initscript_info = "
+There are two ways to attach an initscript to a slice:<ul>
+
+<li> <span class='bold'> Shared initscripts </span> are global to the
+MyPLC, and managed by the Operations Team. For that reason, regular
+users cannot change these scripts, but can reference one of the
+available names in the drop down below. </li>
+
+<li> You also have the option to provide <span class='bold'> your own
+code </span>, with the following conventions: <ul>
+
+<li> Like regular initscripts, your script must expect to receive as a
+first argument <span class='bold'> start </span>, <span class='bold'>
+stop </span> or <span class='bold'> restart </span>. It is important
+to honor this argument, as your slice may be stopped and restarted at
+any time; also this is used whenever the installed code gets changed.
+</li>
+
+<li> As a second argument, you will receive the slicename; in most
+cases this can be safely ignored. </li>
+
+</ul>
+</li>
+ </ul>
+The slice-specific setting has precedence on a shared initscript.
+";
+
+$shared_initscripts = $api->GetInitScripts(array('-SORT' => 'name'), array('name'));
+//$shared_initscripts=$api->GetInitScripts();
+if ($profiling) {
+ plc_debug_prof('13: initscripts', count($initscripts));
+}
+
+// xxx expose this even on foreign slices for now
+if ($local_peer) {
+ $initscript = '';
+ $initscript_code = '';
+ if ($tags) {
+ foreach ($tags as $tag) {
+ if ($tag['tagname'] == 'initscript') {
+ if ($initscript != '') {
+ drupal_set_error("multiple occurrences of 'initscript' tag");
+ }
+
+ $initscript = $tag['value'];
+ }
+ if ($tag['tagname'] == 'initscript_code') {
+ if ($initscript_code != '') {
+ drupal_set_error("multiple occurrences of 'initscript_code' tag");
+ }
+
+ $initscript_code = $tag['value'];
+ // plc_debug_txt('retrieved body',$initscript_code);
+ }
+ }
+ }
+
+ $label = "No initscript";
+ $trimmed = trim($initscript_code);
+ if (!empty($trimmed)) {
+ $label = "Initscript : slice-specific (" . substr($initscript_code, 0, 20) . " ...)";
+ } else if (!empty($initscript)) {
+ $label = "Initscript: shared " . $initscript;
+ }
+
+ $toggle = new PlekitToggle('slice-initscripts', $label,
+ array('bubble' => 'Manage initscript on that slice',
+ 'visible' => get_arg('show_initscripts'),
+ 'info-text' => $initscript_info,
+ // not messing with persontags to guess whether this should be displayed or not
+ // hopefully some day toggle will know how to handle that using web storage
+ ));
+ $toggle->start();
+
+ $details = new PlekitDetails(true);
+ // we expose the previous values so that actions.php can know if changes are really needed
+ // the code needs to be encoded as it may contain any character
+ // as far as the code, this does not work too well b/c what actions.php receives
+ // seems to have spurrious \r chars, and the comparison between old and new values
+ // is not reliable, which results in changes being made although the code hasn't changed
+ // hve spent too much time on this, good enough for now...
+ $details->form_start(l_actions(), array('action' => 'update-initscripts',
+ 'slice_id' => $slice_id,
+ 'name' => $name,
+ 'previous-initscript' => $initscript,
+ 'previous-initscript-code' => htmlentities($initscript_code)));
+ $details->start();
+ // comppute a pulldown with available names
+ $selectors = array();
+ $is_found = false;
+ if ($shared_initscripts) {
+ foreach ($shared_initscripts as $is) {
+ $is_selector = array('display' => $is['name'], 'value' => $is['name']);
+ if ($is['name'] == $initscript) {
+ $is_selector['selected'] = true;
+ $is_found = true;
+ }
+ $selectors[] = $is_selector;
+ }
+ }
+
+ // display a warning when initscript references an unknown script
+ $details->tr_submit('unused', 'Update initscripts');
+ ////////// by name
+ $details->th_td("shared initscript name",
+ $details->form()->select_html('initscript', $selectors, array('label' => 'none')),
+ 'initscript',
+ array('input_type' => 'select'));
+ if ($initscript && !$is_found)
+ // xxx better rendering ?
+ {
+ $details->th_td('WARNING', plc_warning_html("Current name '" . $initscript . "' is not a known shared initscript name"));
+ }
+
+ ////////// by contents
+ $script_height = 8;
+ $script_width = 60;
+ if ($initscript_code) {
+ $text = explode("\n", $initscript_code);
+ $script_height = count($text);
+ $script_width = 10;
+ foreach ($text as $line) {
+ $script_width = max($script_width, strlen($line));
+ }
+
+ }
+ $details->th_td('slice initscript', $initscript_code, 'initscript-code',
+ array('input_type' => 'textarea', 'width' => $script_width, 'height' => $script_height));
+ $details->tr_submit('unused', 'Update initscripts');
+ $details->form_end();
+ $details->end();
+ $toggle->end();
+}
+
+//////////////////////////////////////////////////////////// tab:tags
+// very wide values get abbreviated
+$tag_value_threshold = 24;
+// xxx fixme
+// * this area could use a help message about some special tags:
+// * initscript-related should be taken out
+// * sliverauth-related (ssh_key & hmac) should have a toggle to hide or show
+// xxx fixme
+
+// xxx expose this even on foreign slices for now
+//if ( $local_peer ) {
+if ($profiling) {
+ plc_debug_prof('14: slice tags', count($tags));
+}
+
+function get_tagname($tag)
+{return $tag['tagname'];}
+$tagnames = array_map("get_tagname", $tags);
+
+$toggle = new PlekitToggle('slice-tags', count_english_warning($tags, 'tag'),
+ array('bubble' => 'Inspect and set tags on that slice',
+ 'visible' => get_arg('show_tags')));
+$toggle->start();
+
+$headers = array(
+ "Name" => "string",
+ "Value" => "string",
+ "Node" => "string",
+ "NodeGroup" => "string");
+if ($tags_privileges) {
+ $headers[plc_delete_icon()] = "none";
+}
+
+$table_options = array("notes_area" => false, "pagesize_area" => false, "search_width" => 10);
+$table = new PlekitTable("slice_tags", $headers, '0', $table_options);
+$form = new PlekitForm(l_actions(),
+ array('slice_id' => $slice['slice_id']));
+$form->start();
+$table->start();
+if ($tags) {
+ // Get hostnames for nodes in a single pass
+ $_node_ids = array();
+ foreach ($tags as $tag) {
+ if ($tag['node_id']) {
+ array_push($_node_ids, $tag['node_id']);
+ }
+ }
+ $_nodes = $api->GetNodes(array('node_id' => $_node_ids), array('node_id', 'hostname'));
+ $_hostnames = array();
+ if ($_nodes) {
+ foreach ($_nodes as $_node) {
+ $_hostnames[$_node['node_id']] = $_node['hostname'];
+ }
+ }
+
+ // Loop through tags again to display
+ foreach ($tags as $tag) {
+ $node_name = "ALL";
+ if ($tag['node_id']) {
+ $node_name = $_hostnames[$tag['node_id']];
+ }
+ $nodegroup_name = "n/a";
+ if ($tag['nodegroup_id']) {
+ $nodegroups = $api->GetNodeGroups(array('nodegroup_id' => $tag['nodegroup_id']));
+ if ($profiling) {
+ plc_debug_prof('15: nodegroup for slice tag', $nodegroup);
+ }
+
+ if ($nodegroup) {
+ $nodegroup = $nodegroups[0];
+ $nodegroup_name = $nodegroup['groupname'];
+ }
+ }
+ $table->row_start();
+ $table->cell(l_tag_obj($tag));
+ // very wide values get abbreviated
+ $table->cell(truncate_and_popup($tag['value'], $tag_value_threshold));
+ $table->cell($node_name);
+ $table->cell($nodegroup_name);
+ if ($tags_privileges) {
+ $table->cell($form->checkbox_html('slice_tag_ids[]', $tag['slice_tag_id']));
+ }
+
+ $table->row_end();
+ }
+}
+if ($tags_privileges) {