7bd81bcf616870dbd4fb65daac25f48f4b519d7a
[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 <script src="/planetlab/slices/leases.js" type="text/javascript" charset="utf-8"></script>
31 ');
32
33 // -------------------- admins potentially need to get full list of users
34 ini_set('memory_limit','32M');
35
36 $profiling=false;
37 if ($_GET['profiling']) $profiling=true;
38
39 if ($profiling)  plc_debug_prof_start();
40
41 // -------------------- 
42 // recognized URL arguments
43 $slice_id=intval($_GET['id']);
44 if ( ! $slice_id ) { plc_error('Malformed URL - id not set'); return; }
45
46 ////////////////////
47 // have to name columns b/c we need the non-native 'omf_control' column
48 $slice_columns=array('slice_id','name','peer_id','site_id','person_ids','node_ids','expires',
49                      'url','description','instantiation','omf_control');
50 $slices= $api->GetSlices( array($slice_id), $slice_columns);
51
52 if (empty($slices)) {
53   drupal_set_message ("Slice " . $slice_id . " not found");
54   return;
55  }
56
57 $slice=$slices[0];
58
59 if ($profiling) plc_debug_prof('2: slice',count($slices));
60 // pull all node info to vars
61 $name= $slice['name'];
62 $expires = date( "d/m/Y", $slice['expires'] );
63 $site_id= $slice['site_id'];
64
65 $person_ids=$slice['person_ids'];
66
67 // get peers
68 $peer_id= $slice['peer_id'];
69 $peers=new Peers ($api);
70 $local_peer = ! $peer_id;
71
72 if ($profiling) plc_debug_prof('3: peers',count($peers));
73
74 // gets site info
75 $sites= $api->GetSites( array( $site_id ) );
76 $site=$sites[0];
77 $site_name= $site['name'];
78 $max_slices = $site['max_slices'];
79
80 if ($profiling) plc_debug_prof('4: sites',count($sites));
81 //////////////////////////////////////// building blocks for the renew area
82 // Constants
83 global $DAY;            $DAY = 24*60*60;
84 global $WEEK;           $WEEK = 7 * $DAY; 
85 global $MAX_WEEKS;      $MAX_WEEKS= 8;          // weeks from today
86 global $GRACE_DAYS;     $GRACE_DAYS=10;         // days for renewal promoted on top
87 global $NOW;            $NOW=mktime();
88
89 ////////////////////////////////////////////////////////////
90 // make the renew area on top and open if the expiration time is less than 10 days from now
91 function renew_needed ($slice) {
92   global $DAY, $NOW, $GRACE_DAYS;
93   $current_exp=$slice['expires'];
94
95   $time_left = $current_exp - $NOW;
96   $visible = $time_left/$DAY <= $GRACE_DAYS;
97   return $visible;
98 }
99
100 function renew_area ($slice,$site,$visible) {
101   global $DAY, $WEEK, $MAX_WEEKS, $GRACE_DAYS, $NOW;
102  
103   $current_exp=$slice['expires'];
104   $current_text = gmstrftime("%A %b-%d-%y %T %Z", $current_exp);
105   $max_exp= $NOW + ($MAX_WEEKS * $WEEK); // seconds since epoch
106   $max_text = gmstrftime("%A %b-%d-%y %T %Z", $max_exp);
107
108   // xxx some extra code needed to enable this area only if the slice description is OK:
109   // description and url must be non void
110   $toggle=
111     new PlekitToggle('renew',"Expires $current_text - Renew this slice",
112                      array("bubble"=>
113                            "Enter this zone if you wish to renew your slice",
114                            'visible'=>$visible));
115   $toggle->start();
116
117   // xxx message could take roles into account
118   if ($site['max_slices']<=0) {
119      $message= <<< EOF
120 <p class='my-slice-renewal'>Slice creation and renewal have been temporarily disabled for your
121 <site. This may have occurred because your site's nodes have been down
122 or unreachable for several weeks, and multiple attempts to contact
123 your site's PI(s) and Technical Contact(s) have all failed. If so,
124 contact your site's PI(s) and Technical Contact(s) and ask them to
125 bring up your site's nodes. Please visit your <a
126 href='/db/sites/index.php?id=$site_id'>site details</a> page to find
127 out more about your site's nodes, and how to contact your site's PI(s)
128 and Technical Contact(s).</p>
129 EOF;
130      echo $message;
131  
132   } else {
133     // xxx this is a rough cut and paste from the former UI
134     // showing a datepicker view could be considered as well with some extra work
135     // calculate possible extension lengths
136     $selectors = array();
137     foreach ( array ( 1 => "One more week", 
138                       2 => "Two more weeks", 
139                       3 => "Three more weeks", 
140                       4 => "One more month" ) as $weeks => $text ) {
141       $candidate_exp = $current_exp + $weeks*$WEEK;
142       if ( $candidate_exp < $max_exp) {
143         $selectors []= array('display'=>"$text (" . gmstrftime("%A %b-%d-%y %T %Z", $candidate_exp) . ")",
144                              'value'=>$candidate_exp);
145         $max_renewal_weeks=$weeks;
146         $max_renewal_date= gmstrftime("%A %b-%d-%y %T %Z", $candidate_exp);
147       }
148     }
149
150     if ( empty( $selectors ) ) {
151       print <<< EOF
152 <div class='my-slice-renewal'>
153 Slices cannot be renewed more than $MAX_WEEKS weeks from now, i.e. not beyond $max_text. 
154 For this reason, the current slice cannot be renewed any further into the future, try again closer to expiration date.
155 </div>
156 EOF;
157      } else {
158       print <<< EOF
159 <div class='my-slice-renewal'>
160 <span class='bold'>Important:</span> Please take this opportunity to review and update your slice information in the Details tab.
161 <p>
162 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.
163 </p><p>
164 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. 
165 </p>
166 EOF;
167
168       $form = new PlekitForm (l_actions(),
169                               array('action'=>'renew-slice',
170                                     'slice_id'=>$slice['slice_id']));
171       $form->start();
172       print $form->label_html('expires','Duration:&nbsp;');
173       print $form->select_html('expires',$selectors,array('label'=>'Pick one'));
174       print $form->submit_html('renew-button','Renew');
175       $form->end();
176
177 print("<p><i>NOTE: Slices cannot be renewed beyond another $max_renewal_weeks week(s) ($max_renewal_date).</i>  </p>");
178 print ("</div>");
179     }
180   }
181  
182   $toggle->end();
183 }
184
185 ////////////////////////////////////////////////////////////
186
187 $am_in_slice = in_array(plc_my_person_id(),$person_ids);
188
189 if ($am_in_slice) {
190   drupal_set_title("My slice " . $name);
191  } else {
192   drupal_set_title("Slice " . $name);
193 }
194
195 $privileges = ( $local_peer && (plc_is_admin()  || plc_is_pi() || $am_in_slice));
196 $tags_privileges = $privileges || plc_is_admin();
197
198 $tabs=array();
199 $tabs [] = tab_nodes_slice($slice_id);
200 $tabs [] = tab_site($site);
201
202 // are these the right privileges for deletion ?
203 if ($privileges) {
204   $tabs ['Delete']= array('url'=>l_actions(),
205                           'method'=>'post',
206                           'values'=>array('action'=>'delete-slice','slice_id'=>$slice_id),
207                           'bubble'=>"Delete slice $name",
208                           'confirm'=>"Are you sure to delete slice $name");
209
210   $tabs["Events"]=array_merge(tablook_event(),
211                               array('url'=>l_event("Slice","slice",$slice_id),
212                                     'bubble'=>"Events for slice $name"));
213   $tabs["Comon"]=array_merge(tablook_comon(),
214                              array('url'=>l_comon("slice_id",$slice_id),
215                                    'bubble'=>"Comon page about slice $name"));
216 }
217
218 plekit_linetabs($tabs);
219
220 ////////////////////////////////////////
221 $peers->block_start($peer_id);
222
223 //////////////////////////////////////// renewal area 
224 // (1) close to expiration : show on top and open
225
226 if ($local_peer ) {
227   $renew_visible = renew_needed ($slice);
228   if ($renew_visible) renew_area ($slice,$site,true);
229  }
230
231
232 //////////////////// details
233 // default for opening the details section or not ?
234 if ($local_peer) {
235   $default_show_details = true;
236  } else {
237   $default_show_details = ! $renew_visible;
238  }
239   
240 $toggle = 
241   new PlekitToggle ('my-slice-details',"Details",
242                     array('bubble'=>
243                           'Display and modify details for that slice',
244                           'visible'=>get_arg('show_details',$default_show_details)));
245 $toggle->start();
246
247 $details=new PlekitDetails($privileges);
248 $details->form_start(l_actions(),array('action'=>'update-slice',
249                                        'slice_id'=>$slice_id,
250                                        'name'=>$name));
251
252 $details->start();
253 if (! $local_peer) {
254   $details->th_td("Peer",$peers->peer_link($peer_id));
255   $details->space();
256  }
257
258
259 $details->th_td('Name',$slice['name']);
260 $details->th_td('Description',$slice['description'],'description',
261                 array('input_type'=>'textarea',
262                       'width'=>50,'height'=>5));
263 $details->th_td('URL',$slice['url'],'url',array('width'=>50));
264 $details->tr_submit("submit","Update Slice");
265 $details->th_td('Expires',$expires);
266 $details->th_td('Instantiation',$slice['instantiation']);
267 $details->th_td("OMF-friendly", ($slice['omf_control'] ? 'Yes' : 'No') . " [to change: see 'omf_control' in the tags section below]");
268 $details->th_td('Site',l_site_obj($site));
269 // xxx show the PIs here
270 //$details->th_td('PIs',...);
271 $details->end();
272
273 $details->form_end();
274 $toggle->end();
275
276 //////////////////// persons
277 $person_columns = array('email','person_id','first_name','last_name','roles');
278 // get persons in slice
279 if (!empty($person_ids))
280   $persons=$api->GetPersons(array('person_id'=>$slice['person_ids']),$person_columns);
281 // just propose to add everyone else
282 // xxx this is maybe too much for admins as it slows stuff down 
283 // as regular persons can see only a fraction of the db anyway
284 $potential_persons=
285   $api->GetPersons(array('~person_id'=>$slice['person_ids'],
286                          'peer_id'=>NULL,
287                          'enabled'=>true),
288                    $person_columns);
289 $count=count($persons);
290
291 if ($profiling) plc_debug_prof('4: persons',count($persons));
292 $toggle=
293   new PlekitToggle ('my-slice-persons',"$count users",
294                     array('bubble'=>
295                           'Manage accounts attached to this slice',
296                           'visible'=>get_arg('show_persons',false)));
297 $toggle->start();
298
299 ////////// people currently in
300 // visible:
301 // hide if both current+add are included
302 // so user can chose which section is of interest
303 // show otherwise
304 $toggle_persons = new PlekitToggle ('my-slice-persons-current',
305                                     "$count people currently in $name",
306                                     array('visible'=>get_arg('show_persons_current',!$privileges)));
307 $toggle_persons->start();
308
309 $headers=array();
310 $headers['email']='string';
311 $headers['first']='string';
312 $headers['last']='string';
313 $headers['R']='string';
314 if ($privileges) $headers[plc_delete_icon()]="none";
315 $table=new PlekitTable('persons',$headers,'0',
316                        array('notes_area'=>false));
317 $form=new PlekitForm(l_actions(),array('slice_id'=>$slice['slice_id']));
318 $form->start();
319 $table->start();
320 if ($persons) foreach ($persons as $person) {
321   $table->row_start();
322   $table->cell(l_person_obj($person));
323   $table->cell($person['first_name']);
324   $table->cell($person['last_name']);
325   $table->cell(plc_vertical_table ($person['roles']));
326   if ($privileges) $table->cell ($form->checkbox_html('person_ids[]',$person['person_id']));
327   $table->row_end();
328 }
329 // actions area
330 if ($privileges) {
331
332   // remove persons
333   $table->tfoot_start();
334
335   $table->row_start();
336   $table->cell($form->submit_html ("remove-persons-from-slice","Remove selected"),
337                array('hfill'=>true,'align'=>'right'));
338   $table->row_end();
339  }
340 $table->end();
341 $toggle_persons->end();
342
343 ////////// people to add
344 if ($privileges) {
345   $count=count($potential_persons);
346   $toggle_persons = new PlekitToggle ('my-slice-persons-add',
347                                       "$count people may be added to $name",
348                                       array('visible'=>get_arg('show_persons_add',false)));
349   $toggle_persons->start();
350   if ( ! $potential_persons ) {
351     // xxx improve style
352     echo "<p class='not-relevant'>No person to add</p>";
353   } else {
354     $headers=array();
355     $headers['email']='string';
356     $headers['first']='string';
357     $headers['last']='string';
358     $headers['R']='string';
359     $headers['+']="none";
360     $options = array('notes_area'=>false,
361                      'search_width'=>15,
362                      'pagesize'=>8);
363     // show search for admins only as other people won't get that many names to add
364     if ( ! plc_is_admin() ) $options['search_area']=false;
365     
366     $table=new PlekitTable('add_persons',$headers,'0',$options);
367     $form=new PlekitForm(l_actions(),array('slice_id'=>$slice['slice_id']));
368     $form->start();
369     $table->start();
370     if ($potential_persons) foreach ($potential_persons as $person) {
371         $table->row_start();
372         $table->cell(l_person_obj($person));
373         $table->cell($person['first_name']);
374         $table->cell($person['last_name']);
375         $table->cell(plc_vertical_table ($person['roles']));
376         $table->cell ($form->checkbox_html('person_ids[]',$person['person_id']));
377         $table->row_end();
378       }
379     // add users
380     $table->tfoot_start();
381     $table->row_start();
382     $table->cell($form->submit_html ("add-persons-in-slice","Add selected"),
383                  array('hfill'=>true,'align'=>'right'));
384     $table->row_end();
385     $table->end();
386     $form->end();
387   }
388   $toggle_persons->end();
389 }
390 $toggle->end();
391
392 //////////////////////////////////////////////////////////// Nodes
393 // the nodes details to display here
394 // (1) we search for the tag types for which 'category' matches 'node*/ui*'
395 // all these tags will then be tentatively displayed in this area
396 // (2) further information can also be optionally specified in the category:
397 //     (.) we split the category with '/' and search for assignments of the form var=value
398 //     (.) header can be set to supersede the column header (default is tagname)
399 //     (.) rank can be used for ordering the columns (default is tagname)
400 //     (.) type is passed to the javascript table, for sorting (default is 'string')
401
402 // minimal list as a start
403 $node_fixed_columns = array('hostname','node_id','peer_id','slice_ids_whitelist', 'site_id',
404                             'run_level','boot_state','last_contact','node_type');
405 // create a VisibleTags object : basically the list of tag columns to show
406 //$visibletags = new VisibleTags ($api, 'node');
407 //$visiblecolumns = $visibletags->column_names();
408
409 // optimizing calls to GetNodes
410 //$all_nodes=$api->GetNodes(NULL,$node_columns);
411 //$slice_nodes=$api->GetNodes(array('node_id'=>$slice['node_ids']),$node_columns);
412 //$potential_nodes=$api->GetNodes(array('~node_id'=>$slice['node_ids']),$node_columns);
413
414
415 //NEW CODE FOR ENABLING COLUMN CONFIGURATION
416
417 //prepare fix and configurable columns
418
419 $fix_columns = array();
420 $fix_columns[]=array('tagname'=>'hostname', 'header'=>'hostname', 'type'=>'string', 'title'=>'The name of the node');
421 $fix_columns[]=array('tagname'=>'peer_id', 'header'=>'AU', 'type'=>'string', 'title'=>'Authority');
422 $fix_columns[]=array('tagname'=>'run_level', 'header'=>'ST', 'type'=>'string', 'title'=>'Status');
423 $fix_columns[]=array('tagname'=>'node_type', 'header'=>'RES', 'type'=>'string', 'title'=>'Reservable');
424
425 // columns that correspond to the visible tags for nodes (*node/ui*)
426 $visibletags = new VisibleTags ($api, 'node');
427 $visibletags->columns();
428 $tag_columns = $visibletags->headers();
429
430 //columns that are not defined as extra myslice tags
431 $extra_columns = array();
432 //MyPLC columns
433 $extra_columns[]=array('tagname'=>'sitename', 'header'=>'SN', 'type'=>'string', 'title'=>'Site name', 'fetched'=>true, 'source'=>'myplc');
434 $extra_columns[]=array('tagname'=>'domain', 'header'=>'DN', 'type'=>'string', 'title'=>'Toplevel domain name', 'fetched'=>true, 'source'=>'myplc');
435 $extra_columns[]=array('tagname'=>'ipaddress', 'header'=>'IP', 'type'=>'string', 'title'=>'IP Address', 'fetched'=>true, 'source'=>'myplc');
436 $extra_columns[]=array('tagname'=>'fcdistro', 'header'=>'OS', 'type'=>'string', 'title'=>'Operating system', 'fetched'=>false, 'source'=>'myplc');
437 $extra_columns[]=array('tagname'=>'date_created', 'header'=>'DA', 'source'=>'myplc', 'type'=>'date', 'title'=>'Date added', 'fetched'=>false);
438 $extra_columns[]=array('tagname'=>'arch', 'header'=>'A', 'source'=>'myplc', 'type'=>'string', 'title'=>'Architecture', 'fetched'=>false);
439 if (plc_is_admin()) {
440 $extra_columns[]=array('tagname'=>'deployment', 'header'=>'DL', 'source'=>'myplc', 'type'=>'string', 'title'=>'Deployment', 'fetched'=>false);
441 }
442
443 //CoMon Live data
444 $extra_columns[]=array('tagname'=>'bwlimit', 'header'=>'BW', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Bandwidth limit', 'fetched'=>false);
445 $extra_columns[]=array('tagname'=>'numcores', 'header'=>'CC', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Number of CPU Cores', 'fetched'=>false);
446 $extra_columns[]=array('tagname'=>'cpuspeed', 'header'=>'CR', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'CPU clock rate', 'fetched'=>false);
447 $extra_columns[]=array('tagname'=>'disksize', 'header'=>'DS', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Disk size', 'fetched'=>false);
448 $extra_columns[]=array('tagname'=>'gbfree', 'header'=>'DF', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Currently available disk space', 'fetched'=>false);
449 $extra_columns[]=array('tagname'=>'memsize', 'header'=>'MS', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Memory size', 'fetched'=>false);
450 $extra_columns[]=array('tagname'=>'numslices', 'header'=>'SM', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Number of slices in memory', 'fetched'=>false);
451 $extra_columns[]=array('tagname'=>'uptime', 'header'=>'UT', 'source'=>'comon', 'type'=>'sortAlphaNumericTop', 'title'=>'Continuous uptime until now', 'fetched'=>false);
452
453 //TopHat Live data
454 //$extra_columns[]=array('tagname'=>'hopcount', 'header'=>'HC', 'source'=>'tophat', 'type'=>'sortAlphaNumericTop', 'title'=>'Hop count from reference node', 'fetched'=>false);
455
456
457 //Get user's column configuration
458
459 $first_time_configuration = false;
460 $default_configuration = "hostname:f|ST:f|AU:f|RES:f";
461 //$extra_default = "";
462 $column_configuration = "";
463 $slice_column_configuration = "";
464
465 $show_configuration = "";
466 $show_reservable_message = '1';
467 $show_columns_message = '1';
468
469
470 //$PersonTags=$api->GetPersonTags (array('person_id'=>$plc->person['person_id']));
471 $PersonTags=$api->GetPersonTags (array('person_id'=>$plc->person['person_id']));
472 //print_r($PersonTags);
473 foreach ($PersonTags as $ptag) {
474         if ($ptag['tagname'] == 'columnconf')
475         {
476                 $column_configuration = $ptag['value'];
477                 $conf_tag_id = $ptag['person_tag_id'];
478         }
479         if ($ptag['tagname'] == 'showconf')
480         {
481                 $show_configuration = $ptag['value'];
482                 $show_tag_id = $ptag['person_tag_id'];
483         }
484 }
485
486 //print("<br>person column configuration = ".$column_configuration);
487 //print("<br>person show configuration = ".$show_configuration);
488
489 $sliceconf_exists = false;
490 if ($column_configuration == "")
491 {
492         $first_time_configuration = true;
493         $column_configuration = $slice_id.";default";
494         $sliceconf_exists = true;
495 }
496 else {
497         $slice_conf = explode(";",$column_configuration);
498         for ($i=0; $i<count($slice_conf); $i++ ) {
499                 if ($slice_conf[$i] == $slice_id)
500                 {
501                         $i++;
502                         $slice_column_configuration = $slice_conf[$i];
503                         $sliceconf_exists = true;
504                         break;
505                 }
506                 else
507                 {
508                         $i++;
509                         $slice_column_configuration = $slice_conf[$i];
510                 }
511         }        
512 }
513
514 if ($sliceconf_exists == false)
515         $column_configuration = $column_configuration.";".$slice_id.";default";
516
517 //print("<br>slice configuration = ".$slice_column_configuration);
518
519
520 if ($slice_column_configuration == "")
521         $full_configuration = $default_configuration;
522 else
523         $full_configuration = $default_configuration."|".$slice_column_configuration;
524
525
526 //instantiate the column configuration class, which prepares the headers array
527 $ConfigureColumns =new PlekitColumns($full_configuration, $fix_columns, $tag_columns, $extra_columns);
528
529 $visiblecolumns = $ConfigureColumns->node_tags();
530
531 $node_columns=array_merge($node_fixed_columns,$visiblecolumns);
532 //print_r($node_columns);
533 $all_nodes=$api->GetNodes(NULL,$node_columns);
534
535 $ConfigureColumns->fetch_live_data($all_nodes);
536
537 //print("<br>person show configuration = ".$show_configuration);
538
539 $show_conf = explode(";",$show_configuration);
540 foreach ($show_conf as $ss) {
541         if ($ss =="reservable")
542                 $show_reservable_message = '0';
543         if ($ss =="columns")
544                 $show_columns_message = '0';
545 }        
546
547 //print("res:".$show_reservable_message." - cols:".$show_columns_message);
548
549 $slice_nodes=array();
550 $potential_nodes=array();
551 $reservable_nodes=array();
552 foreach ($all_nodes as $node) {
553   if (in_array($node['node_id'],$slice['node_ids'])) {
554     $slice_nodes[]=$node;
555     if ($node['node_type']=='reservable') $reservable_nodes[]=$node;
556   } else {
557     $potential_nodes[]=$node;
558   }
559 }
560 if ($profiling) plc_debug_prof('5: nodes',count($slice_nodes));
561 ////////////////////
562 // outline the number of reservable nodes
563 $nodes_message=count_english($slice_nodes,"node");
564 if (count($reservable_nodes)) $nodes_message .= " (" . count($reservable_nodes) . " reservable)";
565 $toggle=new PlekitToggle ('my-slice-nodes',$nodes_message,
566                           array('bubble'=>
567                                 'Manage nodes attached to this slice',
568                                 'visible'=>get_arg('show_nodes',false)));
569 $toggle->start();
570
571
572 //////////////////// reservable nodes area
573
574 $count=count($reservable_nodes);
575 if ($count && $privileges) {
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'=>$show_reservable_message, 'info_div'=>'note_reservable_div'));
580   $toggle_nodes->start();
581
582 if ($show_reservable_message) 
583 $note_display = "";
584 else
585 $note_display = "display:none;";
586
587 ////////// show a notice to people having attached a reservable node
588 if (count($reservable_nodes) && $privileges) {
589   $mark=reservable_mark();
590   print <<<EOF
591 <br>
592 <div id='note_reservable_div' style="align:center; background-color:#CAE8EA; padding:4px; width:800px; $note_display">
593 <table align=center><tr><td valign=top>
594 You have attached one or more reservable nodes to your slice. 
595 Reservable nodes show up with the '$mark' mark. 
596 Your slivers will be available only during timeslots
597 where you have obtained leases. 
598 You can manage your leases in the tab below.
599 <br>
600 This feature is still experimental; feedback is appreciated at <a href="mailto:devel@planet-lab.org">devel@planet-lab.org</a>
601 </td><td valign=top><span onClick=closeMessage('reservable')><img class='reset' src="/planetlab/icons/clear.png" alt="hide message"></span>
602 </td></tr></table>
603 </div>
604 EOF;
605 }  
606
607   // get settings from environment, otherwise set to defaults
608   // when to start, in hours in the future from now
609   $leases_offset=$_GET['leases_offset'];
610   if ( ! $leases_offset ) $leases_offset=0;
611   // how many timeslots to show
612   $leases_slots=$_GET['leases_slots'];
613   if ( ! $leases_slots ) $leases_slots = 36;
614   // offset in hours (in the future) from now 
615   $leases_w = $_GET['leases_w'];
616   if ( ! $leases_w) $leases_w=20;
617   // number of timeslots to display
618
619   $granularity=$api->GetLeaseGranularity();
620
621   // these elements are for passing data to the javascript layer
622   echo "<span class='hidden' id='leases_slicename'>" . $slice['name'] . "</span>";
623   echo "<span class='hidden' id='leases_slice_id'>" . $slice['slice_id']. "</span>";
624   echo "<span class='hidden' id='leases_granularity'>" . $granularity . "</span>";
625   echo "<span class='hidden' id='leases_offset'>" . $leases_offset . "</span>";
626   echo "<span class='hidden' id='leases_slots'>" . $leases_slots . "</span>";
627   echo "<span class='hidden' id='leases_w'>" . $leases_w . "</span>";
628
629   // leases_data is the name used by leases.js to locate this place
630   // first population will be triggered by init_scheduler from leases.js
631   echo "<table id='leases_data' class='hidden'></table>";
632
633   // the general layout for the scheduler
634   echo <<< EOF
635 <div id='leases_area'></div>
636
637 <div id='leases_buttons'>
638   <button id='leases_refresh' type='submit'>Refresh</button>
639   <button id='leases_submit' type='submit'>Submit</button>
640 </div>
641 EOF;
642
643   $toggle_nodes->end();
644  }
645
646
647 //////////////////// node configuration panel
648
649 if ($first_time_configuration) 
650 $column_conf_visible = '1';
651 else
652 $column_conf_visible = '0';
653
654
655 $toggle_nodes=new PlekitToggle('my-slice-nodes-configuration',
656                                "Node table layout",
657                                array('visible'=>$column_conf_visible, 'info_div'=>'note_columns_div'));
658 $toggle_nodes->start();
659
660 //usort ($table_headers, create_function('$col1,$col2','return strcmp($col1["header"],$col2["header"]);'));
661 //print("<p>TABLE HEADERS<p>");
662 //print_r($table_headers);
663
664 print("<div id='debug'></div>");
665 print("<input type='hidden' id='slice_id' value='".$slice['slice_id']."' />");
666 print("<input type='hidden' id='person_id' value='".$plc->person['person_id']."' />");
667 print("<input type='hidden' id='conf_tag_id' value='".$conf_tag_id."' />");
668 print("<input type='hidden' id='show_tag_id' value='".$show_tag_id."' />");
669 print("<input type='hidden' id='show_configuration' value='".$show_configuration."' />");
670 print("<input type='hidden' id='column_configuration' value='".$slice_column_configuration."' />");
671 print("<br><input type='hidden' size=80 id='full_column_configuration' value='".$column_configuration."' />");
672 print("<input type='hidden' id='previousConf' value='".$slice_column_configuration."' />");
673 print("<input type='hidden' id='defaultConf' value='".$default_configuration."' />");
674
675 //print ("showing column message = ".$show_columns_message);
676 if ($show_columns_message == '0') 
677 $note_display = "display:none;";
678 else
679 $note_display = "";
680
681   print <<<EOF
682 <div id='note_columns_div' style="align:center; background-color:#CAE8EA; padding:4px; width:800px; $note_display">
683 <table align=center><tr><td valign=top>
684 This tab allows you to customize the columns in the node tables, below. Information on the nodes comes from a variety of monitoring sources. If you, as either a user or a provider of monitoring data, would like to see additional columns made available, please send us your request in mail to <a href="mailto:support@myslice.info">support@myslice.info</a>. You can find more information about the MySlice project at <a href="http://trac.myslice.info">http://trac.myslice.info</a>.
685 </td><td valign=top><span onClick=closeMessage('columns')><img class='reset' src="/planetlab/icons/clear.png" alt="hide message permanently"></span>
686 </td></tr></table>
687 </div>
688 EOF;
689
690 $ConfigureColumns->configuration_panel_html(true);
691
692 $ConfigureColumns->javascript_init();
693
694 $toggle_nodes->end();
695
696
697 $all_sites=$api->GetSites(NULL, array('site_id','login_base'));
698 $site_hash=array();
699 foreach ($all_sites as $tmp_site) $site_hash[$tmp_site['site_id']]=$tmp_site['login_base'];
700
701 $interface_columns=array('ip','node_id','interface_id');
702 $interface_filter=array('is_primary'=>TRUE);
703 $interfaces=$api->GetInterfaces($interface_filter,$interface_columns);
704
705 $interface_hash=array();
706 foreach ($interfaces as $interface) $interface_hash[$interface['node_id']]=$interface;
707
708
709
710
711
712 //////////////////// nodes currently in
713 $toggle_nodes=new PlekitToggle('my-slice-nodes-current',
714                                count_english($slice_nodes,"node") . " currently in $name",
715                                array('visible'=>get_arg('show_nodes_current',!$privileges)));
716 $toggle_nodes->start();
717
718 $headers=array();
719 $notes=array();
720 //$notes=array_merge($notes,$visibletags->notes());
721 $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";
722
723 /*
724 $headers['peer']='string';
725 $headers['hostname']='string';
726 $short="-S-"; $long=Node::status_footnote(); $type='string'; 
727         $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
728 $short=reservable_mark(); $long=reservable_legend(); $type='string';
729         $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
730 // the extra tags, configured for the UI
731 $headers=array_merge($headers,$visibletags->headers());
732
733 if ($privileges) $headers[plc_delete_icon()]="none";
734 */
735
736 $edit_header = array();
737 if ($privileges) $edit_header[plc_delete_icon()]="none";
738 $headers = array_merge($ConfigureColumns->get_headers(),$edit_header);
739
740 //print("<p>HEADERS<p>");
741 //print_r($headers);
742
743 $table_options = array('notes'=>$notes,
744                        'search_width'=>15,
745                        'pagesize'=>20,
746                         'configurable'=>true);
747
748 $table=new PlekitTable('nodes',$headers,NULL,$table_options);
749
750 $form=new PlekitForm(l_actions(),array('slice_id'=>$slice['slice_id']));
751 $form->start();
752 $table->start();
753 if ($slice_nodes) foreach ($slice_nodes as $node) {
754   $table->row_start();
755
756 $table->cell($node['node_id'], array('display'=>'none'));
757
758   $table->cell(l_node_obj($node));
759   $peers->cell($table,$node['peer_id']);
760   $run_level=$node['run_level'];
761   list($label,$class) = Node::status_label_class_($node);
762   $table->cell ($label,array('class'=>$class));
763   $table->cell( ($node['node_type']=='reservable')?reservable_mark():"" );
764
765   $hostname=$node['hostname'];
766   $ip=$interface_hash[$node['node_id']]['ip'];
767   $interface_id=$interface_hash[$node['node_id']]['interface_id'];
768
769 //extra columns
770 $node['domain'] = topdomain($hostname);
771 $node['sitename'] = l_site_t($node['site_id'],$site_hash[$node['site_id']]);
772 if ($interface_id)
773         $node['ipaddress'] = l_interface_t($interface_id,$ip);
774   else
775         $node['ipaddress'] = "n/a";
776
777  //foreach ($visiblecolumns as $tagname) $table->cell($node[$tagname]);
778  $ConfigureColumns->cells($table, $node);
779
780   if ($privileges) $table->cell ($form->checkbox_html('node_ids[]',$node['node_id']));
781   $table->row_end();
782 }
783 // actions area
784 if ($privileges) {
785
786   // remove nodes
787   $table->tfoot_start();
788
789   $table->row_start();
790   $table->cell($form->submit_html ("remove-nodes-from-slice","Remove selected"),
791                array('hfill'=>true,'align'=>'right'));
792   $table->row_end();
793  }
794 $table->end();
795 $toggle_nodes->end();
796
797 //////////////////// nodes to add
798 if ($privileges) {
799   $new_potential_nodes = array();
800   if ($potential_nodes) foreach ($potential_nodes as $node) {
801       $emptywl=empty($node['slice_ids_whitelist']);
802       $inwl = (!emptywl) and in_array($slice['slice_id'],$node['slice_ids_whitelist']);
803       if ($emptywl or $inwl)
804         $new_potential_nodes[]=$node;
805   }
806   $potential_nodes=$new_potential_nodes;
807
808   $count=count($potential_nodes);
809   $toggle_nodes=new PlekitToggle('my-slice-nodes-add',
810                                  count_english($potential_nodes,"more node") . " available",
811                                  array('visible'=>get_arg('show_nodes_add',false)));
812   $toggle_nodes->start();
813
814   if ( $potential_nodes ) {
815     $headers=array();
816     $notes=array();
817
818
819 /*
820     $headers['peer']='string';
821     $headers['hostname']='string';
822     $short="-S-"; $long=Node::status_footnote(); $type='string'; 
823         $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
824         $short=reservable_mark(); $long=reservable_legend(); $type='string';
825         $headers[$short]=array('type'=>$type,'title'=>$long); $notes []= "$short = $long";
826     // the extra tags, configured for the UI
827     $headers=array_merge($headers,$visibletags->headers());
828     $headers['+']="none";
829 */
830
831     $add_header = array();
832     $add_header['+']="none";
833     $headers = array_merge($ConfigureColumns->get_headers(),$add_header);
834
835     //$notes=array_merge($notes,$visibletags->notes());
836 $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";
837     
838     $table=new PlekitTable('add_nodes',$headers,NULL, $table_options);
839     $form=new PlekitForm(l_actions(),
840                          array('slice_id'=>$slice['slice_id']));
841     $form->start();
842     $table->start();
843     if ($potential_nodes) foreach ($potential_nodes as $node) {
844         $table->row_start();
845
846 $table->cell($node['node_id'], array('display'=>'none'));
847
848         $table->cell(l_node_obj($node));
849         $peers->cell($table,$node['peer_id']);
850         list($label,$class) = Node::status_label_class_($node);
851         $table->cell ($label,array('class'=>$class));
852         $table->cell( ($node['node_type']=='reservable')?reservable_mark():"" );
853
854         //extra columns
855           $hostname=$node['hostname'];
856           $ip=$interface_hash[$node['node_id']]['ip'];
857           $interface_id=$interface_hash[$node['node_id']]['interface_id'];
858         $node['domain'] = topdomain($hostname);
859         $node['sitename'] = l_site_t($node['site_id'],$site_hash[$node['site_id']]);
860         $node['ipaddress'] = l_interface_t($interface_id,$ip);
861
862         //foreach ($visiblecolumns as $tagname) $table->cell($node[$tagname]);
863         $ConfigureColumns->cells($table, $node);
864
865         $table->cell ($form->checkbox_html('node_ids[]',$node['node_id']));
866         $table->row_end();
867       }
868     // add nodes
869     $table->tfoot_start();
870     $table->row_start();
871     $table->cell($form->submit_html ("add-nodes-in-slice","Add selected"),
872                  array('hfill'=>true,'align'=>'right'));
873     $table->row_end();
874     $table->end();
875     $form->end();
876   }
877   $toggle_nodes->end();
878 }
879
880 $toggle->end();
881
882 // very wide values get abbreviated
883 $tag_value_threshold=24;
884 //////////////////////////////////////////////////////////// Tags
885 //if ( $local_peer ) {
886   $tags=$api->GetSliceTags (array('slice_id'=>$slice_id));
887   if ($profiling) plc_debug_prof('8 slice tags',count($tags));
888   function get_tagname ($tag) { return $tag['tagname'];}
889   $tagnames = array_map ("get_tagname",$tags);
890   
891   $toggle = new PlekitToggle ('slice-tags',count_english_warning($tags,'tag'),
892                               array('bubble'=>'Inspect and set tags on tat slice',
893                                     'visible'=>get_arg('show_tags',false)));
894   $toggle->start();
895   
896   $headers=array(
897     "Name"=>"string",
898     "Value"=>"string",
899     "Node"=>"string",
900     "NodeGroup"=>"string");
901   if ($tags_privileges) $headers[plc_delete_icon()]="none";
902   
903   $table_options=array("notes_area"=>false,"pagesize_area"=>false,"search_width"=>10);
904   $table=new PlekitTable("slice_tags",$headers,'0',$table_options);
905   $form=new PlekitForm(l_actions(),
906                        array('slice_id'=>$slice['slice_id']));
907   $form->start();
908   $table->start();
909   if ($tags) {
910     // Get hostnames for nodes in a single pass
911     $_node_ids = array();
912     foreach ($tags as $tag) {
913       if ($tag['node_id']) {
914         array_push($_node_ids, $tag['node_id']);
915       }
916     }
917     $_nodes = $api->GetNodes(array('node_id' => $_node_ids), array('node_id', 'hostname'));
918     $_hostnames = array();
919     foreach ($_nodes as $_node) {
920       $_hostnames[$_node['node_id']] = $_node['hostname'];
921     }
922
923     // Loop through tags again to display
924     foreach ($tags as $tag) {
925       $node_name = "ALL";
926       if ($tag['node_id']) {
927         $node_name = $_hostnames[$tag['node_id']];
928       }
929       $nodegroup_name="n/a";
930       if ($tag['nodegroup_id']) { 
931         $nodegroups=$api->GetNodeGroups(array('nodegroup_id'=>$tag['nodegroup_id']));
932         if ($profiling) plc_debug_prof('10 nodegroup for slice tag',$nodegroup);
933         if ($nodegroup) {
934           $nodegroup = $nodegroups[0];
935           $nodegroup_name = $nodegroup['groupname'];
936         }
937       }
938       $table->row_start();
939       $table->cell(l_tag_obj($tag));
940       // very wide values get abbreviated
941       $table->cell(truncate_and_popup($tag['value'],$tag_value_threshold));
942       $table->cell($node_name);
943       $table->cell($nodegroup_name);
944       if ($tags_privileges) $table->cell ($form->checkbox_html('slice_tag_ids[]',$tag['slice_tag_id']));
945       $table->row_end();
946     }
947   }
948   if ($tags_privileges) {
949     $table->tfoot_start();
950     $table->row_start();
951     $table->cell($form->submit_html ("delete-slice-tags","Remove selected"),
952                  array('hfill'=>true,'align'=>'right'));
953     $table->row_end();
954     
955     $table->row_start();
956     function tag_selector ($tag) {
957       return array("display"=>$tag['tagname'],"value"=>$tag['tag_type_id']);
958     }
959     $all_tags= $api->GetTagTypes( array ("category"=>"slice*","-SORT"=>"+tagname"), array("tagname","tag_type_id"));
960     if ($profiling) plc_debug_prof('11 tagtypes',count($all_tags));
961     $selector_tag=array_map("tag_selector",$all_tags);
962     
963     function node_selector($node) { 
964       return array("display"=>$node["hostname"],"value"=>$node['node_id']);
965     }
966     $selector_node=array_map("node_selector",$slice_nodes);
967     
968     function nodegroup_selector($ng) {
969       return array("display"=>$ng["groupname"],"value"=>$ng['nodegroup_id']);
970     }
971     $all_nodegroups = $api->GetNodeGroups( array("groupname"=>"*"), array("groupname","nodegroup_id"));
972     if ($profiling) plc_debug_prof('13 nodegroups',count($all_nodegroups));
973     $selector_nodegroup=array_map("nodegroup_selector",$all_nodegroups);
974     
975     $table->cell($form->select_html("tag_type_id",$selector_tag,array('label'=>"Choose Tag")));
976     $table->cell($form->text_html("value","",array('width'=>8)));
977     $table->cell($form->select_html("node_id",$selector_node,array('label'=>"All Nodes")));
978     $table->cell($form->select_html("nodegroup_id",$selector_nodegroup,array('label'=>"No Nodegroup")));
979     $table->cell($form->submit_html("add-slice-tag","Set Tag"),array('columns'=>2,'align'=>'left'));
980     $table->row_end();
981   }
982     
983   $table->end();
984   $form->end();
985   $toggle->end();
986 //}
987
988
989 //////////////////////// renew slice
990 if ($local_peer ) {
991   if ( ! $renew_visible) renew_area ($slice,$site,false);
992  }
993
994 $peers->block_end($peer_id);
995
996 if ($profiling) plc_debug_prof_end();
997
998 // Print footer
999 include 'plc_footer.php';
1000
1001 ?>