Commit 15d24b96 authored by Leigh Stoller's avatar Leigh Stoller

Bury dead code. Really dead.

parent cab96ec4
......@@ -82,27 +82,6 @@ tmcd: tmcd.c ${TMCDLIBS} tmcd.h version.o $(BOOTINFO) $(NOTPMLIB)
$(LDFLAGS) -L/usr/local/lib/mysql -lmysqlclient \
$(ELVINFLAGS) $(TMCDLDFLAGS) $(TMCDLIBS) $(TMLIBS)
mod_tmcd.so: libtmcd.o
apxs -c mod_tmcd.c -L/usr/local/lib/mysqlclient -lmysqlclient \
-L /usr/local/lib -lxml2 \
$(ELVINFLAGS) $(TMCDLDFLAGS) $(TMCDLIBS) $(NOTPMLIB) $(TMLIBS) $<
newtmcd: newtmcd.c libtmcd.o ${TMCDLIBS} tmcd.h version.o \
$(NOTPMLIB) $(BOOTINFO)
$(CC) $(TMCDCFLAGS) $(CFLAGS) $(SSLFLAGS) -o tmcd $< \
libtmcd.o version.o $(NOTPMLIB) $(BOOTINFO) \
$(LDFLAGS) -L/usr/local/lib/mysql -lmysqlclient -lxml2 \
$(ELVINFLAGS) $(TMCDLDFLAGS) $(TMCDLIBS) $(TMLIBS)
libtmcd.o: libtmcd.c ${TMCDLIBS} tmcd.h version.o $(BOOTINFO)
$(CC) $(TMCDCFLAGS) $(CFLAGS) $(SSLFLAGS) \
-I/usr/local/include/libxml2 -c -o libtmcd.o $<
libtmcd.so: libtmcd.o ${TMCDLIBS} tmcd.h $(BOOTINFO)
$(LD) -shared $^ -L/usr/local/lib/mysql -lxml2 -lmysqlclient \
$(TMCDLIBS) $(ELVINFLAGS) $(TESTBED_LIBOBJDIR)/libtb/libtb.a \
-o $@
version.c: tmcd.c
echo >$@ "char build_info[] = \"Built `date +%d-%b-%Y` by `id -nu`@`hostname | sed 's/\..*//'`:`pwd`\";"
......
This diff is collapsed.
/*
* Copyright (c) 2008-2009 University of Utah and the Flux Group.
*
* {{{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/>.
*
* }}}
*/
#ifndef _LIBTMCD_H_
#define _LIBTMCD_H_
#include <netinet/in.h>
#include <mysql/mysql.h>
#include <arpa/inet.h>
#include "tbdefs.h"
#ifdef EVENTSYS
#include "event.h"
#endif
#define DBNAME_SIZE 64
#define HOSTID_SIZE (32+64)
#define TMCD_STATUS_OK 0
#define TMCD_STATUS_UNKNOWN_COMMAND 1
#define TMCD_STATUS_INVALID_UDP_REQUEST 2
#define TMCD_STATUS_INVALID_REMOTE_UDP_REQUEST 3
#define TMCD_STATUS_REQUIRES_ENCRYPTION 4
#define TMCD_STATUS_NODE_NOT_ALLOCATED 5
#define TMCD_STATUS_MALLOC_FAILED 6
#define TMCD_STATUS_COMMAND_FAILED 7
/*
* This structure is passed to each request function. The intent is to
* reduce the number of DB queries per request to a minimum.
*/
typedef struct {
MYSQL db;
int db_connected;
char dbname[DBNAME_SIZE];
char prev_dbname[DBNAME_SIZE];
struct in_addr myipaddr;
#ifdef EVENTSYS
event_handle_t event_handle;
#endif
char fshostid[HOSTID_SIZE];
int verbose;
int debug;
int isssl;
int istcp;
int version;
struct in_addr client;
int allocated;
int jailflag;
int isvnode;
int issubnode;
int islocal;
int isdedicatedwa;
int iscontrol;
int isplabdslice;
int isplabsvc;
int elab_in_elab;
int singlenet; /* Modifier for elab_in_elab */
int update_accounts;
int exptidx;
int creator_idx;
int swapper_idx;
int swapper_isadmin;
int genisliver_idx;
char nodeid[TBDB_FLEN_NODEID];
char vnodeid[TBDB_FLEN_NODEID];
char pnodeid[TBDB_FLEN_NODEID]; /* XXX */
char pid[TBDB_FLEN_PID];
char eid[TBDB_FLEN_EID];
char gid[TBDB_FLEN_GID];
char nickname[TBDB_FLEN_VNAME];
char type[TBDB_FLEN_NODETYPE];
char class[TBDB_FLEN_NODECLASS];
char ptype[TBDB_FLEN_NODETYPE]; /* Of physnode */
char pclass[TBDB_FLEN_NODECLASS]; /* Of physnode */
char creator[TBDB_FLEN_UID];
char swapper[TBDB_FLEN_UID];
char syncserver[TBDB_FLEN_VNAME]; /* The vname */
char keyhash[TBDB_FLEN_PRIVKEY];
char eventkey[TBDB_FLEN_PRIVKEY];
char sfshostid[TBDB_FLEN_SFSHOSTID];
char testdb[TBDB_FLEN_TINYTEXT];
char tmcd_redirect[TBDB_FLEN_TINYTEXT];
char privkey[TBDB_FLEN_PRIVKEY+1];
} tmcdreq_t;
typedef struct {
char *data;
char *type;
int length;
} tmcdresp_t;
int iptonodeid(tmcdreq_t *reqp, struct in_addr ipaddr, char* nodekey);
int checkprivkey(tmcdreq_t *reqp, struct in_addr, char *);
int checkdbredirect(tmcdreq_t *);
void tmcd_free_response(tmcdresp_t *);
int tmcd_handle_request(tmcdreq_t *, tmcdresp_t **, char *, char *);
int tmcd_init(tmcdreq_t *reqp, struct in_addr *, char *);
#endif /* _LIBTMCD_H_ */
/*
* Copyright (c) 2008-2009 University of Utah and the Flux Group.
*
* {{{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/>.
*
* }}}
*/
#include <arpa/inet.h>
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_main.h"
#include "http_protocol.h"
#include "libtmcd.h"
module MODULE_VAR_EXPORT tmcd_module;
static char **make_argv(char *args, int *argc, char separator)
{
char **argv = NULL;
char *p, *token;
int count;
int i;
count = 1;
p = args;
while (*p) {
if (*p == separator) {
count++;
}
p++;
}
argv = malloc(sizeof(char *) * count);
if (argv == NULL)
goto err;
memset(argv, 0, sizeof(char *) * count);
p = args;
token = args;
i = 0;
while (*p) {
if (*p == separator) {
*p = '\0';
argv[i] = token;
token = p + 1;
i++;
}
p++;
}
argv[i] = token;
*argc = count;
err:
return argv;
}
static int handle_request(request_rec *r)
{
tmcdreq_t tmcdreq, *reqp = &tmcdreq;
tmcdresp_t *response = NULL;
char *command;
struct in_addr local_addr;
struct in_addr remote_addr;
struct sockaddr_in redir_client;
int tmcd_status;
int status = OK;
char *status_line = NULL;
char *args = NULL;
char *function_args = NULL;
char *p;
char **argv = NULL;
int argc, i;
reqp->istcp = 1;
reqp->isssl = 1; /* FIXME */
if (strcmp(r->handler, "tmcd")) {
status = DECLINED;
goto err;
}
#if 0
r->allowed |= (AP_METHOD_BIT << M_GET);
if (r->method_number != M_GET) {
status = DECLINED;
goto err;
}
#endif
memset(reqp, 0, sizeof(*reqp));
local_addr = r->connection->local_addr.sin_addr;
remote_addr = r->connection->remote_addr.sin_addr;
reqp->version = 1; /* FIXME need sane default */
tmcd_init(reqp, &local_addr, NULL);
command = r->path_info;
while (*command && *command == '/') {
command++;
}
if (command[0] == '\0') {
status = HTTP_BAD_REQUEST;
goto err;
}
if (r->args) {
args = malloc(strlen(r->args) + 1);
if (args == NULL) {
status = HTTP_INTERNAL_SERVER_ERROR;
goto err;
}
strcpy(args, r->args);
argv = make_argv(args, &argc, '&');
if (argv == NULL) {
status = HTTP_INTERNAL_SERVER_ERROR;
goto err;
}
for (i = 0; i < argc; i++) {
/* Unescape the arguments */
p = args;
while (*p) {
if (*p == '+')
*p = ' ';
p++;
}
status = ap_unescape_url(args);
if (status != OK) {
goto err;
}
if (strncasecmp(argv[i], "version=", 8) == 0) {
long version;
char *end;
version = strtol(argv[i] + 8, &end, 10);
if (*end != '\0' || *(argv[i] + 8) == '\0') {
status = HTTP_BAD_REQUEST;
status_line = "Invalid Version";
goto err;
}
reqp->version = version;
} else if (strncasecmp(argv[i], "redirect=", 9) == 0) {
if (inet_pton(AF_INET, argv[i] + 9,
&redir_client.sin_addr) <= 0) {
status = HTTP_BAD_REQUEST;
status_line = "Invalid IP Address";
goto err;
}
/* FIXME info message */
if (remote_addr.s_addr != local_addr.s_addr) {
status = HTTP_FORBIDDEN;
status_line = "Redirection Not Allowed";
goto err;
}
remote_addr =
redir_client.sin_addr;
} else if (strncasecmp(argv[i], "vnodeid=", 8) == 0) {
if (strlen(argv[i] + 8) >=
sizeof(reqp->vnodeid)) {
status = HTTP_BAD_REQUEST;
status_line =
"Virtual Node ID Too Long";
goto err;
}
reqp->isvnode = 1;
strcpy(reqp->vnodeid, argv[i] + 8);
} else if (strncasecmp(argv[i], "args=", 5) == 0) {
function_args = argv[i] + 5;
}
}
}
/* FIXME handle wanodekey */
if ((tmcd_status = iptonodeid(reqp, remote_addr, NULL))) {
if (reqp->isvnode) {
status_line = "Invalid Virtual Node";
}
else {
status_line = "Invalid Node";
}
status = HTTP_NOT_FOUND;
goto err;
}
if (reqp->tmcd_redirect[0]) {
/* FIXME what if https should be used? */
/* FIXME do I need to specify the args should be passed too? */
char *uri = ap_psprintf(r->pool, "http://%s%s?%s", reqp->tmcd_redirect,
r->uri, r->args);
ap_table_setn(r->headers_out, "Location", uri);
status = HTTP_MOVED_TEMPORARILY;
goto done;
}
tmcd_status = tmcd_handle_request(reqp, &response, command,
function_args);
if (tmcd_status == TMCD_STATUS_OK) {
r->content_type = response->type;
ap_set_content_length(r, response->length);
/* FIXME doctype */
ap_soft_timeout("tmcd response call trace", r);
ap_send_http_header(r);
ap_rprintf(r, "%s", response->data);
ap_kill_timeout(r);
status = OK;
goto done;
} else {
switch(tmcd_status) {
case TMCD_STATUS_UNKNOWN_COMMAND:
status = HTTP_NOT_FOUND;
status_line = "Unknown Command";
break;
case TMCD_STATUS_REQUIRES_ENCRYPTION:
status = HTTP_FORBIDDEN;
status_line = "SSL Required";
break;
case TMCD_STATUS_NODE_NOT_ALLOCATED:
status = HTTP_FORBIDDEN;
status_line = "Node Not Allocated";
break;
case TMCD_STATUS_COMMAND_FAILED:
status = HTTP_INTERNAL_SERVER_ERROR;
if (response && response->data) {
status_line = response->data;
}
break;
case TMCD_STATUS_MALLOC_FAILED:
status = HTTP_INTERNAL_SERVER_ERROR;
break;
}
goto err;
}
err:
done:
if (argv)
free(argv);
if (args)
free(args);
if (response)
tmcd_free_response(response);
if (status_line) {
r->status_line = ap_psprintf(r->pool, "%3.3u %s", status,
status_line);
}
return status;
}
static const handler_rec tmcd_handlers[] =
{
{"tmcd", handle_request},
{NULL}
};
module MODULE_VAR_EXPORT tmcd_module = {
STANDARD_MODULE_STUFF,
NULL, /* module initializer */
NULL, /* per-directory config creator */
NULL, /* dir config merger */
NULL, /* server config creator */
NULL, /* server config merger */
NULL, /* command table */
tmcd_handlers, /* [9] list of handlers */
NULL, /* [2] filename-to-URI translation */
NULL, /* [5] check/validate user_id */
NULL, /* [6] check user_id is valid *here* */
NULL, /* [4] check access by host address */
NULL, /* [7] MIME type checker/setter */
NULL, /* [8] fixups */
NULL, /* [10] logger */
#if MODULE_MAGIC_NUMBER >= 19970103
NULL, /* [3] header parser */
#endif
#if MODULE_MAGIC_NUMBER >= 19970719
NULL, /* process initializer */
#endif
#if MODULE_MAGIC_NUMBER >= 19970728
NULL, /* process exit/cleanup */
#endif
#if MODULE_MAGIC_NUMBER >= 19970902
NULL /* [1] post read_request handling */
#endif
};
This diff is collapsed.
#
# Copyright (c) 2000-2007 University of Utah and the Flux Group.
#
# {{{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/>.
#
# }}}
#
#
# XXX ONLY RUN THIS INSTALL ON A TESTBED NODE!
#
# These things need to be installed into the right place on a testbed
# node before cutting an image. This directory is installed first,
# followed by the system-specific directory.
#
#
SRCDIR = @srcdir@
TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ../..
SUBDIR = tmcd/common
include $(OBJDIR)/Makeconf
all:
include $(TESTBED_SRCDIR)/GNUmakerules
DESTDIR =
ETCDIR = $(DESTDIR)$(CLIENT_ETCDIR)
BINDIR = $(DESTDIR)$(CLIENT_BINDIR)
VARDIR = $(DESTDIR)$(CLIENT_VARDIR)
RCDIR = $(BINDIR)/rc
SYSRCDIR = $(DESTDIR)/usr/local/etc/rc.d
TBBINDIR = $(DESTDIR)/usr/testbed/bin
TBLIBDIR = $(DESTDIR)/usr/testbed/lib
INSTALL = /usr/bin/install -c
install client-install:
@echo "You should probably not run this install directly!"
@echo "If you do, be sure to install from the system specific "
@echo "directory afterwards."
local-install: path-install local-script-install symlinks
remote-install: path-install remote-script-install
control-install: path-install control-script-install
other-install:
(cd ../../os; $(MAKE) DESTDIR=$(DESTDIR) client-install)
(cd ../../event; $(MAKE) DESTDIR=$(DESTDIR) client-install)
(cd ../../sensors/slothd; $(MAKE) DESTDIR=$(DESTDIR) client-install)
(cd ../../tools; $(MAKE) DESTDIR=$(DESTDIR) client-install)
dir-install:
$(INSTALL) -m 755 -o root -d $(ETCDIR)
$(INSTALL) -m 755 -o root -d $(BINDIR)
$(INSTALL) -m 755 -o root -d $(RCDIR)
$(INSTALL) -m 755 -o root -d $(VARDIR)
$(INSTALL) -m 755 -o root -d $(VARDIR)/db
$(INSTALL) -m 755 -o root -d $(VARDIR)/jails
$(INSTALL) -m 755 -o root -d $(VARDIR)/logs
$(INSTALL) -m 755 -o root -d $(VARDIR)/boot
$(INSTALL) -m 755 -o root -d $(VARDIR)/lock
$(INSTALL) -m 755 -o root -d $(TBBINDIR)
path-install: dir-install
$(INSTALL) -m 755 $(SRCDIR)/paths.pm $(ETCDIR)/paths.pm
$(INSTALL) -m 755 $(SRCDIR)/paths.sh $(ETCDIR)/paths.sh
common-script-install: dir-install
$(INSTALL) -m 755 $(SRCDIR)/libsetup.pm $(BINDIR)/libsetup.pm
$(INSTALL) -m 755 $(SRCDIR)/libtmcc.pm $(BINDIR)/libtmcc.pm
$(INSTALL) -m 755 $(SRCDIR)/libtestbed.pm $(BINDIR)/libtestbed.pm
$(INSTALL) -m 755 $(SRCDIR)/tmcc.pl $(BINDIR)/tmcc
$(INSTALL) -m 755 $(SRCDIR)/logboot $(BINDIR)/logboot
$(INSTALL) -m 755 $(SRCDIR)/watchdog $(BINDIR)/watchdog
$(INSTALL) -m 755 $(SRCDIR)/ntpstart $(BINDIR)/ntpstart
$(INSTALL) -m 755 $(SRCDIR)/runstartup $(BINDIR)/runstartup
$(INSTALL) -m 755 $(SRCDIR)/runcvsup.sh $(BINDIR)/runcvsup.sh
$(INSTALL) -m 755 $(SRCDIR)/update $(BINDIR)/update
$(INSTALL) -m 755 $(SRCDIR)/ifsetup $(BINDIR)/ifsetup
$(INSTALL) -m 755 $(SRCDIR)/ifdynconfig $(BINDIR)/ifdynconfig
$(INSTALL) -m 755 $(SRCDIR)/vnodesetup $(BINDIR)/vnodesetup
$(INSTALL) -m 755 $(SRCDIR)/bootsubnodes $(BINDIR)/bootsubnodes
$(INSTALL) -m 755 $(SRCDIR)/bootvnodes $(BINDIR)/bootvnodes
$(INSTALL) -m 755 $(SRCDIR)/startcmddone $(BINDIR)/startcmddone
(cd config; $(MAKE) DESTDIR=$(DESTDIR) script-install)
symlinks: dir-install
rm -f $(TBBINDIR)/tevc$(EXE)
ln -s $(CLIENT_BINDIR)/tevc$(EXE) $(TBBINDIR)/tevc$(EXE)
rm -f $(TBBINDIR)/emulab-sync$(EXE)
ln -s $(CLIENT_BINDIR)/emulab-sync$(EXE) $(TBBINDIR)/emulab-sync$(EXE)
rm -f $(TBLIBDIR)
ln -s $(CLIENT_BINDIR) $(TBLIBDIR)
local-script-install: common-script-install
$(INSTALL) -m 755 $(SRCDIR)/sendevent $(BINDIR)/sendevent
$(INSTALL) -m 755 $(SRCDIR)/rc.testbed $(RCDIR)/rc.testbed
$(INSTALL) -m 755 $(SRCDIR)/rc.bootsetup $(RCDIR)/rc.bootsetup
$(INSTALL) -m 755 $(SRCDIR)/rc.slothd $(RCDIR)/rc.slothd
$(INSTALL) -m 755 $(SRCDIR)/rc.canaryd $(RCDIR)/rc.canaryd
$(INSTALL) -m 755 $(SRCDIR)/rc.linktest $(RCDIR)/rc.linktest
$(INSTALL) -m 755 $(SRCDIR)/rc.inelab $(RCDIR)/rc.inelab
# Symlink this cause we invoke it from boss, and its too much
# of a hassle to worry about right now.
rm -f $(ETCDIR)/update
-ln -s $(CLIENT_BINDIR)/update $(ETCDIR)/update
remote-script-install: common-script-install
-chown root $(BINDIR)/vnodesetup
-chmod u+s $(BINDIR)/vnodesetup
control-script-install: dir-install bossnode
$(INSTALL) -m 755 $(SRCDIR)/libsetup.pm $(BINDIR)/libsetup.pm
$(INSTALL) -m 755 $(SRCDIR)/libtmcc.pm $(BINDIR)/libtmcc.pm
$(INSTALL) -m 755 $(SRCDIR)/tmcc.pl $(BINDIR)/tmcc
$(INSTALL) -m 755 $(SRCDIR)/ctrlnode.sh $(SYSRCDIR)/ctrlnode.sh
$(INSTALL) -m 755 $(SRCDIR)/rc.ctrlnode $(RCDIR)/rc.ctrlnode
$(INSTALL) -m 755 $(SRCDIR)/config/librc.pm $(BINDIR)/librc.pm
$(INSTALL) bossnode $(ETCDIR)/bossnode
bossnode: GNUmakefile
echo >$@ "$(BOSSNODE)"
#!/usr/bin/perl -wT
#
# Copyright (c) 2000-2003, 2005 University of Utah and the Flux Group.
#
# {{{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/>.
#
# }}}
#
use Getopt::Std;
use English;
use Errno;
use POSIX qw(strftime);
#
# Startup subnodes, if there are any!
#
# NB: This script should not be run in foreground mode on a remote node
# when booting; if boss is down the boot will hang. On local nodes, its
# okay to hang.
#
sub usage()
{
print "Usage: bootsubnodes [-d] [-f]\n";
exit(1);
}
my $optlist = "df";
#
# Turn off line buffering on output
#
$| = 1;
# Drag in path stuff so we can find emulab stuff.
BEGIN { require "/etc/emulab/paths.pm"; import emulabpaths; }
#
# Load the OS independent support library. It will load the OS dependent
# library and initialize itself.
#
use libsetup;
use libtmcc;
# Locals
my $logname = "$LOGDIR/bootsubnodes.debug";
my $debug = 0;
my $daemon = 1;
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"f"})) {
$daemon = 0;
}
if (@ARGV) {
usage();
}
#
# Must be root.
#
if ($UID != 0) {
die("*** $0:\n".
" Must be root to run this script!\n");
}
#
# Put this into the background and log its output. We *must* do this cause
# we do not want to halt the boot if the testbed is down!
#
if ($daemon && TBBackGround($logname)) {
#
# Parent exits normally
#
exit(0);
}
my %subnodelist;
#
# Get the current set of subnodes that are supposed to be running on
# this node.
#
my %tmccresults;
if (tmcc(TMCCCMD_SUBNODELIST, undef, \%tmccresults) < 0) {
die("*** WARNING: Could not get subnode list from server!\n");
}
if (!$tmccresults{'subnode'}) {
print "No subnodes. Exiting gracefully ...\n";
exit(0);
}
foreach my $node (@{$tmccresults{'subnode'}}) {
my $nodeid = $$node{'nodeid'};
my $type = $$node{'type'};
if ($node =~ /^([-\w]+)$/ && $type =~ /^([-\w]+)$/) {
$subnodelist{$nodeid} = $type;
}
else {
warn("*** WARNING: Skipping bad subnodeid: 'NODEID=$nodeid TYPE=$type'\n");
}
}
print "subnodelist is @{[keys(%subnodelist)]}\n";
# Pause to give hardware settle time.
sleep(2);
foreach my $subnode (keys(%subnodelist)) {
my $type = $subnodelist{$subnode};
print "Setting up subnode $subnode ($type) ...\n";
# These should not return until the subnode is fully running.
SWITCH: for ($type) {
/^IXP$/i && do {
system("ixpboot $subnode");
if ($?) {