newnodecheckin.php 10.8 KB
Newer Older
1
<?php
2
#
3
# Copyright (c) 2003-2016 University of Utah and the Flux Group.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# 
# {{{EMULAB-LICENSE
# 
# This file is part of the Emulab network testbed software.
# 
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
# 
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
# License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
# 
# }}}
23 24
#
require("defs.php3");
25
require("newnode-defs.php3");
26
include("xmlrpc.php3");
27 28 29 30 31

#
# Note - this script is not meant to be called by humans! It returns no useful
# information whatsoever, and expects the client to fill in all fields
# properly.
32
# Since this script does not cause any action to actually happen, so its save
33 34 35 36
# to leave 'in the open' - the worst someone can do is annoy the testbed admins
# with it!
#

37 38 39 40 41 42 43 44 45
$reqargs = RequiredPageArguments("cpuspeed",    PAGEARG_STRING,
				 "diskdev",     PAGEARG_STRING,
				 "disksize",    PAGEARG_STRING,
				 "role",        PAGEARG_STRING,
				 "messages",    PAGEARG_STRING);

$optargs = OptionalPageArguments("node_id",     PAGEARG_STRING,
				 "identifier",  PAGEARG_STRING,
				 "use_temp_IP", PAGEARG_STRING,
46 47
				 "type",        PAGEARG_STRING,
				 "cnetiface",	PAGEARG_STRING);
48

49 50 51 52 53 54
#
# Grab the IP address that this node has right now, so that we can contact it
# later if we need to, say, reboot it.
#
$tmpIP = getenv("REMOTE_ADDR");

55 56 57
#
# Find all interfaces
#
58
$interfaces = array();
Mike Hibler's avatar
Mike Hibler committed
59
foreach ($_GET as $key => $value) {
60
    if (preg_match("/iface(name|mac|driver)(\d+)/",$key,$matches)) {
61 62 63 64
        $vartype = $matches[1];
    	$ifacenum = $matches[2];
    	if ($vartype == "name") {
	    if (preg_match("/^([a-z]+)(\d+)$/i",$value,$matches)) {
65 66 67
		if (!isset($interfaces[$ifacenum]["type"])) {
		    $interfaces[$ifacenum]["type"] = $matches[1];
		}
68
	        $interfaces[$ifacenum]["card"] = $ifacenum;
69 70 71
		if (isset($cnetiface) && $cnetiface == $value) {
		    $cnetcard = $ifacenum;
		}
72
	    } else {
73 74
		echo "Bad interface name ". CleanString($value). ", ignored!";
	        $interfaces[$ifacenum]["bad"] = 1;
75 76
		continue;
	    }
77
	} else if ($vartype == "driver") {
78 79 80 81 82 83 84
	    if (preg_match("/^([a-z]+)$/i",$value,$matches)) {
		$interfaces[$ifacenum]["type"] = $matches[1];
	    } else {
		echo "Bad interface type ". CleanString($value). ", ignored!";
	        $interfaces[$ifacenum]["bad"] = 1;
		continue;
	    }
85
	} else {
86 87 88 89 90 91 92
	    if (preg_match("/^([0-9a-f]+)$/i",$value,$matches)) {
		$interfaces[$ifacenum]["mac"] = $matches[1];
	    } else {
		echo "Bad interface MAC ". CleanString($value). ", ignored!";
	        $interfaces[$ifacenum]["bad"] = 1;
		continue;
	    }
93 94 95
	}
    }
}
96 97 98
# weed out bad ones
foreach ($interfaces as $i => $interface) {
    if (isset($interface["bad"])) {
99 100 101
	if (isset($cnetcard) && $cnetcard == $interface["card"]) {
	    unset($cnetcard);
	}
102 103 104
	unset($interfaces[$i]);
    }
}
105

