3 // $Id: node_actions.php 1184 2008-02-12 20:33:35Z thierry $
4 // This file was created when we decided to make the node page consistent with the other pages
5 // That is to say, we wanted the 'Update' and 'Delete' functions to appear in a drop-down
6 // menu like for the other objects
7 // It appeared after analysis that it was easier to have the following
8 // functions gathered in a single php file
11 // displays current settings and prompt for changes before going to node_actions.php
12 // (*) node_actions.php
13 // (GET) 'del=node_id'
14 // (GET) 'update=node_id' -> actual UpdateNode
15 // (POST) node_id=node_id ng_add=nodegroup_id
17 // (POST) boot_state=boot_state node_id=node_id
18 // (POST) ng_add=nodegroup_id
19 // (*) downloadconf.php
20 // (GET) id=node_id [download=1]
21 // either showed current status, or performed actual config download
23 // in this new version we support only POST behaviour with the following interface
24 // REQUIRED : node_id=node_id
25 // (*) action='prompt-update' : former node_update.php
26 // (*) action='update'
28 // model= : actually updated the node
29 // (*) action='boot-state'
30 // boot_state= : changes bootstate
31 // (*) action='delete' : deletes node
32 // (*) action='download-node-floppy' :
33 // (*) action='download-node-iso' :
34 // (*) action='download-node-usb' :
35 // : same as former downloadconf.php with download unset
36 // if in addition POST contains a non-empty field 'download' :
37 // : performs actual node-dep download
38 // (*) action='download-generic-iso':
39 // (*) action='download-generic-usb':
40 // : performs actual generic download
41 // (*) action='add-in-nodegroup': should include this for compatibility, replaces ng_add,
42 // though I could not figure where it's called
45 // TODO : manage a post field for displaying results of previous page
46 // see the special 'flash' in rails
48 // delivering node-dependant images requires larger memory limit
49 // trial and error, based on the current sizes
50 // generic-ISO 43980800
51 // generic-usb 44720128
58 // Bottom line is, looks like we need in the order of twice the file size
59 // so let's play it safe
60 // Thierry - for 4.2, we need a larger area, was 100 for 4.1
61 ini_set("memory_limit","150M");
64 require_once 'plc_login.php';
66 // Get session and API handles
67 require_once 'plc_session.php';
71 require_once 'plc_functions.php';
72 require_once 'plc_sorts.php';
75 $_person= $plc->person;
76 $_roles= $_person['role_ids'];
78 // NOTE: this function exits() after it completes its job,
79 // simply returning leads to html decorations being added around the contents
80 function deliver_and_unlink ($filename) {
82 // for security reasons we want to be able to unlink the resulting file once downloaded
83 // so simply redirecting through a header("Location:") is not good enough
85 $size= filesize($filename);
88 header ("Content-Type: application/octet-stream");
89 header ("Content-Transfer-Encoding: binary");
90 header ("Content-Disposition: attachment; filename=" . basename($filename) );
91 header ("Content-Length: " . $size );
92 // for getting IE to work properly
93 // from princeton cvs new_plc_www/planetlab/nodes/downloadconf.php 1.2->1.3
94 header ("Pragma: hack");
95 header ("Cache-Control: public, must-revalidate");
97 // outputs the whole file contents
98 print (file_get_contents($filename));
101 if (! unlink ($filename) ) {
102 // cannot unlink, but how can we notify this ?
103 // certainly not by printing
108 function show_download_confirm_button($api, $node_id, $action, $can_gen_config, $show_details) {
110 if( $can_gen_config ) {
111 if ($show_details && method_exists($api,"GetBootMedium")) {
112 $preview=$api->GetBootMedium($node_id,"node-preview","");
113 print ("<hr /> <h3>Current node configuration contents</h3>");
114 print ("<pre>\n$preview</pre>\n");
117 $action_labels = array ('download-node-floppy' => 'textual node config (for floppy)' ,
118 'download-node-iso' => 'ISO image',
119 'download-node-usb' => 'USB image' );
121 $format = $action_labels [ $action ] ;
122 print( "<p><form method='post' action='node_actions.php'>\n");
123 print ("<input type='hidden' name='node_id' value='$node_id'>\n");
124 print ("<input type='hidden' name='action' value='$action'>\n");
125 print ("<input type='hidden' name='download' value='1'>\n");
126 print( "<input type='submit' value='Download $format'>\n" );
127 print( "</form>\n" );
129 echo "<p><font color=red>Configuration file cannot be created until missing values above are updated.</font>";
135 if (empty($_POST['node_id'])) {
136 header ('location:index.php');
139 $node_id = intval($_POST['node_id']);
142 $action=$_POST['action'];
146 // ACTION: prompt-update
147 // from former node_update.php
148 case "prompt-update":
150 require_once('plc_drupal.php');
151 $node_info= $api->GetNodes( array( $node_id ), array( "hostname", "model" ) );
152 drupal_set_title("Updating " . $node_info[0]['hostname']);
153 include 'plc_header.php';
156 echo "<form method=post action='node_actions.php'>\n";
157 echo "<input type=hidden name='node_id' value='$node_id'></input>\n";
158 echo "<input type=hidden name='action' value='update'></input>\n";
159 if( $_POST['error'] ) echo "<font color=red>". unserialize( $_POST['error'] ."</font>\n" );
160 echo "<p><table cellpadding=2><tbody>\n
161 <tr><th>Hostname: </th><td> <input type=text size=35 name='hostname' value='". $node_info[0]['hostname'] ."'></td></tr>\n
162 <tr><th>Model: </th><td> <input type=text size=35 name='model' value='". $node_info[0]['model'] ."'></td></tr>\n
164 <p><input type=submit value='Update Node'>\n
167 echo "<p><a href='index.php?id=$node_id'>Back to Node</a>\n";
172 // from former node_actions.php
175 $hostname= $_POST['hostname'];
176 $model= $_POST['model'];
178 $fields= array( "hostname"=>$hostname, "model"=>$model );
179 $api->UpdateNode( intval( $node_id ), $fields );
180 $error= $api->error();
182 if( empty( $error ) ) {
183 header( "location: index.php?id=$node_id" );
186 echo "<font color=red>". $error . "</font>\n" ;
187 echo "<p> Press back to retry</p>";
193 // from former node_actions.php
195 $api->DeleteNode( intval( $node_id ) );
196 header( "location: index.php" );
200 // ACTION: boot-state
201 // from former node_actions.php
203 switch( $_POST['boot_state'] ) {
210 $api->UpdateNode( intval( $node_id ), array( "boot_state" => $_POST['boot_state'] ) );
211 header( "location: index.php?id=$node_id" );
215 print "<div class='plc-error'> no such boot state " . $_POST['boot_state'] . "</div>";
220 // ACTION: download-generic
221 case "download-generic-iso":
222 case "download-generic-usb":
224 if ( ! method_exists($api,"GetBootMedium")) {
225 print ("<span class='plc-warning'> API lacks support for GetBootMedium </span>");
229 if ($action=="download-generic-iso") {
230 $boot_action="generic-iso";
232 $boot_action="generic-usb";
235 // place the result in a random-named sub dir for clear filenames
236 $filename = $api->GetBootMedium ($node_id, $boot_action, "%d/%n-%p-%a-%v%s");
237 $error=$api->error();
238 // NOTE. for some reason, GetBootMedium sometimes does not report an error but the
239 // file is not created - this happens e.g. when directory owmer/modes are wrong
240 // in this case we get an empty filename
241 // see /etc/httpd/logs/error_log in this case
242 if (empty($error) && empty($filename)) {
243 $error="Unexpected error from GetBootMedium - probably wrong directory modes";
245 if (! empty($error)) {
246 print ("<div class='plc-error'> $error </div>\n");
247 print ("<p><a href='/db/nodes/index.php?id=$node_id'>Back to node </a>\n");
250 deliver_and_unlink ($filename);
255 // ACTION: download-node
256 // from former downloadconf.php
258 case "download-node-floppy":
259 case "download-node-iso":
260 case "download-node-usb":
262 $return= $api->GetNodes( array( $node_id ) );
263 $node_detail= $return[0];
265 // non-admin people need to be affiliated with the right site
266 if( !in_array( 10, $_roles ) ) {
267 $node_site_id = $node_detail['site_id'];
268 $in_site = in_array ($node_site_id,$_person['site_ids']);
270 $error= "Insufficient permission. You cannot create configuration files for this node.";
274 $hostname= $node_detail['hostname'];
275 $return= $api->GetInterfaces( array( "node_id" => $node_id ), NULL );
280 if( count($return) > 0 ) {
281 foreach( $return as $node_network_detail ) {
282 if( $node_network_detail['is_primary'] == true ) {
289 if( !$has_primary ) {
292 if( $node_detail['hostname'] == "" ) {
294 $node_detail['hostname']= "<i>Missing</i>";
297 $fields= array("method","ip");
298 foreach( $fields as $field ) {
299 if( $node_network_detail[$field] == "" ) {
301 $node_network_detail[$field]= "<i>Missing</i>";
305 if( $node_network_detail['method'] == "static" ) {
306 $fields= array("gateway","netmask","network","broadcast","dns1");
307 foreach( $fields as $field ) {
308 if( $node_network_detail[$field] == "" ) {
310 $node_network_detail[$field]= "<i>Missing</i>";
315 if( $node_network_detail['method'] != "static"
316 && $node_network_detail['method'] != "dhcp" ) {
318 $node_network_detail['method']= "<i>Unknown method</i>";
322 $download= $_POST['download'];
324 if( $can_gen_config && !empty($download) ) {
325 if (! method_exists ($api,"GetBootMedium")) {
326 $file_contents= $api->AdmGenerateNodeConfFile( $node_id );
327 header ("Content-Type: application/octet-stream");
328 header ("Content-Transfer-Encoding: binary");
329 header ("Content-Disposition: attachment; filename=plnode.txt" );
330 header ("Content-Length: " . strlen(file_contents));
331 header ("Pragma: hack");
332 header ("Cache-Control: public, must-revalidate");
337 case 'download-node-floppy':
338 $boot_action='node-floppy';
339 $location = "%d/%n-%v-rename-into-plnode%s";
341 case 'download-node-iso':
342 $boot_action='node-iso';
343 $location = "%d/%n-%a-%v%s";
345 case 'download-node-usb':
346 $boot_action='node-usb';
347 $location = "%d/%n-%a-%v%s";
351 $filename=$api->GetBootMedium($node_id,$boot_action,$location);
352 $error=$api->error();
353 if (empty($error) && empty($filename)) {
354 $error="Unexpected error from GetBootMedium - probably wrong directory modes";
356 if (! empty($error)) {
357 print ("<div class='plc-error'> $error </div>\n");
358 print ("<p><a href='/db/nodes/index.php?id=$node_id'>Back to node </a>\n");
361 deliver_and_unlink ($filename);
368 drupal_set_title("Download boot material for $hostname");
372 WARNING: Creating a new configuration file for this node will generate
373 a new node key, and any existing configuration file will be unusable and
374 must be updated before the node can successfully boot, install, or
377 <p>In order to create a configuration file for this node using this page,
378 all the node network settings must be up to date. Below is summary of these
379 values. Any missing values must be entered before this can be used.
385 show_download_confirm_button($api, $node_id, $action, $can_gen_config, false);
387 print ("<h3>Current node network settings</h3>\n");
390 print( "<table border=\"0\" cellspacing=\"4\">\n" );
392 print( "<tr><th colspan=2><a href='index.php?id=$node_id'>Node Details</a></th></tr>" );
393 print( "<tr><th>node_id:</th>" );
394 print( "<td>$node_id</td></tr>\n" );
395 print( "<tr><th>Hostname:</th>" );
396 print( "<td>" . $node_detail['hostname'] . "</td></tr>\n" );
398 $nn_id = $node_network_detail['interface_id'];
399 print( "<tr><th colspan=2><a href='node_networks.php?id=$nn_id'>Node Network Details</a></th></tr>" );
401 print( "<tr><th>Method:</th>" );
402 print( "<td>" . $node_network_detail['method'] . "</td></tr>\n" );
403 print( "<tr><th>IP:</th>" );
404 print( "<td>" . $node_network_detail['ip'] . "</td></tr>\n" );
406 if( $node_network_detail['method'] == "static" ) {
407 print( "<tr><th>Gateway:</th>" );
408 print( "<td>" . $node_network_detail['gateway'] . "</td></tr>\n" );
409 print( "<tr><th>Network mask:</th>" );
410 print( "<td>" . $node_network_detail['netmask'] . "</td></tr>\n" );
411 print( "<tr><th>Network address:</th>" );
412 print( "<td>" . $node_network_detail['network'] . "</td></tr>\n" );
413 print( "<tr><th>Broadcast address:</th>" );
414 print( "<td>" . $node_network_detail['broadcast'] . "</td></tr>\n" );
415 print( "<tr><th>DNS 1:</th>" );
416 print( "<td>" . $node_network_detail['dns1'] . "</td></tr>\n" );
417 print( "<tr><th>DNS 2:</th>" );
418 if( $node_network_detail['dns2'] == "" ) {
419 print( "<td><i>Optional, missing</i></td></tr>\n" );
421 print( "<td>" . $node_network_detail['dns2'] . "</td></tr>\n" );
425 if (method_exists ($api,'GetInterfaceSettings')) {
426 print ("<tr><th colspan=2><a href='node_networks.php?id=$nn_id'>Additional Settings</a></th></tr>\n");
427 $nn_id = $node_network_detail['interface_id'];
428 $settings=$api->GetInterfaceSettings(array("interface_id" => array($nn_id)));
429 foreach ($settings as $setting) {
430 $category=$setting['category'];
431 $name=$setting['name'];
432 $value=$setting['value'];
433 print (" <tr><th> $category $name </th><td> $value </td></tr>\n");
437 print( "</table>\n" );
439 print( "<p class='plc-warning'>This node has no configured primary network.</p>\n" );
442 show_download_confirm_button($api, $node_id, $action, $can_gen_config, true);
446 echo "Unkown action <$action>.";
447 header("location:index.php?id=" . $node_id);