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