106 107 108 109
#
# Use one of the interfaces to see if this node seems to have already checked
# in once
#
110 111 112 113
if (count($interfaces)) {
    $testmac = $interfaces[0]["mac"];

    #
114 115
    # First, make sure it is not a 'real boy' - we should let the operators 
    # know about this, because there may be some problem.
116 117 118 119
    #
    $query_result = DBQueryFatal("select n.node_id from " .
	"nodes as n left join interfaces as i " .
	"on n.node_id=i.node_id " .
120
	"where i.mac='$testmac' or i.guid='$testmac'");
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    if  (mysql_num_rows($query_result)) {
        $row = mysql_fetch_array($query_result);
	$node_id = $row["node_id"];
        echo "Node is already a real node, named $node_id\n";
	TBMAIL($TBMAIL_OPS,"Node Checkin Error","A node attempted to check " .
	    "in as a new node, but it is already\n in the database as " .
	    "$node_id!");
	exit;
    }


    #
    # Next, try the new nodes
    #
    $query_result = DBQueryFatal("select n.new_node_id, n.node_id from " .
	"new_nodes as n left join new_interfaces as i " .
	"on n.new_node_id=i.new_node_id " .
138
	"where i.mac='$testmac' or i.guid='$testmac'");
139 140 141 142
    if  (mysql_num_rows($query_result)) {
        $row = mysql_fetch_array($query_result);
	$id = $row["new_node_id"];
	$node_id = $row["node_id"];
143 144
        echo "Node has already checked in\n";
	echo "Node ID is $id\n";
145 146

	#
147
	# Keep the temp. IP address around in case its gotten a new one
148 149 150 151 152 153 154
	#
	DBQueryFatal("update new_nodes set temporary_IP='$tmpIP' " .
	    "where new_node_id=$id");

	exit;
    }
}
155

156 157

#
158 159
# Attempt to come up with a node_id and an IP address for it - unless one was
# provided by the client.
160
#
161
if (!isset($node_id)) {
162 163 164 165 166 167 168 169
    $name_info = find_free_id("pc");
    $node_prefix = $name_info[0];
    $node_num = $name_info[1];
    $hostname = $node_prefix . $node_num;
} else {
    $hostname = $node_id;
}

170
if (isset($use_temp_IP)) {
171 172 173 174
    $IP = $tmpIP;
} else {
    $IP = guess_IP($node_prefix,$node_num);
}
175 176

#
177
# Handle the node type
178
#
Leigh Stoller's avatar
Leigh Stoller committed
179
if (isset($type) && $type != "") {
180
    #
181
    # If they gave us a type, lets see if that type exists or not
182
    #
183 184 185 186
    if (!preg_match("/^[-\w]*$/", $type)) {
	echo "Illegal characters in type: '$type'\n";
	exit;
    }
187 188 189 190 191 192 193 194 195 196 197 198 199 200
    if (TBValidNodeType($type)) {
	#
	# Great, it already exists, nothin' else to do
	#
    } else {
	#
	# Okay, it doesn't exist. We'll create it.
	#
	make_node_type($type,$cpuspeed,$disksize);
    }
} else {
    #
    # Make an educated guess as to what type it belongs to
    #
201 202 203 204 205 206
    $type = guess_node_type($cpuspeed,$disksize);
}

#
# Default the role to 'testnode' if the node didn't supply a role
#
207
$role = (isset($role) ? addslashes($role) : "testnode");
208 209 210 211

#
# Stash this information in the database
#
Leigh Stoller's avatar
Leigh Stoller committed
212
if (isset($identifier) && $identifier != "") {
213
    $identifier = "'" . addslashes($identifier) . "'";
214 215 216
} else {
    $identifier = "NULL";
}
217 218 219
$messages = (isset($messages) ? addslashes($messages) : "");
$hostname = (isset($hostname) ? addslashes($hostname) : "");

220
DBQueryFatal("insert into new_nodes set node_id='$hostname', type='$type', " .
221
	"IP='$IP', temporary_IP='$tmpIP', dmesg='$messages', created=now(), " .
222
	"identifier=$identifier, role='$role'");
223 224 225 226 227

$query_result = DBQueryFatal("select last_insert_id()");
$row = mysql_fetch_array($query_result);
$new_node_id = $row[0];

228 229
echo "Node ID is $new_node_id\n";

230
foreach ($interfaces as $interface) {
231 232 233 234
    $card = $interface["card"];
    $mac = $interface["mac"];
    $type = $interface["type"];
    $clause = "";
235 236 237 238
    # see if they specified the cnet interface and this is it
    if (isset($cnetcard) && $cnetcard == $card) {
	$clause .= ", role='ctrl'";
    }
239 240 241
    # XXX not a 6 byte value, assume it is a guid
    # XXX probably should check interface_capabilities for the type
    if (strlen($mac) != 12) {
242
	$clause .= ", guid='$mac'";
243 244 245 246 247 248 249 250 251
	# XXX 16 bytes implies an Infiniband port GUID to us
	# cons up what would be the mac
	if (strlen($mac) == 16) {
	    $mac = substr($mac, 0, 6) . substr($mac, 10, 6);
	}
    }
    DBQueryFatal("insert into new_interfaces set " .
	"new_node_id=$new_node_id, card=$card, mac='$mac', " .
	"interface_type='$type'$clause");
252 253 254 255 256 257 258
}

