d43ada614868d0edfd1935a5a8f9650a7e4c51d2
[plewww.git] / planetlab / nodes / node_downloads.php
1 <?php
2
3   // $Id$
4
5   // cleaned up, keep only the actions related to downloading stuff
6   // REQUIRED : node_id=node_id
7   // (*) action='download-node-floppy' : 
8   // (*) action='download-node-iso' : 
9   // (*) action='download-node-usb' : 
10   //                            : same as former downloadconf.php with download unset
11   //     if in addition POST contains a non-empty field 'download' :
12   //                            : performs actual node-dep download
13   // (*) action='download-generic-iso':
14   // (*) action='download-generic-usb':
15   //                            : performs actual generic download
16
17 // delivering node-dependant images requires larger memory limit
18 // trial and error, based on the current sizes
19 // generic-ISO 43980800 
20 // generic-usb 44720128 
21 // 256M OK
22 // 128M OK
23 // 96M OK
24 // 88M KO
25 // 80M KO
26 // 64M KO
27 // Bottom line is, looks like we need in the order of twice the file size
28 // so let's play it safe
29 // Thierry - for 4.2, we need a larger area, was 100 for 4.1
30 ini_set("memory_limit","150M");
31
32 // Require login
33 require_once 'plc_login.php';
34
35 // Get session and API handles
36 require_once 'plc_session.php';
37 global $plc, $api;
38
39 // Common functions
40 require_once 'plc_functions.php';
41 require_once 'details.php';
42
43 // NOTE: this function exits() after it completes its job, 
44 // simply returning leads to html decorations being added around the contents
45 function deliver_and_unlink ($filename) {
46   
47   // for security reasons we want to be able to unlink the resulting file once downloaded
48   // so simply redirecting through a header("Location:") is not good enough
49
50   $size= filesize($filename);
51
52   // headers
53   header ("Content-Type: application/octet-stream");
54   header ("Content-Transfer-Encoding: binary");
55   header ("Content-Disposition: attachment; filename=" . basename($filename) );
56   header ("Content-Length: " . $size );
57   // for getting IE to work properly
58   // from princeton cvs new_plc_www/planetlab/nodes/downloadconf.php 1.2->1.3
59   header ("Pragma: hack");
60   header ("Cache-Control: public, must-revalidate");
61
62   // turn off output buffering
63   ob_end_flush();
64   // outputs the whole file contents without copying it to memory
65   readfile($filename);
66  
67   // unlink the file
68   if (! unlink ($filename) ) {
69     // cannot unlink, but how can we notify this ?
70     // certainly not by printing
71   }
72   exit();
73 }
74
75 function show_download_confirm_button ($api, $node_id, $action, $can_gen_config, $show_details) {
76
77   if( $can_gen_config ) {
78     if ($show_details) {
79       $preview=$api->GetBootMedium($node_id,"node-preview","");
80       print ("<hr />");
81       print ("<h3 class='node_download'>Configuration file contents</h3>");
82       print ("<pre>\n$preview</pre>\n");
83       print ("<hr />");
84     }
85     $action_labels = array ('download-node-floppy' => 'textual node config (for floppy)' ,
86                             'download-node-iso' => 'ISO image',
87                             'download-node-usb' => 'USB image' );
88     
89     $format = $action_labels [ $action ] ;
90     print( "<div id='download_button'> <form method='post' action='node_downloads.php'>");
91     print ("<input type='hidden' name='node_id' value='$node_id'>");
92     print ("<input type='hidden' name='action' value='$action'>");
93     print ("<input type='hidden' name='download' value='1'>");
94     print( "<input type='submit' value='Download $format'>" );
95     print( "</form></div>\n" );
96   } else {
97     echo "<p><font color=red>Configuration file cannot be created until missing values above are updated.</font>";
98   }
99 }
100
101 // check arguments
102
103 if (empty($_POST['node_id'])) {
104   plc_redirect (l_nodes());
105  } else {
106   $node_id = intval($_POST['node_id']);
107 }
108
109 $action=$_POST['action'];
110
111 switch ($action) {
112
113  case "download-generic-iso":
114  case "download-generic-usb":
115    
116    if ($action=="download-generic-iso") {
117      $boot_action="generic-iso";
118    } else {
119      $boot_action="generic-usb";
120    }
121
122    // place the result in a random-named sub dir for clear filenames
123    $filename = $api->GetBootMedium ($node_id, $boot_action, "%d/%n-%p-%a-%v%s");
124    $error=$api->error();
125    // NOTE. for some reason, GetBootMedium sometimes does not report an error but the
126    // file is not created - this happens e.g. when directory owmer/modes are wrong 
127    // in this case we get an empty filename
128    // see /etc/httpd/logs/error_log in this case
129    if (empty($error) && empty($filename)) {
130      $error="Unexpected error from GetBootMedium - probably wrong directory modes";
131    }    
132    if (! empty($error)) {
133      print ("<div class='plc-error'> $error </div>\n");
134      print ("<p><a href='/db/nodes/index.php?id=$node_id'>Back to node </a>\n");
135      return ;
136    } else {
137      deliver_and_unlink ($filename);
138      exit();
139    }
140    break;
141
142    // ACTION: download-node
143    // from former downloadconf.php
144    
145  case "download-node-floppy":
146  case "download-node-iso":
147  case "download-node-usb":
148  case "download-node-usb-partition":
149
150    
151    $nodes = $api->GetNodes( array( $node_id ) );
152    $node = $nodes[0];
153
154    // non-admin people need to be affiliated with the right site
155    if( ! plc_is_admin() ) {
156      $node_site_id = $node['site_id'];
157      $in_site = plc_in_site($node_site_id);
158      if( ! $in_site) {
159        $error= "Insufficient permission. You cannot create configuration files for this node.";
160      }
161    }
162
163    $hostname= $node['hostname'];
164    // search for the primary interface
165    $interfaces = $api->GetInterfaces( array( "node_id" => $node_id, "is_primary"=>true ), NULL );
166    
167    $can_gen_config= 1;
168
169    if ( ! $interfaces ) {
170      $can_gen_config= 0;
171    } else {
172      $interface = $interfaces[0];
173      if ( $node['hostname'] == "" ) {
174        $can_gen_config= 0;
175        $node['hostname']= plc_warning("Missing");
176      }
177      
178      # fields to check
179      $fields= array("method","ip");
180      if ( $interface['method'] == "static" ) 
181        $fields = array_merge ( $fields, array("gateway","netmask","network","broadcast","dns1"));
182      foreach( $fields as $field ) {
183        if( $interface[$field] == "" ) {
184          $can_gen_config= 0;
185          $interface[$field]= plc_warning("Missing");
186        }
187      }
188
189      if(    $interface['method'] != "static" 
190          && $interface['method'] != "dhcp" ) {
191        $can_gen_config= 0;
192        $interface['method']= "<i>Unknown method</i>";
193      }
194    }
195
196    $download= $_POST['download'];
197    
198    if( $can_gen_config && !empty($download) ) {
199      switch ($action) {
200      case 'download-node-floppy':
201        $boot_action='node-floppy'; 
202        $location = "%d/%n-%v-rename-into-plnode%s";
203        $options = array();
204        break;
205      case 'download-node-iso':
206        $boot_action='node-iso';
207        $location = "%d/%n-%a-%v%s";
208        $options = array();
209        break;
210      case 'download-node-usb':
211        $boot_action='node-usb';
212        $location = "%d/%n-%a-%v%s";
213        $options = array();
214        break;
215      case "download-node-usb-partition":
216        $boot_action='node-usb';
217        $location = "%d/%n-%a-%v-partition%s";
218        $options = array('partition');
219        break;
220      }   
221
222      $filename=$api->GetBootMedium($node_id,$boot_action,$location,$options);
223      $error=$api->error();
224      if (empty($error) && empty($filename)) {
225        $error="Unexpected error from GetBootMedium - probably wrong directory modes";
226      }    
227      if (! empty($error)) {
228        print ("<div class='plc-error'> $error </div>\n");
229        print ("<p><a href='/db/nodes/index.php?id=$node_id'>Back to node </a>\n");
230        return ;
231      } else {
232        deliver_and_unlink ($filename);
233        exit();
234      }
235    }
236
237    drupal_set_title("Download boot medium for $hostname");
238
239    $header= <<<EOF
240 <p class='node_download'>
241 <span class='bold'>WARNING:</span> Downloading a new boot medium
242 for this node will generate <span class='bold'>a new node key</span>, and any 
243 formerly downloaded boot medium for that node will become <span class='bold'>outdated</span>.
244 <br/>
245 <br/>
246 In order to create a configuration file for this node using this page,
247 the interface settings must be up to date. Below is summary of these
248 values. 
249 </p>
250
251 EOF;
252
253    echo $header;
254
255    show_download_confirm_button($api, $node_id, $action, $can_gen_config, false);
256    print ("<hr />");
257    print ("<h3 class='node_download'>Current node configuration</h3>");
258
259    $details = new PlekitDetails (false);
260    $details->start();
261
262    if( ! $interface ) {
263      print ("<center>");
264      print (plc_warning("This node has no configured primary interface."));
265      print ("You can add one " . href(l_interface_add($node_id), "here "));
266      print ("</center>");
267    } else {
268      $details->tr(l_node_t($node_id,"Node details"),"center");
269      $details->th_td("node_id",$node_id);
270      $details->th_td("Hostname",$node['hostname']);
271
272      $interface_id = $interface['interface_id'];
273      $details->tr(l_interface_t($interface_id,"Interface Details"),"center");
274      $details->th_td("Method",$interface['method']);
275      $details->th_td("IP",$interface['ip']);
276
277      if( $interface['method'] == "static" ) {
278        $details->th_td("Gateway",$interface['gateway']);
279        $details->th_td("Network mask",$interface['netmask']);
280        $details->th_td("Network address",$interface['network']);
281        $details->th_td("Broadcast address",$interface['broadcast']);
282        $details->th_td("DNS 1",$interface['dns1']);
283        if ($interface['dns2'])
284          $details->th_td("DNS 2",$interface['dns2']);
285       }
286
287      $details->tr(href(l_interface_tags($interface_id),"Interface extra settings (tags)"),"center");
288      $interface_id = $interface['interface_id'];
289      $settings=$api->GetInterfaceTags(array("interface_id" => array($interface_id)));
290      if ( ! $settings) {
291        $details->tr("no tag set","center");
292      } else foreach ($settings as $setting) {
293        $category=$setting['category'];
294        $name=$setting['tagname'];
295        $value=$setting['value'];
296        $details->th_td($category . " " . $name,$value);
297      }
298    }
299    $details->end();
300
301  show_download_confirm_button($api, $node_id, $action, $can_gen_config, true);
302  break;
303  
304  default:
305    drupal-set_error("Unkown action $action in node_downloads.php");
306    plc_redirect (l_node($node_id));
307    break;
308  }
309
310 ?>