get rid of all trace or error_reporting even under commented form
[plewww.git] / planetlab / slices / slice.php
1 <?php
2
3 // Require login
4 require_once 'plc_login.php';
5
6 // Get session and API handles
7 require_once 'plc_session.php';
8 global $plc, $api;
9
10 // Print header
11 require_once 'plc_drupal.php';
12 include 'plc_header.php';
13
14 // Common functions
15 require_once 'plc_functions.php';
16 require_once 'plc_peers.php';
17 require_once 'plc_objects.php';
18 require_once 'plc_visibletags2.php';
19 require_once 'linetabs.php';
20 require_once 'table2.php';
21 require_once 'details.php';
22 require_once 'toggle.php';
23 require_once 'form.php';
24 require_once 'raphael.php';
25 require_once 'columns.php';
26
27 // keep css separate for now
28 drupal_set_html_head('
29 <link href="/planetlab/css/my_slice.css" rel="stylesheet" type="text/css" />
30 ');
31
32
33 $profiling=false;
34 if ($get_array($_GET, 'profiling')) $profiling=true;
35
36 if ($profiling)  plc_debug_prof_start();
37
38 // --------------------
39 // recognized URL arguments
40 $slice_id=intval($get_array($_GET, 'id'));
41 if ( ! $slice_id ) { plc_error('Malformed URL - id not set'); return; }
42
43 ////////////////////
44 // have to name columns b/c we need the non-native 'omf_control' column
45 $slice_columns=array('slice_id','name','peer_id','site_id','person_ids','node_ids','expires',
46                      'url','description','instantiation','omf_control');
47 $slices= $api->GetSlices( array($slice_id), $slice_columns);
48
49 if (empty($slices)) {
50   drupal_set_message ("Slice " . $slice_id . " not found");
51   return;
52  }
53
54 $slice=$slices[0];
55
56 if ($profiling) plc_debug_prof('01: slice',count($slices));
57 // pull all node info to vars
58 $name= $slice['name'];
59 $expires = date( "d/m/Y", $slice['expires'] );
60 $site_id= $slice['site_id'];
61
62 $person_ids=$slice['person_ids'];
63
64 // get peers
65 $peer_id= $slice['peer_id'];
66 $peers=new Peers ($api);
67 $local_peer = ! $peer_id;
68
69 if ($profiling) plc_debug_prof('02: peers',count($peers));
70
71 // gets site info
72 $sites= $api->GetSites( array( $site_id ) );
73 $site=$sites[0];
74 $site_name= $site['name'];
75 $max_slices = $site['max_slices'];
76
77 if ($profiling) plc_debug_prof('03: sites',count($sites));
78 //////////////////////////////////////// building blocks for the renew area
79 // Constants
80 global $DAY;            $DAY = 24*60*60;
81 global $WEEK;           $WEEK = 7 * $DAY;
82 global $MAX_WEEKS;      $MAX_WEEKS= 8;          // weeks from today
83 global $GRACE_DAYS;     $GRACE_DAYS=10;         // days for renewal promoted on top
84 global $NOW;            $NOW=time();
85
86 //////////////////////////////////////////////////////////// utility for the renew tab
87 // make the renew area on top and open if the expiration time is less than 10 days from now
88 function renew_needed ($slice) {
89   global $DAY, $NOW, $GRACE_DAYS;
90   $current_exp=$slice['expires'];
91
92   $time_left = $current_exp - $NOW;
93   $visible = $time_left/$DAY <= $GRACE_DAYS;
94   return $visible;
95 }
96
97 function renew_area ($slice,$site,$visible) {
98   global $DAY, $WEEK, $MAX_WEEKS, $GRACE_DAYS, $NOW;
99
100   $current_exp=$slice['expires'];
101   $current_text = gmstrftime("%A %b-%d-%y %T %Z", $current_exp);
102   $max_exp= $NOW + ($MAX_WEEKS * $WEEK); // seconds since epoch
103   $max_text = gmstrftime("%A %b-%d-%y %T %Z", $max_exp);
104
105   // xxx some extra code needed to enable this area only if the slice description is OK:
106   // description and url must be non void
107   $toggle=
108     new PlekitToggle('renew',"Expires $current_text - Renew this slice",
109                      array("bubble"=>
110                            "Enter this zone if you wish to renew your slice",
111                            'visible'=>$visible));
112   $toggle->start();
113
114   // xxx message could take roles into account
115   if ($site['max_slices']<=0) {
116      $message= <<< EOF
117 <p class='my-slice-renewal'>Slice creation and renewal have been temporarily disabled for your
118 <site. This may have occurred because your site's nodes have been down
119 or unreachable for several weeks, and multiple attempts to contact
120 your site's PI(s) and Technical Contact(s) have all failed. If so,
121 contact your site's PI(s) and Technical Contact(s) and ask them to
122 bring up your site's nodes. Please visit your <a
123 href='/db/sites/index.php?id=$site_id'>site details</a> page to find
124 out more about your site's nodes, and how to contact your site's PI(s)
125 and Technical Contact(s).</p>
126 EOF;
127      echo $message;
128
129   } else {
130     // xxx this is a rough cut and paste from the former UI
131     // showing a datepicker view could be considered as well with some extra work
132     // calculate possible extension lengths
133     $selectors = array();
134     foreach ( array ( 1 => "One more week",
135                       2 => "Two more weeks",
136                       3 => "Three more weeks",
137                       4 => "One more month" ) as $weeks => $text ) {
138       $candidate_exp = $current_exp + $weeks*$WEEK;
139       if ( $candidate_exp < $max_exp) {
140         $selectors []= array('display'=>"$text (" . gmstrftime("%A %b-%d-%y %T %Z", $candidate_exp) . ")",
141                              'value'=>$candidate_exp);
142         $max_renewal_weeks=$weeks;
143         $max_renewal_date= gmstrftime("%A %b-%d-%y %T %Z", $candidate_exp);
144       }
145     }
146
147     if ( empty( $selectors ) ) {
148       print <<< EOF
149 <div class='my-slice-renewal'>
150 Slices cannot be renewed more than $MAX_WEEKS weeks from now, i.e. not beyond $max_text.
151 For this reason, the current slice cannot be renewed any further into the future, try again closer to expiration date.
152 </div>
153 EOF;
154      } else {
155       print <<< EOF
156 <div class='my-slice-renewal'>
157 <span class='bold'>Important:</span> Please take this opportunity to review and update your slice information in the Details tab.
158 <p>
159 PlanetLab's security model requires that anyone who is concerned about a slice's activity be able to immediately learn about that slice. The details that you provide are your public explanation about why the slice behaves as it does. Be sure to describe the <span class='bold'>kind of traffic</span> that your slice generates, and how it handles material that is under <span class='bold'>copyright</span>, if relevant.
160 </p><p>
161 The PlanetLab Operations Centres regularly respond to concerns raised by third parties about site behaviour. Most incidents are resolved rapidly based upon the publicly posted slice details. However, when these details are not sufficiently clear or accurate, and we cannot immediately reach the slice owner, we must delete the slice.
162 </p>
163 EOF;
164
165       $form = new PlekitForm (l_actions(),
166                               array('action'=>'renew-slice',
167                                     'slice_id'=>$slice['slice_id']));
168       $form->start();
169       print $form->label_html('expires','Duration:&nbsp;');
170       print $form->select_html('expires',$selectors,array('label'=>'Pick one'));
171       print $form->submit_html('renew-button','Renew');
172       $form->end();
173
174 print("<p><i>NOTE: Slices cannot be renewed beyond another $max_renewal_weeks week(s) ($max_renewal_date).</i>  </p>");
175 print ("</div>");
176     }
177   }
178
179   $toggle->end();
180 }
181
182 ////////////////////////////////////////////////////////////
183
184 $am_in_slice = in_array(plc_my_person_id(),$person_ids);
185
186 if ($am_in_slice) {
187   drupal_set_title("My slice " . $name);
188  } else {
189   drupal_set_title("Slice " . $name);
190 }
191
192 $privileges = ( $local_peer && (plc_is_admin()  || plc_is_pi() || $am_in_slice));
193 $tags_privileges = $privileges || plc_is_admin();
194
195 $tabs=array();
196 $tabs [] = tab_nodes_slice($slice_id);
197 $tabs [] = tab_site($site);
198
199 // are these the right privileges for deletion ?
200 if ($privileges) {
201   $tabs ['Delete']= array('url'=>l_actions(),
202                           'method'=>'post',
203                           'values'=>array('action'=>'delete-slice','slice_id'=>$slice_id),
204                           'bubble'=>"Delete slice $name",
205                           'confirm'=>"Are you sure to delete slice $name");
206
207   $tabs["Events"]=array_merge(tablook_event(),
208                               array('url'=>l_event("Slice","slice",$slice_id),
209                                     'bubble'=>"Events for slice $name"));
210   $tabs["Comon"]=array_merge(tablook_comon(),
211                              array('url'=>l_comon("slice_id",$slice_id),
212                                    'bubble'=>"Comon page about slice $name"));
213 }
214
215 plekit_linetabs($tabs);
216
217 ////////////////////////////////////////
218 $peers->block_start($peer_id);
219
220 //////////////////////////////////////// renewal area
221 // (1) close to expiration : show on top and open
222
223 if ($local_peer ) {
224   $renew_visible = renew_needed ($slice);
225   if ($renew_visible) renew_area ($slice,$site,true);
226  }
227
228
229 //////////////////////////////////////////////////////////// tab:details
230 $toggle =
231   new PlekitToggle ('my-slice-details',"Details",
232                     array('bubble'=>
233                           'Display and modify details for that slice',
234                           'visible'=>get_arg('show_details')));
235 $toggle->start();
236
237 $details=new PlekitDetails($privileges);
238 $details->form_start(l_actions(),array('action'=>'update-slice',
239                                        'slice_id'=>$slice_id,
240                                        'name'=>$name));
241
242 $details->start();
243 if (! $local_peer) {
244   $details->th_td("Peer",$peers->peer_link($peer_id));
245   $details->space();
246  }
247
248
249 $details->th_td('Name',$slice['name']);
250 $details->th_td('Description',$slice['description'],'description',
251                 array('input_type'=>'textarea',
252                       'width'=>50,'height'=>5));
253 $details->th_td('URL',$slice['url'],'url',array('width'=>50));
254 $details->tr_submit("submit","Update Slice");
255 $details->th_td('Expires',$expires);
256 $details->th_td('Instantiation',$slice['instantiation']);
257 $details->th_td("OMF-friendly", ($slice['omf_control'] ? 'Yes' : 'No') . " [to change: see 'omf_control' in the tags section below]");
258 $details->th_td('Site',l_site_obj($site));
259 // xxx show the PIs here
260 //$details->th_td('PIs',...);
261 $details->end();
262
263 $details->form_end();
264 $toggle->end();
265
266 //////////////////////////////////////////////////////////// tab:persons
267 $person_columns = array('email','person_id','first_name','last_name','roles');
268 // get persons in slice
269 if (!empty($person_ids))
270   $persons=$api->GetPersons(array('person_id'=>$slice['person_ids']),$person_columns);
271 // just propose to add everyone else
272 // xxx this is maybe too much for admins as it slows stuff down
273 // as regular persons can see only a fraction of the db anyway
274 $potential_persons=
275   $api->GetPersons(array('~person_id'=>$slice['person_ids'],
276                          'peer_id'=>NULL,
277                          'enabled'=>true),
278                    $person_columns);
279 $count=count($persons);
280
281 if ($profiling) plc_debug_prof('04: persons',count($persons));
282 $toggle=
283   new PlekitToggle ('my-slice-persons',"$count users",
284                     array('bubble'=>
285                           'Manage accounts attached to this slice',
286                           'visible'=>get_arg('show_persons')));
287 $toggle->start();
288
289 ////////// people currently in
290 // visible:
291 // hide if both current+add are included
292 // so user can chose which section is of interest
293 // show otherwise
294 $toggle_persons = new PlekitToggle ('my-slice-persons-current',
295                                     "$count people currently in $name",
296                                     array('visible'=>get_arg('show_persons_current')));
297 $toggle_persons->start();
298
299 $headers=array();
300 $headers['email']='string';
301 $headers['first']='string';
302 $headers['last']='string';
303 $headers['R']='string';
304 if ($privileges) $headers[plc_delete_icon()]="none";
305 $table=new PlekitTable('persons',$headers,'0',
306                        array('notes_area'=>false));
307 $form=new PlekitForm(l_actions(),array('slice_id'=>$slice['slice_id']));
308 $form->start();
309 $table->start();
310 if ($persons) foreach ($persons as $person) {
311   $table->row_start();
312   $table->cell(l_person_obj($person));
313   $table->cell($person['first_name']);
314   $table->cell($person['last_name']);
315   $table->cell(plc_vertical_table ($person['roles']));
316   if ($privileges) $table->cell ($form->checkbox_html('person_ids[]',$person['person_id']));
317   $table->row_end();
318 }
319 // actions area
320 if ($privileges) {
321
322   // remove persons
323   $table->tfoot_start();
324
325   $table->row_start();
326   $table->cell($form->submit_html ("remove-persons-from-slice","Remove selected"),
327                array('hfill'=>true,'align'=>'right'));
328   $table->row_end();
329  }
330 $table->end();
331 $toggle_persons->end();
332
333 ////////// people to add
334 if ($privileges) {
335   $count=count($potential_persons);
336   $toggle_persons = new PlekitToggle ('my-slice-persons-add',
337                                       "$count people may be added to $name",
338                                       array('visible'=>get_arg('show_persons_add')));
339   $toggle_persons->start();
340   if ( ! $potential_persons ) {
341     // xxx improve style
342     echo "<p class='not-relevant'>No person to add</p>";
343   } else {
344     $headers=array();
345     $headers['email']='string';
346     $headers['first']='string';
347     $headers['last']='string';
348     $headers['R']='string';
349     $headers['+']="none";
350     $options = array('notes_area'=>false,
351                      'search_width'=>15,
352                      'pagesize'=>8);
353     // show search for admins only as other people won't get that many names to add
354     if ( ! plc_is_admin() ) $options['search_area']=false;
355
356     $table=new PlekitTable('add_persons',$headers,'0',$options);
357     $form=new PlekitForm(l_actions(),array('slice_id'=>$slice['slice_id']));
358     $form->start();
359     $table->start();
360     if ($potential_persons) foreach ($potential_persons as $person) {
361         $table->row_start();
362         $table->cell(l_person_obj($person));
363         $table->cell($person['first_name']);
364         $table->cell($person['last_name']);
365         $table->cell(plc_vertical_table ($person['roles']));
366         $table->cell ($form->checkbox_html('person_ids[]',$person['person_id']));
367         $table->row_end();
368       }
369     // add users
370     $table->tfoot_start();
371     $table->row_start();
372     $table->cell($form->submit_html ("add-persons-in-slice","Add selected"),
373                  array('hfill'=>true,'align'=>'right'));
374     $table->row_end();
375     $table->end();
376     $form->end();
377   }
378   $toggle_persons->end();
379 }
380 $toggle->end();
381
382 //////////////////////////////////////////////////////////// tab:nodes
383 // the nodes details to display here
384 // (1) we search for the tag types for which 'category' matches 'node*/ui*'
385 // all these tags will then be tentatively displayed in this area
386 // (2) further information can also be optionally specified in the category:
387 //     (.) we split the category with '/' and search for assignments of the form var=value
388 //     (.) header can be set to supersede the column header (default is tagname)
389 //     (.) rank can be used for ordering the columns (default is tagname)
390 //     (.) type is passed to the javascript table, for sorting (default is 'string')
391
392 // minimal list as a start
393 $node_fixed_columns = array('hostname','node_id','peer_id','slice_ids_whitelist', 'site_id',
394                             'run_level','boot_state','last_contact','node_type');
395 // create a VisibleTags object : basically the list of tag columns to show
396 //$visibletags = new VisibleTags ($api, 'node');
397 //$visiblecolumns = $visibletags->column_names();
398
399 // optimizing calls to GetNodes
400 //$all_nodes=$api->GetNodes(NULL,$node_columns);
401 //$slice_nodes=$api->GetNodes(array('node_id'=>$slice['node_ids']),$node_columns);
402 //$potential_nodes=$api->GetNodes(array('~node_id'=>$slice['node_ids']),$node_columns);
403
404
405 //NEW CODE FOR ENABLING COLUMN CONFIGURATION
406
407 //prepare fix and configurable columns
408
409 $fix_columns = array();
410 $fix_columns[]=array('tagname'=>'hostname', 'header'=>'hostname', 'type'=>'string', 'title'=>'The name of the node');
411 $fix_columns[]=array('tagname'=>'peer_id', 'header'=>'AU', 'type'=>'string', 'title'=>'Authority');
412 $fix_columns[]=array('tagname'=>'run_level', 'header'=>'ST', 'type'=>'string', 'title'=>'Status');
413 $fix_columns[]=array('tagname'=>'node_type', 'header'=>'RES', 'type'=>'string', 'title'=>'Reservable');
414
415 // columns that correspond to the visible tags for nodes (*node/ui*)
416 $visibletags = new VisibleTags ($api, 'node');
417 $visibletags->columns();
418 $tag_columns = $visibletags->headers();
419
420 //columns that are not defined as extra myslice tags
421 $extra_columns = array();
422 //MyPLC columns
423 $extra_columns[]=array('tagname'=>'sitename', 'header'=>'SN', 'type'=>'string', 'title'=>'Site name', 'fetched'=>true, 'source'=>'myplc');
424 $extra_columns[]=array('tagname'=>'domain', 'header'=>'DN', 'type'=>'string', 'title'=>'Toplevel domain name', 'fetched'=>true, 'source'=>'myplc');
425 $extra_columns[]=array('tagname'=>'ipaddress', 'header'=>'IP', 'type'=>'string', 'title'=>'IP Address', 'fetched'=>true, 'source'=>'myplc');
426 $extra_columns[]=array('tagname'=>'fcdistro', 'header'=>'OS', 'type'=>'string', 'title'=>'Operating system', 'fetched'=>false, 'source'=>'myplc');
427 $extra_columns[]=array('tagname'=>'date_created', 'header'=>'DA', 'source'=>'myplc', 'type'=>'date', 'title'=>'Date added', 'fetched'=>false);
428 $extra_columns[]=array('tagname'=>'arch', 'header'=>'A', 'source'=>'myplc', 'type'=>'string', 'title'=>'Architecture', 'fetched'=>false);
429 if (plc_is_admin()) {
430 $extra_columns[]=array('tagname'=>'deployment', 'header'=>'DL', 'source'=>'myplc', 'type'=>'string', 'title'=>'Deployment', 'fetched'=>false);
431 }
432
433 //CoMon Live data
434
435 if (MYSLICE_COMON_AVAILABLE)
436 {
437 $extra_columns[]=array('tagname'=>'bwlimit', 'header'=>'BW', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Bandwidth limit', 'fetched'=>false);
438 $extra_columns[]=array('tagname'=>'numcores', 'header'=>'CC', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Number of CPU Cores', 'fetched'=>false);
439 $extra_columns[]=array('tagname'=>'cpuspeed', 'header'=>'CR', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'CPU clock rate', 'fetched'=>false);
440 $extra_columns[]=array('tagname'=>'disksize', 'header'=>'DS', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Disk size', 'fetched'=>false);
441 $extra_columns[]=array('tagname'=>'gbfree', 'header'=>'DF', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Currently available disk space', 'fetched'=>false);
442 $extra_columns[]=array('tagname'=>'memsize', 'header'=>'MS', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Memory size', 'fetched'=>false);
443 $extra_columns[]=array('tagname'=>'numslices', 'header'=>'SM', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Number of slices in memory', 'fetched'=>false);
444 $extra_columns[]=array('tagname'=>'uptime', 'header'=>'UT', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Continuous uptime until now', 'fetched'=>false);
445 }
446
447 //TopHat Live data
448
449 if (MYSLICE_TOPHAT_AVAILABLE)
450 {
451 $extra_columns[]=array('tagname'=>'asn', 'header'=>'AS', 'source'=>'tophat', 'type'=>'string', 'title'=>'AS Number', 'fetched'=>false);
452 $extra_columns[]=array('tagname'=>'city', 'header'=>'LCY', 'source'=>'tophat', 'type'=>'string', 'title'=>'City', 'fetched'=>false);
453 $extra_columns[]=array('tagname'=>'region', 'header'=>'LRN', 'source'=>'tophat', 'type'=>'string', 'title'=>'Region', 'fetched'=>false);
454 $extra_columns[]=array('tagname'=>'country', 'header'=>'LCN', 'source'=>'tophat', 'type'=>'string', 'title'=>'Country', 'fetched'=>false);
455 $extra_columns[]=array('tagname'=>'continent', 'header'=>'LCT', 'source'=>'tophat', 'type'=>'string', 'title'=>'Continent', 'fetched'=>false);
456 //$extra_columns[]=array('tagname'=>'hopcount', 'header'=>'HC', 'source'=>'tophat', 'type'=>'sortAlphaNumericTop', 'title'=>'Hop count from reference node', 'fetched'=>false);
457 ////$extra_columns[]=array('tagname'=>'rtt', 'header'=>'RTT', 'source'=>'tophat', 'type'=>'sortAlphaNumericTop', 'title'=>'Round trip time from reference node', 'fetched'=>false);
458 //////$extra_columns[]=array('tagname'=>'agents', 'header'=>'MA', 'source'=>'tophat', 'type'=>'sortAlphaNumericTop', 'title'=>'Co-located measurement agents', 'fetched'=>true);
459 ////$extra_columns[]=array('tagname'=>'agents_sonoma', 'header'=>'MAS', 'source'=>'tophat', 'type'=>'sortAlphaNumericTop', 'title'=>'Co-located SONoMA agents', 'fetched'=>true);
460 ////$extra_columns[]=array('tagname'=>'agents_etomic', 'header'=>'MAE', 'source'=>'tophat', 'type'=>'sortAlphaNumericTop', 'title'=>'Co-located ETOMIC agents', 'fetched'=>true);
461 ////$extra_columns[]=array('tagname'=>'agents_tdmi', 'header'=>'MAT', 'source'=>'tophat', 'type'=>'sortAlphaNumericTop', 'title'=>'Co-located TDMI agents', 'fetched'=>true);
462 ////$extra_columns[]=array('tagname'=>'agents_dimes', 'header'=>'MAD', 'source'=>'tophat', 'type'=>'sortAlphaNumericTop', 'title'=>'Co-located DIMES agents', 'fetched'=>true);
463 }
464
465
466
467 //Get user's column configuration
468
469 $first_time_configuration = false;
470 $default_configuration = "hostname:f|ST:f|AU:f|RES:f";
471 //$extra_default = "";
472 $column_configuration = "";
473 $slice_column_configuration = "";
474
475 $show_configuration = "";
476
477 $PersonTags=$api->GetPersonTags (array('person_id'=>$plc->person['person_id']));
478 //plc_debug('ptags',$PersonTags);
479 foreach ($PersonTags as $ptag) {
480   if ($ptag['tagname'] == 'columnconf') {
481     $column_configuration = $ptag['value'];
482     $conf_tag_id = $ptag['person_tag_id'];
483   } else if ($ptag['tagname'] == 'showconf') {
484     $show_configuration = $ptag['value'];
485     $show_tag_id = $ptag['person_tag_id'];
486   }
487 }
488
489 $sliceconf_exists = false;
490 if ($column_configuration == "") {
491   $first_time_configuration = true;
492   $column_configuration = $slice_id.";default";
493   $sliceconf_exists = true;
494 } else {
495   $slice_conf = explode(";",$column_configuration);
496   for ($i=0; $i<count($slice_conf); $i++ ) {
497     if ($slice_conf[$i] == $slice_id) {
498       $i++;
499       $slice_column_configuration = $slice_conf[$i];
500       $sliceconf_exists = true;
501       break;
502     } else {
503       $i++;
504       $slice_column_configuration = $slice_conf[$i];
505     }
506   }
507 }
508
509 if ($sliceconf_exists == false)
510   $column_configuration = $column_configuration.";".$slice_id.";default";
511
512 if ($slice_column_configuration == "")
513   $full_configuration = $default_configuration;
514 else
515   $full_configuration = $default_configuration."|".$slice_column_configuration;
516
517
518 //instantiate the column configuration class, which prepares the headers array
519 $ConfigureColumns =new PlekitColumns($full_configuration, $fix_columns, $tag_columns, $extra_columns);
520
521 $visiblecolumns = $ConfigureColumns->node_tags();
522
523 $node_columns=array_merge($node_fixed_columns,$visiblecolumns);
524 $all_nodes=$api->GetNodes(NULL,$node_columns);
525
526 $ConfigureColumns->fetch_live_data($all_nodes);
527
528 $show_reservable_info = TRUE;
529 $show_layout_info = '1';
530 $show_conf = explode(";",$show_configuration);
531 foreach ($show_conf as $ss) {
532   if ($ss =="reservable")
533     $show_reservable_info = FALSE;
534   else if ($ss =="columns")
535     $show_layout_info = '0';
536 }
537
538 $slice_nodes=array();
539 $potential_nodes=array();
540 $reservable_nodes=array();
541 foreach ($all_nodes as $node) {
542   if (in_array($node['node_id'],$slice['node_ids'])) {
543     $slice_nodes[]=$node;
544     if ($node['node_type']=='reservable') $reservable_nodes[]=$node;
545   } else {
546     $potential_nodes[]=$node;
547   }
548 }
549 if ($profiling) plc_debug_prof('05: nodes',count($slice_nodes));
550 ////////////////////
551 // outline the number of reservable nodes
552 $nodes_message=count_english($slice_nodes,"node");
553 if (count($reservable_nodes)) $nodes_message .= " (" . count($reservable_nodes) . " reservable)";
554 $toggle=new PlekitToggle ('my-slice-nodes',$nodes_message,
555                           array('bubble'=>
556                                 'Manage nodes attached to this slice',
557                                 'visible'=>get_arg('show_nodes')));
558 $toggle->start();
559
560
561 //////////////////// reservable nodes area
562 $leases_info="
563 You have attached one or more reservable nodes to your slice.
564 Reservable nodes show up with the '$mark' mark.
565 Your slivers will be available only during timeslots
566 where you have obtained leases.
567 You can manage your leases in the tab below.
568 <br>
569 This feature is still experimental; feedback is appreciated at <a href='mailto:devel@planet-lab.org'>devel@planet-lab.org</a>
570 ";
571 $count=count($reservable_nodes);
572 if ($count && $privileges) {
573   // include leases.js only if needed
574   drupal_set_html_head('<script src="/planetlab/slices/leases.js" type="text/javascript" charset="utf-8"></script>');
575
576   // having reservable nodes in white lists looks a bit off scope for now...
577   $toggle_nodes=new PlekitToggle('my-slice-nodes-reserve',
578                                  "Leases - " . count($reservable_nodes) . " reservable node(s)",
579                                  array('visible'=>get_arg('show_nodes_resa'),
580                                        'info-text'=>$leases_info,
581                                        'info-visible'=>$show_reservable_info));
582   $toggle_nodes->start();
583
584   // get settings from environment, otherwise set to defaults
585   // when to start, in hours in the future from now
586   $leases_offset=$get_array($_GET, 'leases_offset');
587   if ( ! $leases_offset ) $leases_offset=0;
588   // how many timeslots to show
589   $leases_slots=$get_array($_GET, 'leases_slots');
590   if ( ! $leases_slots ) $leases_slots = 36;
591   // offset in hours (in the future) from now
592   $leases_w = $get_array($_GET, 'leases_w');
593   if ( ! $leases_w) $leases_w=18;
594   // number of timeslots to display
595
596   $granularity=$api->GetLeaseGranularity();
597
598   // these elements are for passing data to the javascript layer
599   echo "<span class='hidden' id='leases_slicename'>" . $slice['name'] . "</span>";
600   echo "<span class='hidden' id='leases_slice_id'>" . $slice['slice_id']. "</span>";
601   echo "<span class='hidden' id='leases_granularity'>" . $granularity . "</span>";
602   // ditto, and editable - very rough for now
603   echo "<div class='center' id='leases_settings'>";
604   echo "<label id='leases_offset_label' class='leases_label'>start, in hours from now</label>";
605   echo "<input type='text' class='leases_input' id='leases_offset_input' value='$leases_offset' />";
606   echo "<label id='leases_slots_label' class='leases_label'># of timeslots</label>";
607   echo "<input type='text' class='leases_input' id='leases_slots_input' value='$leases_slots' />";
608   echo "<label id='leases_w_label' class='leases_label'>slot width, in pixels</label>";
609   echo "<input type='text' class='leases_input' id='leases_w_input' value='$leases_w' />";
610   echo "</div>";
611
612   // leases_data is the name used by leases.js to locate this place
613   // first population will be triggered by init_scheduler from leases.js
614   echo "<table id='leases_data' class='hidden'></table>";
615
616   // the general layout for the scheduler
617   echo <<< EOF
618 <div id='leases_area'></div>
619
620 <div id='leases_buttons'>
621     <button id='leases_refresh' type='submit'>Refresh (Pull)</button>
622     <button id='leases_submit' type='submit'>Submit (Push)</button>
623 </div>
624 EOF;
625
626   $toggle_nodes->end();
627  }
628
629 if ($profiling) plc_debug_prof('06: leases',0);
630
631 //////////////////// node configuration panel
632 if ($first_time_configuration)
633 $column_conf_visible = '1';
634 else
635 $column_conf_visible = '0';
636
637 $layout_info='
638 This tab allows you to customize the columns in the node tables,
639 below. Information on the nodes comes from a variety of monitoring
640 sources. If you, as either a user or a provider of monitoring data,
641 would like to see additional columns made available, please send us
642 your request in mail to <a
643 href="mailto:support@myslice.info">support@myslice.info</a>. You can
644 find more information about the MySlice project at <a
645 href="http://trac.myslice.info">http://trac.myslice.info</a>.
646 ';
647 $toggle_nodes=new PlekitToggle('my-slice-nodes-configuration',
648                                "Node table layout",
649                                array('info-text'=>$layout_info,
650                                      'info-visible'=>$show_layout_info));
651 $toggle_nodes->start();
652
653 //usort ($table_headers, function($col1, $col2) {return strcmp($col1["header"],$col2["header"]);}));
654 //print("<p>TABLE HEADERS<p>");
655 //print_r($table_headers);
656
657 print("<div id='debug'></div>");
658 print("<input type='hidden' id='slice_id' value='".$slice['slice_id']."' />");
659 print("<input type='hidden' id='person_id' value='".$plc->person['person_id']."' />");
660 print("<input type='hidden' id='conf_tag_id' value='".$conf_tag_id."' />");
661 print("<input type='hidden' id='show_tag_id' value='".$show_tag_id."' />");
662 print("<input type='hidden' id='show_configuration' value='".$show_configuration."' />");
663 print("<input type='hidden' id='column_configuration' value='".$slice_column_configuration."' />");
664 print("<br><input type='hidden' size=80 id='full_column_configuration' value='".$column_configuration."' />");
665 print("<input type='hidden' id='previousConf' value='".$slice_column_configuration."' />");
666 print("<input type='hidden' id='defaultConf' value='".$default_configuration."' />");
667
668 if ($profiling) plc_debug_prof('07: before configuration_panel',0);
669 $ConfigureColumns->configuration_panel_html(true);
670
671 if ($profiling) plc_debug_prof('08: before javascript_init',0);
672 $ConfigureColumns->javascript_init();
673
674 $toggle_nodes->end();
675
676 if ($profiling) plc_debug_prof('09: layout',0);
677
678 $all_sites=$api->GetSites(NULL, array('site_id','login_base'));
679 $site_hash=array();
680 foreach ($all_sites as $tmp_site) $site_hash[$tmp_site['site_id']]=$tmp_site['login_base'];
681
682 $interface_columns=array('ip','node_id','interface_id');
683 $interface_filter=array('is_primary'=>TRUE);
684 $interfaces=$api->GetInterfaces($interface_filter,$interface_columns);
685
686 $interface_hash=array();
687 if ($interfaces) {
688         foreach ($interfaces as $interface) $interface_hash[$interface['node_id']]=$interface;
689 }
690
691 if ($profiling) plc_debug_prof('10: interfaces',count($interfaces));
692
693 //////////////////// nodes currently in
694 $toggle_nodes=new PlekitToggle('my-slice-nodes-current',
695                                count_english($slice_nodes,"node") . " currently in $name",
696                                array('visible'=>get_arg('show_nodes_current')));
697 $toggle_nodes->start();
698
699 $headers=array();
700 $notes=array();
701 //$notes=array_merge($notes,$visibletags->notes());
702 $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";
703
704 /*
705 $headers['peer']='string';
706 $headers['hostname']='string';
707 $short="-S-"; $long=Node::status_footnote(); $type='string';
708         $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
709 $short=reservable_mark(); $long=reservable_legend(); $type='string';
710         $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
711 // the extra tags, configured for the UI
712 $headers=array_merge($headers,$visibletags->headers());
713
714 if ($privileges) $headers[plc_delete_icon()]="none";
715 */
716
717 $edit_header = array();
718 if ($privileges) $edit_header[plc_delete_icon()]="none";
719 $headers = array_merge($ConfigureColumns->get_headers(),$edit_header);
720
721 //print("<p>HEADERS<p>");
722 //print_r($headers);
723
724 $table_options = array('notes'=>$notes,
725                        'search_width'=>15,
726                        'pagesize'=>20,
727                         'configurable'=>true);
728
729 $table=new PlekitTable('nodes',$headers,NULL,$table_options);
730
731 $form=new PlekitForm(l_actions(),array('slice_id'=>$slice['slice_id']));
732 $form->start();
733 $table->start();
734 if ($slice_nodes) foreach ($slice_nodes as $node) {
735   $table->row_start();
736
737   $table->cell($node['node_id'], array('display'=>'none'));
738
739   $table->cell(l_node_obj($node));
740   $peers->cell($table,$node['peer_id']);
741   $run_level=$node['run_level'];
742   list($label,$class) = Node::status_label_class_($node);
743   $table->cell ($label,array('class'=>$class));
744   $table->cell( ($node['node_type']=='reservable')?reservable_mark():"" );
745
746   $hostname=$node['hostname'];
747   $ip=$interface_hash[$node['node_id']]['ip'];
748   $interface_id=$interface_hash[$node['node_id']]['interface_id'];
749
750 //extra columns
751 $node['domain'] = topdomain($hostname);
752 $node['sitename'] = l_site_t($node['site_id'],$site_hash[$node['site_id']]);
753 if ($interface_id)
754         $node['ipaddress'] = l_interface_t($interface_id,$ip);
755   else
756         $node['ipaddress'] = "n/a";
757
758  //foreach ($visiblecolumns as $tagname) $table->cell($node[$tagname]);
759  $ConfigureColumns->cells($table, $node);
760
761   if ($privileges) $table->cell ($form->checkbox_html('node_ids[]',$node['node_id']));
762   $table->row_end();
763 }
764 // actions area
765 if ($privileges) {
766
767   // remove nodes
768   $table->tfoot_start();
769
770   $table->row_start();
771   $table->cell($form->submit_html ("remove-nodes-from-slice","Remove selected"),
772                array('hfill'=>true,'align'=>'right'));
773   $table->row_end();
774  }
775 $table->end();
776 $toggle_nodes->end();
777
778 if ($profiling) plc_debug_prof('11: nodes in',count($slice_nodes));
779
780 //////////////////// nodes to add
781 if ($privileges) {
782   $new_potential_nodes = array();
783   if ($potential_nodes) foreach ($potential_nodes as $node) {
784       $emptywl=empty($node['slice_ids_whitelist']);
785       $inwl = (!emptywl) and in_array($slice['slice_id'],$node['slice_ids_whitelist']);
786       if ($emptywl or $inwl)
787         $new_potential_nodes[]=$node;
788   }
789   $potential_nodes=$new_potential_nodes;
790
791   $count=count($potential_nodes);
792   $toggle_nodes=new PlekitToggle('my-slice-nodes-add',
793                                  count_english($potential_nodes,"more node") . " available",
794                                  array('visible'=>get_arg('show_nodes_add')));
795   $toggle_nodes->start();
796
797   if ( $potential_nodes ) {
798     $headers=array();
799     $notes=array();
800
801
802 /*
803     $headers['peer']='string';
804     $headers['hostname']='string';
805     $short="-S-"; $long=Node::status_footnote(); $type='string';
806         $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
807         $short=reservable_mark(); $long=reservable_legend(); $type='string';
808         $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
809     // the extra tags, configured for the UI
810     $headers=array_merge($headers,$visibletags->headers());
811     $headers['+']="none";
812 */
813
814     $add_header = array();
815     $add_header['+']="none";
816     $headers = array_merge($ConfigureColumns->get_headers(),$add_header);
817
818     //$notes=array_merge($notes,$visibletags->notes());
819 $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";
820
821     $table=new PlekitTable('add_nodes',$headers,NULL, $table_options);
822     $form=new PlekitForm(l_actions(),
823                          array('slice_id'=>$slice['slice_id']));
824     $form->start();
825     $table->start();
826     if ($potential_nodes) foreach ($potential_nodes as $node) {
827         $table->row_start();
828
829         $table->cell($node['node_id'], array('display'=>'none'));
830
831         $table->cell(l_node_obj($node));
832         $peers->cell($table,$node['peer_id']);
833         list($label,$class) = Node::status_label_class_($node);
834         $table->cell ($label,array('class'=>$class));
835         $table->cell( ($node['node_type']=='reservable')?reservable_mark():"" );
836
837         //extra columns
838           $hostname=$node['hostname'];
839           $ip=$interface_hash[$node['node_id']]['ip'];
840           $interface_id=$interface_hash[$node['node_id']]['interface_id'];
841         $node['domain'] = topdomain($hostname);
842         $node['sitename'] = l_site_t($node['site_id'],$site_hash[$node['site_id']]);
843         $node['ipaddress'] = l_interface_t($interface_id,$ip);
844
845         //foreach ($visiblecolumns as $tagname) $table->cell($node[$tagname]);
846         $ConfigureColumns->cells($table, $node);
847
848         $table->cell ($form->checkbox_html('node_ids[]',$node['node_id']));
849         $table->row_end();
850       }
851     // add nodes
852     $table->tfoot_start();
853     $table->row_start();
854     $table->cell($form->submit_html ("add-nodes-in-slice","Add selected"),
855                  array('hfill'=>true,'align'=>'right'));
856     $table->row_end();
857     $table->end();
858     $form->end();
859   }
860   $toggle_nodes->end();
861 }
862
863 $toggle->end();
864
865 if ($profiling) plc_debug_prof('12: nodes to add',count($potential_nodes));
866
867 //////////////////////////////////////// retrieve all slice tags
868 $tags=$api->GetSliceTags (array('slice_id'=>$slice_id));
869 //////////////////////////////////////////////////////////// tab:initscripts
870 // xxx fixme
871 // * add a message on how to use this:
872 // * explain the 2 mechanisms (initscript_code, initscript)
873 // * explain the interface : initscript start|stop|restart slicename
874 // xxx fixme
875
876 $initscript_info="
877 There are two ways to attach an initscript to a slice:<ul>
878
879 <li> <span class='bold'> Shared initscripts </span> are global to the
880 MyPLC, and managed by the Operations Team. For that reason, regular
881 users cannot change these scripts, but can reference one of the
882 available names in the drop down below.  </li>
883
884 <li> You also have the option to provide <span class='bold'> your own
885 code </span>, with the following conventions: <ul>
886
887 <li> Like regular initscripts, your script must expect to receive as a
888 first argument <span class='bold'> start </span>, <span class='bold'>
889 stop </span> or <span class='bold'> restart </span>. It is important
890 to honor this argument, as your slice may be stopped and restarted at
891 any time; also this is used whenever the installed code gets changed.
892 </li>
893
894 <li> As a second argument, you will receive the slicename; in most
895 cases this can be safely ignored.  </li>
896
897 </ul>
898 </li>
899  </ul>
900 The slice-specific setting has precedence on a shared initscript.
901 ";
902
903 $shared_initscripts=$api->GetInitScripts(array('-SORT'=>'name'),array('name'));
904 //$shared_initscripts=$api->GetInitScripts();
905 if ($profiling) plc_debug_prof('13: initscripts',count($initscripts));
906 // xxx expose this even on foreign slices for now
907 if ($local_peer) {
908   $initscript='';
909   $initscript_code='';
910   if ($tags) foreach ($tags as $tag) {
911       if ($tag['tagname']=='initscript') {
912         if ($initscript!='') drupal_set_error("multiple occurrences of 'initscript' tag");
913         $initscript=$tag['value'];
914       }
915       if ($tag['tagname']=='initscript_code') {
916         if ($initscript_code!='') drupal_set_error("multiple occurrences of 'initscript_code' tag");
917         $initscript_code=$tag['value'];
918         // plc_debug_txt('retrieved body',$initscript_code);
919       }
920     }
921   $label="No initscript";
922   $trimmed=trim($initscript_code);
923   if (!empty($trimmed)) $label="Initscript : slice-specific (" . substr($initscript_code,0,20) . " ...)";
924   else if (!empty($initscript)) $label="Initscript: shared " . $initscript;
925
926   $toggle = new PlekitToggle('slice-initscripts',$label,
927                              array('bubble'=>'Manage initscript on that slice',
928                                    'visible'=>get_arg('show_initscripts'),
929                                    'info-text'=>$initscript_info
930                                    // not messing with persontags to guess whether this should be displayed or not
931                                    // hopefully some day toggle will know how to handle that using web storage
932                                    ));
933   $toggle->start();
934
935   $details=new PlekitDetails(TRUE);
936   // we expose the previous values so that actions.php can know if changes are really needed
937   // the code needs to be encoded as it may contain any character
938   // as far as the code, this does not work too well b/c what actions.php receives
939   // seems to have spurrious \r chars, and the comparison between old and new values
940   // is not reliable, which results in changes being made although the code hasn't changed
941   // hve spent too much time on this, good enough for now...
942   $details->form_start(l_actions(),array('action'=>'update-initscripts',
943                                          'slice_id'=>$slice_id,
944                                          'name'=>$name,
945                                          'previous-initscript'=>$initscript,
946                                          'previous-initscript-code'=>htmlentities($initscript_code)));
947   $details->start();
948   // comppute a pulldown with available names
949   $selectors=array();
950   $is_found=FALSE;
951   if ($shared_initscripts) foreach ($shared_initscripts as $is) {
952       $is_selector=array('display'=>$is['name'],'value'=>$is['name']);
953       if ($is['name']==$initscript) {
954         $is_selector['selected']=TRUE;
955         $is_found=TRUE;
956       }
957       $selectors[]=$is_selector;
958     }
959   // display a warning when initscript references an unknown script
960   $details->tr_submit('unused','Update initscripts');
961   ////////// by name
962   $details->th_td("shared initscript name",
963                   $details->form()->select_html('initscript',$selectors,array('label'=>'none')),
964                   'initscript',
965                   array('input_type'=>'select'));
966   if ($initscript && ! $is_found)
967     // xxx better rendering ?
968     $details->th_td('WARNING',plc_warning_html("Current name '" . $initscript . "' is not a known shared initscript name"));
969   ////////// by contents
970   $script_height=8;
971   $script_width=60;
972   if ($initscript_code) {
973     $text=explode("\n",$initscript_code);
974     $script_height=count($text);
975     $script_width=10;
976     foreach ($text as $line) $script_width=max($script_width,strlen($line));
977   }
978   $details->th_td('slice initscript',$initscript_code,'initscript-code',
979                   array('input_type'=>'textarea', 'width'=>$script_width,'height'=>$script_height));
980   $details->tr_submit('unused','Update initscripts');
981   $details->form_end();
982   $details->end();
983   $toggle->end();
984 }
985
986 //////////////////////////////////////////////////////////// tab:tags
987 // very wide values get abbreviated
988 $tag_value_threshold=24;
989 // xxx fixme
990 // * this area could use a help message about some special tags:
991 // * initscript-related should be taken out
992 // * sliverauth-related (ssh_key & hmac) should have a toggle to hide or show
993 // xxx fixme
994
995 // xxx expose this even on foreign slices for now
996 //if ( $local_peer ) {
997   if ($profiling) plc_debug_prof('14: slice tags',count($tags));
998   function get_tagname ($tag) { return $tag['tagname'];}
999   $tagnames = array_map ("get_tagname",$tags);
1000
1001   $toggle = new PlekitToggle ('slice-tags',count_english_warning($tags,'tag'),
1002                               array('bubble'=>'Inspect and set tags on that slice',
1003                                     'visible'=>get_arg('show_tags')));
1004   $toggle->start();
1005
1006   $headers=array(
1007     "Name"=>"string",
1008     "Value"=>"string",
1009     "Node"=>"string",
1010     "NodeGroup"=>"string");
1011   if ($tags_privileges) $headers[plc_delete_icon()]="none";
1012
1013   $table_options=array("notes_area"=>false,"pagesize_area"=>false,"search_width"=>10);
1014   $table=new PlekitTable("slice_tags",$headers,'0',$table_options);
1015   $form=new PlekitForm(l_actions(),
1016                        array('slice_id'=>$slice['slice_id']));
1017   $form->start();
1018   $table->start();
1019   if ($tags) {
1020     // Get hostnames for nodes in a single pass
1021     $_node_ids = array();
1022     foreach ($tags as $tag) {
1023       if ($tag['node_id']) {
1024         array_push($_node_ids, $tag['node_id']);
1025       }
1026     }
1027     $_nodes = $api->GetNodes(array('node_id' => $_node_ids), array('node_id', 'hostname'));
1028     $_hostnames = array();
1029     if ($_nodes) {
1030         foreach ($_nodes as $_node) {
1031                 $_hostnames[$_node['node_id']] = $_node['hostname'];
1032         }
1033     }
1034
1035     // Loop through tags again to display
1036     foreach ($tags as $tag) {
1037       $node_name = "ALL";
1038       if ($tag['node_id']) {
1039         $node_name = $_hostnames[$tag['node_id']];
1040       }
1041       $nodegroup_name="n/a";
1042       if ($tag['nodegroup_id']) {
1043         $nodegroups=$api->GetNodeGroups(array('nodegroup_id'=>$tag['nodegroup_id']));
1044         if ($profiling) plc_debug_prof('15: nodegroup for slice tag',$nodegroup);
1045         if ($nodegroup) {
1046           $nodegroup = $nodegroups[0];
1047           $nodegroup_name = $nodegroup['groupname'];
1048         }
1049       }
1050       $table->row_start();
1051       $table->cell(l_tag_obj($tag));
1052       // very wide values get abbreviated
1053       $table->cell(truncate_and_popup($tag['value'],$tag_value_threshold));
1054       $table->cell($node_name);
1055       $table->cell($nodegroup_name);
1056       if ($tags_privileges) $table->cell ($form->checkbox_html('slice_tag_ids[]',$tag['slice_tag_id']));
1057       $table->row_end();
1058     }
1059   }
1060   if ($tags_privileges) {
1061     $table->tfoot_start();
1062     $table->row_start();
1063     $table->cell($form->submit_html ("delete-slice-tags","Remove selected"),
1064                  array('hfill'=>true,'align'=>'right'));
1065     $table->row_end();
1066
1067     $table->row_start();
1068     function tag_selector ($tag) {
1069       return array("display"=>$tag['tagname'],"value"=>$tag['tag_type_id']);
1070     }
1071     $all_tags= $api->GetTagTypes( array ("category"=>"*slice*","-SORT"=>"+tagname"), array("tagname","tag_type_id"));
1072     if ($profiling) plc_debug_prof('16: tagtypes',count($all_tags));
1073     $selector_tag=array_map("tag_selector",$all_tags);
1074
1075     function node_selector($node) {
1076       return array("display"=>$node["hostname"],"value"=>$node['node_id']);
1077     }
1078     $selector_node=array_map("node_selector",$slice_nodes);
1079
1080     function nodegroup_selector($ng) {
1081       return array("display"=>$ng["groupname"],"value"=>$ng['nodegroup_id']);
1082     }
1083     $all_nodegroups = $api->GetNodeGroups( array("groupname"=>"*"), array("groupname","nodegroup_id"));
1084     if ($profiling) plc_debug_prof('17: nodegroups',count($all_nodegroups));
1085     $selector_nodegroup=array_map("nodegroup_selector",$all_nodegroups);
1086
1087     $table->cell($form->select_html("tag_type_id",$selector_tag,array('label'=>"Choose Tag")));
1088     $table->cell($form->text_html("value","",array('width'=>8)));
1089     $table->cell($form->select_html("node_id",$selector_node,array('label'=>"All Nodes")));
1090     $table->cell($form->select_html("nodegroup_id",$selector_nodegroup,array('label'=>"No Nodegroup")));
1091     $table->cell($form->submit_html("add-slice-tag","Set Tag"),array('columns'=>2,'align'=>'left'));
1092     $table->row_end();
1093   }
1094
1095   $table->end();
1096   $form->end();
1097   $toggle->end();
1098 //}
1099
1100
1101 //////////////////////////////////////////////////////////// tab:renew
1102 if ($local_peer ) {
1103   if ( ! $renew_visible) renew_area ($slice,$site,NULL);
1104  }
1105
1106 $peers->block_end($peer_id);
1107
1108 if ($profiling) plc_debug_prof_end();
1109
1110 // Print footer
1111 include 'plc_footer.php';
1112
1113 ?>