#
# Send mail to testbed-ops about the new node
#
TBMAIL($TBMAIL_OPS,"New Node","A new node, $hostname, has checked in");

259
function check_node_exists($node_id) {
260 261
    $node_id = addslashes($node_id);
    
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
    #
    # Just check to see if this node already exists in one of the
    # two tables - return 1 if it does, 0 if not
    #
    $query_result = DBQueryFatal("select node_id from nodes " .
	    "where node_id='$node_id'");
    if (mysql_num_rows($query_result)) {
	return 1;
    }
    $query_result = DBQueryFatal("select node_id from new_nodes " .
	    "where node_id='$node_id'");
    if (mysql_num_rows($query_result)) {
	return 1;
    }

    return 0;
}

280
function find_free_id($prefix) {
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
    global $ELABINELAB, $TBADMINGROUP, $interfaces;

    #
    # When inside an inner emulab, we have to ask the outer emulab for
    # our nodeid; we cannot just pick one out of a hat, at least not yet.
    #
    if ($ELABINELAB) {
	$arghash = array();
	$arghash["mac"] = $interfaces[0]["mac"];

	$results = XMLRPC("nobody", $TBADMINGROUP,
			  "elabinelab.newnode_info", $arghash);

	if (!$results || ! isset($results{'nodeid'})) {
	    echo "Could not get nodeid from XMLRPC server; quitting.\n";
	    exit;
	}
	elseif (preg_match("/^(.*[^\d])(\d+)$/",
			   $results{'nodeid'}, $matches)) {
	    $base   = $matches[1];
	    $number = $matches[2];
	    return array($base, intval($number));
	}
	else {
	    $nodeid = $results{'nodeid'};
	    
	    echo "Improper nodeid ($nodeid) from XMLRPC server; quitting.\n";
	    exit;
	}
    }
311 312

    #
313 314
    # First, check to see if there's a recent entry in new_nodes we can name
    # this node after
315
    #
316
    $ndigits = 0;
317 318 319 320 321 322 323 324
    $query_result = DBQueryFatal("select node_id from new_nodes " .
        "order by created desc limit 1");
    if (mysql_num_rows($query_result)) {
        $row = mysql_fetch_array($query_result);
	$old_node_id = $row[0];
	#
	# Try to figure out if this is in some format we can increment
	#
325 326 327 328 329 330 331 332 333 334 335 336 337
	if (preg_match("/^(.*[^\d])(0\d+)$/",$old_node_id,$matches)) {
	    $base = $matches[1];
	    $number = $matches[2];
	    $ndigits = strlen($number);
	    echo "Matches $ndigits-digit pcXXX format";
	    $fmt = "%0" . $ndigits . "d";
	    $number = sprintf($fmt, $number + 1);
	    $potential_name = $base . $number;
	    if (!check_node_exists($potential_name)) {
		return array($base, $number);
	    }
	    $prefix = $base;
	} elseif (preg_match("/^(.*[^\d])(\d+)$/",$old_node_id,$matches)) {
338 339 340 341 342 343 344 345
	    echo "Matches pcXXX format";
	    # pcXXX format
	    $base = $matches[1];
	    $number = $matches[2];
	    $potential_name = $base . ($number + 1);
	    if (!check_node_exists($potential_name)) {
		return array($base,($number +1));
	    }
346
	    $prefix = $base;
347 348 349 350 351 352 353 354 355
	} elseif (preg_match("/^(.*)-([a-zA-Z])$/",$old_node_id,$matches)) {
	    # Something like WAIL's (type-rack-A) format
	    $base = $matches[1];
	    $lastchar = $matches[2];
	    $newchar = chr(ord($lastchar) + 1);
	    $potential_name = $base . '-' . $newchar;
	    if (!check_node_exists($potential_name)) {
		return array($base . '-', $newchar);
	    }
356
	    $prefix = $base;
357 358
	}
    }
359 360

    #
361
    # Okay, that didn't work.
362 363 364 365
    # Just go through the nodes and new_nodes tables looking for one that
    # hasn't been used yet - put in a silly little guard to prevent an
    # infinite loop in case of bugs.
    #
366 367 368
    if ($ndigits) {
	$fmt = "%0" . $ndigits . "d";
    }
369 370
    $node_number = 0;
    while ($node_number < 10000) {
371 372 373 374 375
	$number = ++$node_number;
	if ($ndigits) {
	    $number = sprintf($fmt, $number);
	}
    	$potential_name = $prefix . $number;
376 377
	if (!check_node_exists($potential_name)) {
	    break;
378 379 380
	}
    }

381
    return array($prefix, $node_number);
382 383 384 385

}

?>