Add a 'report a problem' link for the RebootNode button on node page.
[plewww.git] / planetlab / slices / slice2.php
1 <?php
2
3 // $Id$
4
5 // Require login
6 require_once 'plc_login.php';
7
8 // Get session and API handles
9 require_once 'plc_session.php';
10 global $plc, $api;
11
12 // Print header
13 require_once 'plc_drupal.php';
14 include 'plc_header.php';
15
16 // Common functions
17 require_once 'plc_functions.php';
18 require_once 'plc_peers.php';
19 require_once 'plc_objects.php';
20 require_once 'plc_visibletags2.php';
21 require_once 'linetabs.php';
22 require_once 'table2.php';
23 require_once 'details.php';
24 require_once 'toggle.php';
25 require_once 'form.php';
26 require_once 'columns.php';
27
28 // keep css separate for now
29 drupal_set_html_head('
30 <link href="/planetlab/css/my_slice.css" rel="stylesheet" type="text/css" />
31 ');
32
33 // -------------------- admins potentially need to get full list of users
34 ini_set('memory_limit','32M');
35
36 // -------------------- 
37 // recognized URL arguments
38 $slice_id=intval($_GET['id']);
39 if ( ! $slice_id ) { plc_error('Malformed URL - id not set'); return; }
40
41 ////////////////////
42 // Get all columns as we focus on only one entry
43 $slices= $api->GetSlices( array($slice_id));
44
45 if (empty($slices)) {
46   drupal_set_message ("Slice " . $slice_id . " not found");
47   return;
48  }
49
50 $slice=$slices[0];
51
52 // pull all node info to vars
53 $name= $slice['name'];
54 $expires = date( "d/m/Y", $slice['expires'] );
55 $site_id= $slice['site_id'];
56
57 $person_ids=$slice['person_ids'];
58
59 // get peers
60 $peer_id= $slice['peer_id'];
61 $peers=new Peers ($api);
62 $local_peer = ! $peer_id;
63
64 // gets site info
65 $sites= $api->GetSites( array( $site_id ) );
66 $site=$sites[0];
67 $site_name= $site['name'];
68 $max_slices = $site['max_slices'];
69
70 //////////////////////////////////////// building blocks for the renew area
71 // Constants
72 global $DAY;            $DAY = 24*60*60;
73 global $WEEK;           $WEEK = 7 * $DAY; 
74 global $MAX_WEEKS;      $MAX_WEEKS= 8;          // weeks from today
75 global $GRACE_DAYS;     $GRACE_DAYS=10;         // days for renewal promoted on top
76 global $NOW;            $NOW=mktime();
77
78 ////////////////////////////////////////////////////////////
79 // make the renew area on top and open if the expiration time is less than 10 days from now
80 function renew_needed ($slice) {
81   global $DAY, $NOW, $GRACE_DAYS;
82   $current_exp=$slice['expires'];
83
84   $time_left = $current_exp - $NOW;
85   $visible = $time_left/$DAY <= $GRACE_DAYS;
86   return $visible;
87 }
88
89 function renew_area ($slice,$site,$visible) {
90   global $DAY, $WEEK, $MAX_WEEKS, $GRACE_DAYS, $NOW;
91  
92   $current_exp=$slice['expires'];
93   $current_text = gmstrftime("%A %b-%d-%y %T %Z", $current_exp);
94   $max_exp= $NOW + ($MAX_WEEKS * $WEEK); // seconds since epoch
95   $max_text = gmstrftime("%A %b-%d-%y %T %Z", $max_exp);
96
97   // xxx some extra code needed to enable this area only if the slice description is OK:
98   // description and url must be non void
99   $toggle=
100     new PlekitToggle('renew',"Expires $current_text - Renew this slice",
101                      array("bubble"=>
102                            "Enter this zone if you wish to renew your slice",
103                            'visible'=>$visible));
104   $toggle->start();
105
106   // xxx message could take roles into account
107   if ($site['max_slices']<=0) {
108      $message= <<< EOF
109 <p class='my-slice-renewal'>Slice creation and renewal have been temporarily disabled for your
110 <site. This may have occurred because your site's nodes have been down
111 or unreachable for several weeks, and multiple attempts to contact
112 your site's PI(s) and Technical Contact(s) have all failed. If so,
113 contact your site's PI(s) and Technical Contact(s) and ask them to
114 bring up your site's nodes. Please visit your <a
115 href='/db/sites/index.php?id=$site_id'>site details</a> page to find
116 out more about your site's nodes, and how to contact your site's PI(s)
117 and Technical Contact(s).</p>
118 EOF;
119      echo $message;
120  
121   } else {
122     // xxx this is a rough cut and paste from the former UI
123     // showing a datepicker view could be considered as well with some extra work
124     // calculate possible extension lengths
125     $selectors = array();
126     foreach ( array ( 1 => "One more week", 
127                       2 => "Two more weeks", 
128                       3 => "Three more weeks", 
129                       4 => "One more month" ) as $weeks => $text ) {
130       $candidate_exp = $current_exp + $weeks*$WEEK;
131       if ( $candidate_exp < $max_exp) {
132         $selectors []= array('display'=>"$text (" . gmstrftime("%A %b-%d-%y %T %Z", $candidate_exp) . ")",
133                              'value'=>$candidate_exp);
134         $max_renewal_weeks=$weeks;
135         $max_renewal_date= gmstrftime("%A %b-%d-%y %T %Z", $candidate_exp);
136       }
137     }
138
139     if ( empty( $selectors ) ) {
140       print <<< EOF
141 <div class='my-slice-renewal'>
142 Slices annot be renewed more than $MAX_WEEKS weeks from now, i.e. not beyond $max_text. 
143 For this reason, the current slice cannot be renewed any further into the future, try again closer to expiration date.
144 </div>
145 EOF;
146      } else {
147       print <<< EOF
148 <div class='my-slice-renewal'>
149 <p>You must provide a short description as well as a link to a project website before renewing it.
150 Do <span class='bold'>not</span> provide bogus information; if a complaint is lodged against your slice 
151 and PlanetLab Operations is unable to determine what the normal behavior of your slice is, 
152 your slice may be deleted to resolve the complaint.</p>
153 <p><span class='bold'>NOTE:</span> 
154 Slices cannot be renewed beyond another $max_renewal_weeks week(s) ($max_renewal_date).
155 </p>
156 </div>
157 EOF;
158
159       $form = new PlekitForm (l_actions(),
160                               array('action'=>'renew-slice',
161                                     'slice_id'=>$slice['slice_id']));
162       $form->start();
163       print $form->label_html('expires','Duration');
164       print $form->select_html('expires',$selectors,array('label'=>'Pick one'));
165       print $form->submit_html('renew-button','Renew');
166       $form->end();
167     }
168   }
169  
170   $toggle->end();
171 }
172
173 ////////////////////////////////////////////////////////////
174
175 $am_in_slice = in_array(plc_my_person_id(),$person_ids);
176
177 if ($am_in_slice) {
178   drupal_set_title("My slice " . $name);
179  } else {
180   drupal_set_title("Slice " . $name);
181 }
182
183 $privileges = ( $local_peer && (plc_is_admin()  || plc_is_pi() || $am_in_slice));
184 $tags_privileges = $privileges || plc_is_admin();
185
186 $tabs=array();
187 $tabs [] = tab_nodes_slice($slice_id);
188 $tabs [] = tab_site($site_id);
189
190 // are these the right privileges for deletion ?
191 if ($privileges) {
192   $tabs ['Delete']= array('url'=>l_actions(),
193                           'method'=>'post',
194                           'values'=>array('action'=>'delete-slice','slice_id'=>$slice_id),
195                           'bubble'=>"Delete slice $name",
196                           'confirm'=>"Are you sure to delete slice $name");
197
198   $tabs["Events"]=array_merge(tablook_event(),
199                               array('url'=>l_event("Slice","slice",$slice_id),
200                                     'bubble'=>"Events for slice $name"));
201   $tabs["Comon"]=array_merge(tablook_comon(),
202                              array('url'=>l_comon("slice_id",$slice_id),
203                                    'bubble'=>"Comon page about slice $name"));
204 }
205
206 plekit_linetabs($tabs);
207
208 ////////////////////////////////////////
209 $peers->block_start($peer_id);
210
211 //////////////////////////////////////// renewal area 
212 // (1) close to expiration : show on top and open
213
214 if ($local_peer ) {
215   $renew_visible = renew_needed ($slice);
216   if ($renew_visible) renew_area ($slice,$site,true);
217  }
218
219
220 //////////////////// details
221 // default for opening the details section or not ?
222 if ($local_peer) {
223   $default_show_details = true;
224  } else {
225   $default_show_details = ! $renew_visible;
226  }
227   
228 $toggle = 
229   new PlekitToggle ('my-slice-details',"Details",
230                     array('bubble'=>
231                           'Display and modify details for that slice',
232                           'visible'=>get_arg('show_details',$default_show_details)));
233 $toggle->start();
234
235 $details=new PlekitDetails($privileges);
236 $details->form_start(l_actions(),array('action'=>'update-slice',
237                                        'slice_id'=>$slice_id,
238                                        'name'=>$name));
239
240 $details->start();
241 if (! $local_peer) {
242   $details->th_td("Peer",$peers->peer_link($peer_id));
243   $details->space();
244  }
245
246
247 $details->th_td('Name',$slice['name']);
248 $details->th_td('Description',$slice['description'],'description',
249                 array('input_type'=>'textarea',
250                       'width'=>50,'height'=>5));
251 $details->th_td('URL',$slice['url'],'url',array('width'=>50));
252 $details->tr_submit("submit","Update Slice");
253 $details->th_td('Expires',$expires);
254 $details->th_td('Instantiation',$slice['instantiation']);
255 $details->th_td('Site',l_site_obj($site));
256 // xxx show the PIs here
257 //$details->th_td('PIs',...);
258 $details->end();
259
260 $details->form_end();
261 $toggle->end();
262
263 //////////////////// persons
264 $person_columns = array('email','person_id','first_name','last_name','roles');
265 // get persons in slice
266 if (!empty($person_ids))
267   $persons=$api->GetPersons(array('person_id'=>$slice['person_ids']),$person_columns);
268 // just propose to add everyone else
269 // xxx this is maybe too much for admins as it slows stuff down 
270 // as regular persons can see only a fraction of the db anyway
271 $potential_persons=
272   $api->GetPersons(array('~person_id'=>$slice['person_ids'],
273                          'peer_id'=>NULL,
274                          'enabled'=>true),
275                    $person_columns);
276 $count=count($persons);
277
278 $toggle=
279   new PlekitToggle ('my-slice-persons',"$count users",
280                     array('bubble'=>
281                           'Manage accounts attached to this slice',
282                           'visible'=>get_arg('show_persons',false)));
283 $toggle->start();
284
285 ////////// people currently in
286 // visible:
287 // hide if both current+add are included
288 // so user can chose which section is of interest
289 // show otherwise
290 $toggle_persons = new PlekitToggle ('my-slice-persons-current',
291                                     "$count people currently in $name",
292                                     array('visible'=>get_arg('show_persons_current',!$privileges)));
293 $toggle_persons->start();
294
295 $headers=array();
296 $headers['email']='string';
297 $headers['first']='string';
298 $headers['last']='string';
299 $headers['R']='string';
300 if ($privileges) $headers[plc_delete_icon()]="none";
301 $table=new PlekitTable2('persons',$headers,'0', NULL,
302                        array('notes_area'=>false));
303 $form=new PlekitForm(l_actions(),array('slice_id'=>$slice['slice_id']));
304 $form->start();
305 $table->start();
306 if ($persons) foreach ($persons as $person) {
307   $table->row_start();
308   $table->cell(l_person_obj($person));
309   $table->cell($person['first_name']);
310   $table->cell($person['last_name']);
311   $table->cell(plc_vertical_table ($person['roles']));
312   if ($privileges) $table->cell ($form->checkbox_html('person_ids[]',$person['person_id']));
313   $table->row_end();
314 }
315 // actions area
316 if ($privileges) {
317
318   // remove persons
319   $table->tfoot_start();
320
321   $table->row_start();
322   $table->cell($form->submit_html ("remove-persons-from-slice","Remove selected"),
323                array('hfill'=>true,'align'=>'right'));
324   $table->row_end();
325  }
326 $table->end();
327 $toggle_persons->end();
328
329 ////////// people to add
330 if ($privileges) {
331   $count=count($potential_persons);
332   $toggle_persons = new PlekitToggle ('my-slice-persons-add',
333                                       "$count people may be added to $name",
334                                       array('visible'=>get_arg('show_persons_add',false)));
335   $toggle_persons->start();
336   if ( ! $potential_persons ) {
337     // xxx improve style
338     echo "<p class='not-relevant'>No person to add</p>";
339   } else {
340     $headers=array();
341     $headers['email']='string';
342     $headers['first']='string';
343     $headers['last']='string';
344     $headers['R']='string';
345     $headers['+']="none";
346     $options = array('notes_area'=>false,
347                      'search_width'=>15,
348                      'pagesize'=>8);
349     // show search for admins only as other people won't get that many names to add
350     if ( ! plc_is_admin() ) $options['search_area']=false;
351     
352     $table=new PlekitTable2('add_persons',$headers,'0',NULL,$options);
353     $form=new PlekitForm(l_actions(),array('slice_id'=>$slice['slice_id']));
354     $form->start();
355     $table->start();
356     if ($potential_persons) foreach ($potential_persons as $person) {
357         $table->row_start();
358         $table->cell(l_person_obj($person));
359         $table->cell($person['first_name']);
360         $table->cell($person['last_name']);
361         $table->cell(plc_vertical_table ($person['roles']));
362         $table->cell ($form->checkbox_html('person_ids[]',$person['person_id']));
363         $table->row_end();
364       }
365     // add users
366     $table->tfoot_start();
367     $table->row_start();
368     $table->cell($form->submit_html ("add-persons-in-slice","Add selected"),
369                  array('hfill'=>true,'align'=>'right'));
370     $table->row_end();
371     $table->end();
372     $form->end();
373   }
374   $toggle_persons->end();
375 }
376 $toggle->end();
377
378 //////////////////////////////////////////////////////////// Nodes
379 // the nodes details to display here
380 // (1) we search for the tag types for which 'category' matches 'node*/ui*'
381 // all these tags will then be tentatively displayed in this area
382 // (2) further information can also be optionally specified in the category:
383 //     (.) we split the category with '/' and search for assignments of the form var=value
384 //     (.) header can be set to supersede the column header (default is tagname)
385 //     (.) rank can be used for ordering the columns (default is tagname)
386 //     (.) type is passed to the javascript table, for sorting (default is 'string')
387
388 // minimal list as a start
389 //$node_fixed_columns = array('hostname','node_id','slice_ids_whitelist','boot_state','last_contact');
390 // create a VisibleTags object : basically the list of tag columns to show
391 //$visibletags = new VisibleTags ($api, 'node');
392 //$visiblecolumns = $visibletags->column_names();
393 //$node_columns=array_merge($node_fixed_columns,$visiblecolumns);
394
395
396
397 /* TEST PlekitColumns */
398
399 //prepare fix and configurable columns
400
401 $fix_columns = array();
402 $fix_columns[]=array('tagname'=>'hostname', 'header'=>'hostname', 'type'=>'string', 'title'=>'The name of the node');
403 $fix_columns[]=array('tagname'=>'peer_id', 'header'=>'AU', 'type'=>'string', 'title'=>'Authority');
404 $fix_columns[]=array('tagname'=>'run_level', 'header'=>'ST', 'type'=>'string', 'title'=>'Status');
405
406 $visibletags = new VisibleTags ($api, 'node');
407 $visibletags->columns();
408 $tag_columns = $visibletags->headers();
409
410 $extra_columns = array();
411 $extra_columns[]=array('tagname'=>'site_id', 'header'=>'SN', 'type'=>'string', 'title'=>'Site name', 'description'=>'Site name');
412
413 //$configurable_columns = array_merge($tag_columns, $extra_columns);
414 //usort ($configurable_columns, create_function('$col1,$col2','return strcmp($col1["header"],$col2["header"]);'));
415
416
417 $first_time_configuration = 'false';
418 $default_configuration = "hostname:f|ST:f|AU:f|Rw|AST";
419 $column_configuration = "";
420
421 $DescTags=$api->GetSliceTags (array('slice_id'=>$slice['slice_id']));
422 for ($i=0; $i<count($DescTags); $i++ ) {
423         if ($DescTags [$i]['tagname']=='Configuration'){
424                 $column_configuration = $DescTags [$i]['value'];
425                 break;
426         }
427 }
428
429 if ($column_configuration == "")
430 {
431         $first_time_configuration = 'true';
432         $column_configuration = $default_configuration;
433 }
434
435 //print("<p>GOT CONFIGURATION: ".$column_configuration);
436
437 //$test_configuration = "hostname:f|AU:f|ST:f|Rw|AST";
438 //print("<p>Parsing configuration ".$test_configuration);
439
440
441 $ConfigureColumns =new PlekitColumns($column_configuration, $fix_columns, $tag_columns, $extra_columns);
442
443 $node_requested_data = $ConfigureColumns->node_tags();
444 $nodes=$api->GetNodes(array('node_id'=>$slice['node_ids']),$node_requested_data);
445 $potential_nodes=$api->GetNodes(array('~node_id'=>$slice['node_ids']),$node_requested_data);
446
447 //$nodes = array();
448 //$potential_nodes = array();
449
450 //print("<p>RESULTS for ".print_r(array('~node_id'=>$slice['node_ids'])));
451 //print_r($nodes);
452
453 $count=count($nodes);
454
455 $toggle=new PlekitToggle ('my-slice-nodes',"$count nodes",
456                           array('bubble'=>
457                                 'Manage nodes attached to this slice',
458                                 'visible'=>get_arg('show_nodes',false)));
459 $toggle->start();
460
461
462 $toggle_nodes=new PlekitToggle('my-slice-nodes-configuration',
463                                "Node table column configuration",
464                                array('visible'=>'1'));
465
466 $toggle_nodes->start();
467
468
469 //usort ($table_headers, create_function('$col1,$col2','return strcmp($col1["header"],$col2["header"]);'));
470
471 //print("<p>HEADERS TO SHOW<p>");
472 //print_r($headersToShow);
473
474 //print("<p>TABLE HEADERS<p>");
475 //print_r($table_headers);
476
477 print("<div id='debug'></div>");
478 print("<input type='hidden' id='slice_id' value='".$slice['slice_id']."' />");
479 print("<input type='hidden' size='80' id='column_configuration' value='".$column_configuration."' />");
480 print("<input type='hidden' id='previousConf' value='".$column_configuration."'></input>");
481 print("<input type='hidden' id='defaultConf' value='".$default_configuration."'></input>");
482 //print("<input type='button' id='testFunctions' onclick=\"highlightOption('AU')\" value='test'></input>");
483
484 $ConfigureColumns->javascript_vars();
485
486 $ConfigureColumns->configuration_panel_html(true);
487
488 print("<div align='center' id='loadingDiv'></div>");
489
490 $toggle_nodes->end();
491
492
493 ////////// nodes currently in
494
495 $count=count($nodes);
496
497 $toggle_nodes=new PlekitToggle('my-slice-nodes-current',
498                                "$count nodes currently in $name",
499                                array('visible'=>get_arg('show_nodes_current',!$privileges)));
500
501 $toggle_nodes->start();
502
503 $edit_header = array();
504 if ($privileges) $edit_header[plc_delete_icon()]="none";
505
506 $table_options = array('search_width'=>15,
507                        'pagesize'=>20);
508 //$table=new PlekitTable2('nodes',$headers,'1',$table_options);
509 //$table=new PlekitTable2('nodes_pairwise',array_merge($ConfigureColumns->plekit_columns_get_headers(),$edit_header),NULL,$headersToShow, $table_option);
510 //$headersToShow = $ConfigureColumns->plekit_columns_visible();
511
512 $table=new PlekitTable2('nodes',array_merge($ConfigureColumns->get_headers(),$edit_header),NULL,NULL, $table_option); 
513
514 $form=new PlekitForm(l_actions(),array('slice_id'=>$slice['slice_id']));
515 $form->start();
516 $table->start();
517 if ($nodes) foreach ($nodes as $node) {
518   $table->row_start();
519
520   $table->cell($node['node_id'], array('display'=>'none'));
521   $table->cell(l_node_obj($node));
522
523   $peers->cell($table,$node['peer_id']);
524   $run_level=$node['run_level'];
525   list($label,$class) = Node::status_label_class_($node);
526   $table->cell ($label,array('name'=>'ST', 'class'=>$class, 'display'=>'table-cell'));
527
528  
529 $ConfigureColumns->cells($table, $node);
530
531
532
533   if ($privileges) $table->cell ($form->checkbox_html('node_ids[]',$node['node_id']));
534   $table->row_end();
535 }
536 // actions area
537 if ($privileges) {
538
539   // remove nodes
540   $table->tfoot_start();
541
542   $table->row_start();
543   $table->cell($form->submit_html ("remove-nodes-from-slice","Remove selected"),
544                array('hfill'=>true,'align'=>'right'));
545   $table->row_end();
546  }
547 $table->end();
548 $toggle_nodes->end();
549
550 ////////// nodes to add
551 if ($privileges) {
552   $new_potential_nodes = array();
553   if ($potential_nodes) foreach ($potential_nodes as $node) {
554       $emptywl=empty($node['slice_ids_whitelist']);
555       $inwl = (!emptywl) and in_array($slice['slice_id'],$node['slice_ids_whitelist']);
556       if ($emptywl or $inwl)
557         $new_potential_nodes[]=$node;
558   }
559   $potential_nodes=$new_potential_nodes;
560
561   $count=count($potential_nodes);
562   $toggle_nodes=new PlekitToggle('my-slice-nodes-add',
563                                  "$count more nodes available",
564                                  array('visible'=>get_arg('show_nodes_add',false)));
565   $toggle_nodes->start();
566
567   if ( ! $potential_nodes ) {
568     // xxx improve style
569     echo "<p class='not-relevant'>No node to add</p>";
570   } else {
571
572     $edit_header = array();
573     if ($privileges) $edit_header['+']="none";
574     
575     //$table=new PlekitTable2('add_nodes',$headers,'1', $table_options);
576     $table=new PlekitTable2('add_nodes',array_merge($ConfigureColumns->get_headers(), $edit_header),NULL,$headersToShow, $table_options);
577     $form=new PlekitForm(l_actions(),
578                          array('slice_id'=>$slice['slice_id']));
579     $form->start();
580     $table->start();
581
582     if ($potential_nodes) foreach ($potential_nodes as $node) {
583         $table->row_start();
584
585   $table->cell($node['node_id'], array('display'=>'none'));
586   $table->cell(l_node_obj($node));
587
588   $peers->cell($table,$node['peer_id']);
589   $run_level=$node['run_level'];
590   list($label,$class) = Node::status_label_class_($node);
591   $table->cell ($label,array('name'=>'ST', 'class'=>$class, 'display'=>'table-cell'));
592
593 $ConfigureColumns->cells($table, $node);
594
595         $table->cell ($form->checkbox_html('node_ids[]',$node['node_id']));
596         $table->row_end();
597       }
598     // add nodes
599     $table->tfoot_start();
600     $table->row_start();
601     $table->cell($form->submit_html ("add-nodes-in-slice","Add selected"),
602                  array('hfill'=>true,'align'=>'right'));
603     $table->row_end();
604     $table->end();
605     $form->end();
606   }
607   $toggle_nodes->end();
608 }
609 $toggle->end();
610
611 //////////////////////////////////////////////////////////// Tags
612 //if ( $local_peer ) {
613   $tags=$api->GetSliceTags (array('slice_id'=>$slice_id));
614   function get_tagname ($tag) { return $tag['tagname'];}
615   $tagnames = array_map ("get_tagname",$tags);
616   
617   $toggle = new PlekitToggle ('slice-tags',count_english_warning($tags,'tag'),
618                               array('bubble'=>'Inspect and set tags on tat slice',
619                                     'visible'=>get_arg('show_tags',false)));
620   $toggle->start();
621   
622   $headers=array(
623     "Name"=>"string",
624     "Value"=>"string",
625     "Node"=>"string",
626     "NodeGroup"=>"string");
627   if ($tags_privileges) $headers[plc_delete_icon()]="none";
628   
629   $table_options=array("notes_area"=>false,"pagesize_area"=>false,"search_width"=>10);
630   $table=new PlekitTable2("slice_tags",$headers,'0',NULL,$table_options);
631   $form=new PlekitForm(l_actions(),
632                        array('slice_id'=>$slice['slice_id']));
633   $form->start();
634   $table->start();
635   if ($tags) {
636     foreach ($tags as $tag) {
637       $node_name = "ALL";
638       if ($tag['node_id']) {
639         $nodes = $api->GetNodes(array('node_id'=>$tag['node_id']));
640         if($nodes) {
641           $node = $nodes[0];
642           $node_name = $node['hostname'];
643         }
644       }
645       $nodegroup_name="n/a";
646       if ($tag['nodegroup_id']) { 
647         $nodegroup=$api->GetNodeGroups(array('nodegroup_id'=>$tag['nodegroup_id']));
648         if ($nodegroup) {
649           $nodegroup = $nodegroup[0];
650           $nodegroup_name = $nodegroup['groupname'];
651         }
652       }
653       $table->row_start();
654       $table->cell(l_tag_obj($tag));
655       $table->cell($tag['value']);
656       $table->cell($node_name);
657       $table->cell($nodegroup_name);
658       if ($tags_privileges) $table->cell ($form->checkbox_html('slice_tag_ids[]',$tag['slice_tag_id']));
659       $table->row_end();
660     }
661   }
662   if ($tags_privileges) {
663     $table->tfoot_start();
664     $table->row_start();
665     $table->cell($form->submit_html ("delete-slice-tags","Remove selected"),
666                  array('hfill'=>true,'align'=>'right'));
667     $table->row_end();
668     
669     $table->row_start();
670     function tag_selector ($tag) {
671       return array("display"=>$tag['tagname'],"value"=>$tag['tag_type_id']);
672     }
673     $all_tags= $api->GetTagTypes( array ("category"=>"slice*","-SORT"=>"+tagname"), array("tagname","tag_type_id"));
674     $selector_tag=array_map("tag_selector",$all_tags);
675     
676     function node_selector($node) { 
677       return array("display"=>$node["hostname"],"value"=>$node['node_id']);
678     }
679     $all_nodes = $api->GetNodes( array ("node_id" => $slice['node_ids']), array("hostname","node_id"));
680     $selector_node=array_map("node_selector",$all_nodes);
681     
682     function nodegroup_selector($ng) {
683       return array("display"=>$ng["groupname"],"value"=>$ng['nodegroup_id']);
684     }
685     $all_nodegroups = $api->GetNodeGroups( array("groupname"=>"*"), array("groupname","nodegroup_id"));
686     $selector_nodegroup=array_map("nodegroup_selector",$all_nodegroups);
687     
688     $table->cell($form->select_html("tag_type_id",$selector_tag,array('label'=>"Choose Tag")));
689     $table->cell($form->text_html("value","",array('width'=>8)));
690     $table->cell($form->select_html("node_id",$selector_node,array('label'=>"All Nodes")));
691     $table->cell($form->select_html("nodegroup_id",$selector_nodegroup,array('label'=>"No Nodegroup")));
692     $table->cell($form->submit_html("add-slice-tag","Set Tag"),array('columns'=>2,'align'=>'left'));
693     $table->row_end();
694   }
695     
696   $table->end();
697   $form->end();
698   $toggle->end();
699 //}
700
701
702 //////////////////////// renew slice
703 if ($local_peer ) {
704   if ( ! $renew_visible) renew_area ($slice,$site,false);
705  }
706
707 $peers->block_end($peer_id);
708
709 // Print footer
710 include 'plc_footer.php';
711
712 ?>
713
714
715 <script type="text/javascript">
716
717 var sourceComon = '<a target="source_window" href="http://comon.cs.princeton.edu/">CoMoN</a>';
718 var sourceTophat = '<b><a target="source_window" href="http://www.top-hat.info/">TopHat</a></b>';
719 var sourceTophatAPI = '<b><a target="source_window" href="http://www.top-hat.info/API/">TopHat API</a></b>';
720 var sourceMySlice = '<b><a target="source_window" href="http://myslice.info/">MySlice</a></b>';
721 var sourceCymru = '<b><a target="source_window" href="http://www.team-cymru.org/">Team Cymru</a></b>';
722 var sourceMyPLC = '<b><a target="source_window" href="http://www.planet-lab.eu/PLCAPI/">MyPLC API</a></b>';
723 var sourceManiacs = '<b><a target="source_window" href="http://www.ece.gatech.edu/research/labs/MANIACS/as_taxonomy/">MANIACS</a></b>';
724 var sourceMonitor = '<b><a target="source_window" href="http://monitor.planet-lab.org/">Monitor</a></b>';
725 var selectReferenceNode ='Select reference node: <select id="reference_node" onChange="updateDefaultConf(this.value)"><option value=planetlab-europe-07.ipv6.lip6.fr>planetlab-europe-07.ipv6.lip6.fr</option></select>';
726 var addButton = '<input id="addButton" type="button" value="Add" onclick=addColumnAjax(document.getElementById("list1").value)></input>';
727 var deleteButton = '<input id="deleteButton" type="button" value="Delete" onclick=deleteColumn(window.document.getElementById("list1").value)></input>';
728
729 var titleAU = 'Authority';
730 var detailAU = '<i>The authority of the global PlanetLab federation that the site of the node belongs to.</i>';
731 var valuesAU = 'Values: <b>PLC</b> (PlanetLab Central), <b>PLE</b> (PlanetLab Europe)';
732 var sourceAU = '<b>Source:</b> '+sourceMyPLC;
733 var descAU = '<span class="myslice title">'+titleAU+'</span><p>'+detailAU+'<p>'+valuesAU+'<p>'+sourceAU;
734
735 var descHOSTNAME = "test";
736
737
738 var titleAS = 'Autonomous system ID';
739 var sourceAS = 'Source: '+sourceCymru+' (via '+sourceTophat+')';
740 var valuesAS = 'Unit: <b>Integer between 0 and 65535</b>';
741 var descAS = '<span class="myslice title">'+titleAS+'</span><p>'+valuesAS+'<p>' + sourceAS;
742
743 var titleAST = 'Autonomous system type';
744 var sourceAST = 'Source: '+sourceManiacs;
745 var valuesAST = 'Values: <b>t1</b> (tier-1), <b>t2</b> (tier-2), <b>edu</b> (university), <b>comp</b> (company), <b>nic</b> (network information center), <b>ix</b> (IXP), <b>n/a</b>';
746 var descAST = '<span class="myslice title">'+titleAST+'</span><p>'+valuesAST+'<p>'+sourceAST;
747
748 var titleASN = 'Autonomous system name';
749 var sourceASN = 'Source: '+sourceTophat;
750 var descASN = '<span class="myslice title">'+titleASN+'</span><p>'+sourceASN;
751
752 var selectPeriodBU = 'Select period: <select id="selectperiodBU" onChange=updatePeriod("BU")><option value=w>Week</option><option value=m>Month</option><option value=y>Year</option></select>';
753 var titleBU = 'Bandwidth utilization ';
754 var sourceBU = 'Source: '+sourceComon+' (via '+sourceMySlice+')';
755 var valuesBU ='Unit: <b>Kbps</b>';
756 var detailBU = '<i>The average Transmited bandwidh (Tx) over the selected period. The period is the most recent for which data is available, with CoMoN data being collected by MySlice daily.</i>'
757 var descBU = '<span class="myslice title">'+titleBU+'</span><p>'+detailBU+'<p>'+selectPeriodBU+'<p>'+valuesBU+'<p>'+sourceBU; 
758
759 var titleBW= 'Bandwidth limit';
760 var sourceBW = 'Source: '+sourceComon;
761 var valuesBW = 'Unit: <b>Kbps</b>';
762 var detailBW = '<i>The bandwidth limit is a cap on the total outbound bandwidth usage of a node. It is set by the site administrator (PI). For more details see <a href="http://www.planet-lab.org/doc/BandwidthLimits">Bandwidth Limits (planet-lab.org)</a></i>';
763 var descBW = '<span class="myslice title">'+titleBW+'</span><p>'+detailBW+'<p>'+valuesBW+'<p>'+sourceBW;
764
765 var titleCC = 'Number of CPU cores';
766 var sourceCC = 'Source: '+sourceComon;
767 var valuesCC = 'Current PlanetLab hardware requirements: 4 cores min. <br><i>(Older nodes may have fewer cores)</i>';
768 var descCC = '<span class="myslice title">'+titleCC+'</span><p>'+valuesCC+'<p>'+sourceCC;
769
770 var titleCN = 'Number of CPUs';
771 var sourceCN = 'Source: '+sourceComon;
772 var valuesCN = 'Current PlanetLab hardware requirements: <b>1 (if quad core) or 2 (if dual core)</b>';
773 var descCN = '<span class="myslice title">'+titleCN+'</span><p>'+valuesCN+'<p>'+sourceCN;
774
775 var titleCR = 'CPU clock rate';
776 var sourceCR = 'Source: '+sourceComon;
777 var valuesCR = 'Unit: <b>GHz</b><p>Current PlanetLab hardware requirements: <b>2.4 GHz</b>';
778 var descCR = '<span class="myslice title">'+titleCR+'</span><p>'+valuesCR+'<p>'+sourceCR;
779
780 var selectPeriodCF = 'Select period: <select id="selectperiodCF" onChange=updatePeriod("CF")><option value=w>Week</option><option value=m>Month</option><option value=y>Year</option></select>';
781 var titleCF = 'Free CPU';
782 var sourceCF = 'Source: '+sourceComon+' (via '+sourceMySlice+')';
783 var valuesCF = 'Unit: <b>%</b>';
784 var detailCF = '<i> The average CPU percentage that could be allocated by a test slice (burb) run periodically by CoMoN </i>';
785 var descCF = '<span class="myslice title">'+titleCF+'</span><p>'+detailCF+'<p>'+selectPeriodCF+'<p>'+valuesCF+'<p>'+sourceCF; 
786
787 var titleDS = 'Disk size';
788 var sourceDS = 'Source: '+sourceComon;
789 var valuesDS = 'Unit: <b>GB</b><p>Current PlanetLab hardware requirements: <b>500GB</b>';
790 var descDS = '<span class="myslice title">'+titleDS+'</span><p>'+valuesDS+'<p>'+sourceDS;
791
792 var titleDU = 'Current disk utilization';
793 var sourceDU = 'Source: '+sourceComon+' (via '+sourceMySlice+')';
794 var valuesDU = 'Unit: <b>GB</b>';
795 var detailDU = '<i> The amount of disk space currently consumed (checked daily) </i>';
796 var descDU = '<span class="myslice title">'+titleDU+'</span><p>'+detailDU+'<p>'+valuesDU+'<p>'+sourceDU;
797
798 var titleHC = 'Hop count from a reference node';
799 var sourceHC = 'Source: '+sourceTophat;
800 var detailHC = '<i>TopHat conducts traceroutes every five minutes in a full mesh between all PlanetLab nodes. The hop count is the length of the traceroute from the node to the reference node, based upon the most recently reported traceroute</i>.';
801 var descHC = '<span class="myslice title">'+titleHC+'</span><p>'+detailHC+'<p>'+selectReferenceNode+'<p>'+sourceHC;
802
803 var titleIP = 'IP address';
804 var sourceIP = 'Source: '+sourceTophat;
805 var descIP = '<span class="myslice title">'+titleIP+'</span><p>'+sourceIP;
806
807 var selectPeriodL = 'Select period: <select id="selectperiodL" onChange=updatePeriod("L")><option value=w>Week</option><option value=m>Month</option><option value=y>Year</option></select>';
808 var titleL= 'Load ';
809 var sourceL = 'Source: '+sourceComon;
810 var valuesL = 'Unit: <b>float</b>';
811 var detailL = '<i>The average 5-minute Unix load (as reported by the uptime command) over the selected period</i>';
812 var descL = '<span class="myslice title">'+titleL+'</span><p>'+detailL+'<p>'+selectPeriodL+'<p>'+valuesL+'<p>'+sourceL; 
813
814 var titleLON= 'Longitude';
815 var sourceLON = 'Source: '+sourceTophat;
816 var descLON = '<span class="myslice title">'+titleLON+'</span><p>'+sourceLON;
817
818 var titleLAT= 'Latitude';
819 var sourceLAT = 'Source: '+sourceTophat;
820 var descLAT = '<span class="myslice title">'+titleLAT+'</span><p>'+sourceLAT;
821
822 var titleLCN= 'Location (Country)';
823 var sourceLCN = 'Source: '+sourceTophat;
824 var detailLCN = '<i>Based on the latitude, longitude information</i>';
825 var descLCN = '<span class="myslice title">'+titleLCN+'</span><p>'+detailLCN+'<p>'+sourceLCN;
826
827 var titleLCT= 'Location (Continent)';
828 var sourceLCT = 'Source: '+sourceTophat;
829 var detailLCT = '<i>Based on the latitude, longitude information</i>';
830 var descLCT = '<span class="myslice title">'+titleLCT+'</span><p>'+detailLCT+'<p>'+sourceLCT;
831
832 var titleLCY= 'Location (City)';
833 var sourceLCY = 'Source: '+sourceTophat;
834 var detailLCY = '<i>Based on the latitude, longitude information</i>';
835 var descLCY = '<span class="myslice title">'+titleLCY+'</span><p>'+detailLCY+'<p>'+sourceLCY;
836
837 var titleLPR= 'Location precision radius';
838 var sourceLPR = 'Source: '+sourceTophat;
839 var valuesLPR = 'Unit: <b>float</b>';
840 var detailLPR = '<i>The radius of the circle corresponding to the error in precision of the geolocalization</i>';
841 var descLPR = '<span class="myslice title">'+titleLPR+'</span><p>'+detailLPR+'<p>'+valuesLPR+'<p>'+sourceLPR;
842
843 var titleLRN= 'Location (Region)';
844 var sourceLRN = 'Source: '+sourceTophat;
845 var detailLRN = '<i>Based on the latitude, longitude information</i>';
846 var descLRN = '<span class="myslice title">'+titleLRN+'</span><p>'+detailLRN+'<p>'+sourceLRN;
847
848 var titleMS= 'Memory size';
849 var sourceMS = 'Source: '+sourceComon;
850 var valuesMS = 'Unit: <b>GB</b><p>Current PlanetLab hardware requirements: <b>4GB</b>';
851 var descMS = '<span class="myslice title">'+titleMS+'</span><p>'+valuesMS+'<p>'+sourceMS;
852
853 var selectPeriodMU = 'Select period: <select id="selectperiodMU" onChange=updatePeriod("MU")><option value=w>Week</option><option value=m>Month</option><option value=y>Year</option></select>';
854 var titleMU = 'Memory utilization';
855 var sourceMU = 'Source: '+sourceComon;
856 var valuesMU = '<p>Unit: <b>%</b>';
857 var detailMU = '<i>The average active memory utilization as reported by CoMoN</i>';
858 var descMU = '<span class="myslice title">'+titleMU+'</span><p>'+detailMU+'<p>'+selectPeriodMU+'<p>'+valuesMU+'<p>'+sourceMU; 
859
860 var titleNEC= 'Network information (ETOMIC)';
861 var sourceNEC = 'Source: '+sourceTophat;
862 var valuesNEC = 'Values: <b>yes/no</b>';
863 var detailNEC = '<i>The existence of a colocated ETOMIC box. When an ETOMIC box is present you have the possibility to conduct high-precision measurements through the '+sourceTophatAPI+'</i>';
864 var descNEC = '<span class="myslice title">'+titleNEC+'</span><p>'+detailNEC+'<p>'+valuesNEC+'<p>'+sourceNEC;
865
866 var titleNTH= 'Network information (TopHat)';
867 var sourceNTH = 'Source: '+sourceTophat;
868 var valuesNTH = 'Values: <b>yes/no</b>';
869 var detailNTH = '<i>The existence of a colocated TopHat agent. When a TopHat agent is present you have the possibility to conduct high-precision measurements through the '+sourceTophatAPI+'</i>';
870 var descNTH = '<span class="myslice title">'+titleNTH+'</span><p>'+detailNTH+'<p>'+valuesNTH+'<p>'+sourceNTH;
871
872 var titleNDS= 'Network information (DIMES)';
873 var sourceNDS = 'Source: '+sourceTophat;
874 var valuesNDS = 'Values: <b>yes/no</b>';
875 var detailNDS = '<i>The existence of a colocated DIMES agent. When a DIMES agent is present you have the possibility to conduct high-precision measurements through the '+sourceTophatAPI+'</i>';
876 var descNDS = '<span class="myslice title">'+titleNDS+'</span><p>'+detailNDS+'<p>'+valuesNDS+'<p>'+sourceNDS;
877
878 var titleNSF= 'Network information (spoof)';
879 var sourceNSF = 'Source: '+sourceTophat;
880 var valuesNSF = '<p>Values: <b>yes/no</b>';
881 var detailNSF = '<i> Whether the node can send packets packets using the IP spoof option</i>';
882 var descNSF = '<span class="myslice title">'+titleNSF+'</span><p>'+detailNSF+'<p>'+valuesNSF+'<p>'+sourceNSF;
883
884 var titleNSR= 'Network information (source route)';
885 var sourceNSR = 'Source: '+sourceTophat;
886 var valuesNSR = '<p>Values: <b>yes/no</b>';
887 var detailNSR = '<i> Whether the node can send packets packets using the IP source route option</i>';
888 var descNSR = '<span class="myslice title">'+titleNSR+'</span><p>'+detailNSR+'<p>'+valuesNSR+'<p>'+sourceNSR;
889
890 var titleNTP= 'Network information (timestamp)';
891 var sourceNTP = 'Source: '+sourceTophat;
892 var valuesNTP = '<p>Values: <b>yes/no</b>';
893 var detailNTP = '<i> Whether the node can send packets packets using the IP timestamp option</i>';
894 var descNTP = '<span class="myslice title">'+titleNTP+'</span><p>'+detailNTP+'<p>'+valuesNTP+'<p>'+sourceNTP;
895
896 var titleNRR= 'Network information (record route)';
897 var sourceNRR = 'Source: '+sourceTophat;
898 var valuesNRR = '<p>Values: <b>yes/no</b>';
899 var detailNRR = '<i> Whether the node can send packets packets using the IP record route option</i>';
900 var descNRR = '<span class="myslice title">'+titleNRR+'</span><p>'+detailNRR+'<p>'+valuesNRR+'<p>'+sourceNRR;
901
902 var titleOS = 'Operating system';
903 var sourceOS = 'Source: '+sourceMyPLC;
904 var valuesOS = 'Values: <b>Fedora, Cent/OS, other, n/a</b>';
905 var descOS = '<span class="myslice title">'+titleOS+'</span><p>'+valuesOS+'<p>'+sourceOS;
906
907 var selectPeriodR = 'Select period: <select id="selectperiodR" onChange=updatePeriod("R")><option value=w>Week</option><option value=m>Month</option><option value=y>Year</option></select>';
908 var titleR = 'Reliability';
909 var sourceR = 'Source: '+sourceComon+' (via '+sourceMySlice+')';
910 var detailR = '<i>CoMoN queries nodes every 5 minutes, for 255 queries per day. The average reliability is the percentage of queries over the selected period for which CoMoN reports a value. The period is the most recent for which data is available, with CoMoN data being collected by MySlice daily</i>';
911 var valuesR = 'Unit: <b>%</b>';
912 var descR = '<span class="myslice title">'+titleR+'</span><p>'+detailR+'<p>'+selectPeriodR+'<p>'+valuesR+'<p>'+sourceR; 
913
914 var titleRES = 'Reservation capabilities';
915 var sourceRES = 'Source: '+sourceMyPLC;
916 var valuesRES = 'Values: <b>yes/no</b>';
917 var detailRES = '<i> Whether the node can be reserved for a certain duration</i>';
918 var descRES = '<span class="myslice title">'+titleRES+'</span><p>'+detailRES+'<p>'+valuesRES+'<p>'+sourceRES;
919
920 var selectPeriodS = 'Select period: <select id="selectperiodS" onChange=updatePeriod("S")><option value=w>Week</option><option value=m>Month</option><option value=y>Year</option></select>';
921 var titleS = 'Active slices';
922 var sourceS = 'Source: '+sourceComon+' (via '+sourceMySlice+')';
923 var valuesS = 'Unit: <b>%</b>';
924 var detailS = '<i>Average number of active slices over the selected period for which CoMoN reports a value. The period is the most recent for which data is available, with CoMoN data being collected by MySlice daily</i>';
925 var descS = '<span class="myslice title">'+titleS+'</span><p>'+detailS+'<p>'+selectPeriodS+'<p>'+valuesS+'<p>'+sourceS; 
926
927 var titleSN = 'Site name';
928 var sourceSN = 'Source: '+sourceMyPLC;
929 var descSN = '<span class="myslice title">'+titleSN+'</span><p>'+sourceSN;
930
931 var selectPeriodSSH = 'Select period: <select id="selectperiodSSH" onChange=updatePeriod("SSH")><option value=w>Week</option><option value=m>Month</option><option value=y>Year</option></select>';
932 var titleSSH = 'Average SSH response delay';
933 var valuesSSH = 'Unit: <b>%</b>';
934 var detailSSH = '<i>The average response delay of the node to SSH logins over the selected period for which CoMoN reports a value. The period is the most recent for which data is available, with CoMoN data being collected by MySlice daily</i>';
935 var sourceSSH ='Source: '+sourceComon+' (via '+sourceMySlice+')';
936 var descSSH = '<span class="myslice title">'+titleSSH+'</span><p>'+detailSSH+'<p>'+selectPeriodSSH+'<p>'+valuesSSH+'<p>'+sourceSSH; 
937
938 var titleST = 'Status';
939 var sourceST = 'Source: '+sourceMonitor;
940 var valuesST = 'Values: <b>online</b> (up and running), <b>good</b> (up and running recently), <b>offline</b> (unreachable today), <b>down</b> (unreachable nodes for more than 1 day), <b>failboot</b> (safeboot, MyPLC API term for debug)';
941 var descST = '<span class="myslice title">'+titleST+'</span><p>'+valuesST+'<p>'+sourceST;
942
943 highlightOption("AU");
944 overrideTitles();
945
946
947 /*
948 document.defaultAction = false;
949 document.onkeyup = detectEvent;
950
951 function detectEvent(e) {
952         var evt = e || window.event;
953         //debugfilter(evt.type);
954         //debugfilter('keyCode is ' + evt.keyCode);
955         //debugfilter('charCode is ' + evt.charCode);
956         //debugfilter(document.getElementById('testfocus').focused);
957         return document.defaultAction;
958 }
959 */
960
961
962 </script>