Commit 5c961517 authored by Mac Newbold's avatar Mac Newbold

Merge the newstated branch with the main tree.

Changes to watch out for:

- db calls that change boot info in nodes table are now calls to os_select

- whenever you want to change a node's pxe boot info, or def or next boot
osids or paths, use os_select.

- when you need to wait for a node to reach some point in the boot process
(like ISUP), check the state in the database using the lib calls

- Proxydhcp now sends a BOOTING state for each node that it talks to.

- OSs that don't send ISUP will have one generated for them by stated
either when they ping (if they support ping) or immediately after they get
to BOOTING.

- States now have timeouts. Actions aren't currently carried out, but they
will be soon. If you notice problems here, let me know... we're still
tuning it. (Before all timeouts were set to "none" in the db)

One temporary change:

- While I make our new free node manager daemon (freed), all nodes are
forced into reloading when they're nfreed and the calls to reset the os
are disabled (that will move into freed).
parent 3332148a
......@@ -9,8 +9,19 @@ DISTCLEAN_FILES = @DISTCLEAN_FILES@
include Makeconf
SUBDIRS = lib assign discvr tbsetup db os security pxe tmcd utils www \
tip capture ipod vis sensors @optional_subdirs@
#
# Ordering here matters!
# Things with no dependencies go first:
# assign db lib
# Things that may have dependencies go next:
# @optional_subdirs@ (has event)
# discvr ipod os security sensors
# Then things that only depend on stuff we've done:
# pxe tbsetup tmcd utils www tip capture vis
# Then things that depend on stuff we just did:
#
SUBDIRS = lib db assign @optional_subdirs@ discvr ipod os security sensors \
pxe tbsetup tmcd utils www tip capture ipod vis sensors
all: all-subdirs
......
......@@ -1256,7 +1256,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
sensors/slothd/sdisrunning sensors/slothd/sddeploy \
tbsetup/GNUmakefile tbsetup/console_setup tbsetup/spewlogfile \
tbsetup/console_reset tbsetup/bwconfig tbsetup/power_rpc27.pm \
tbsetup/os_load tbsetup/os_setup tbsetup/power \
tbsetup/os_load tbsetup/os_setup tbsetup/os_select tbsetup/power \
tbsetup/node_reboot tbsetup/webnscheck tbsetup/nscheck \
tbsetup/resetvlans tbsetup/rmacct-ctrl tbsetup/rmproj \
tbsetup/sched_reload tbsetup/sched_reserve tbsetup/reload_daemon \
......
......@@ -313,7 +313,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
sensors/slothd/sdisrunning sensors/slothd/sddeploy \
tbsetup/GNUmakefile tbsetup/console_setup tbsetup/spewlogfile \
tbsetup/console_reset tbsetup/bwconfig tbsetup/power_rpc27.pm \
tbsetup/os_load tbsetup/os_setup tbsetup/power \
tbsetup/os_load tbsetup/os_setup tbsetup/os_select tbsetup/power \
tbsetup/node_reboot tbsetup/webnscheck tbsetup/nscheck \
tbsetup/resetvlans tbsetup/rmacct-ctrl tbsetup/rmproj \
tbsetup/sched_reload tbsetup/sched_reserve tbsetup/reload_daemon \
......
......@@ -73,18 +73,24 @@ use Exporter;
TB_ASSIGN_TOOFEWNODES TB_OPSPID
TBDB_TBEVENT_NODESTATE TBDB_TBEVENT_NODEOPMODE
TBDB_TBEVENT_ISUP TBDB_TBEVENT_REBOOTING TBDB_TBEVENT_REBOOTED
TBDB_TBEVENT_NORMAL TBDB_TBEVENT_DELAYING TBDB_TBEVENT_UNKNOWNOS
TBDB_TBEVENT_RELOADING
TBDB_TBEVENT_NODESTATE TBDB_TBEVENT_NODEOPMODE TBDB_TBEVENT_CONTROL
TBDB_NODESTATE_ISUP TBDB_NODESTATE_REBOOTING TBDB_NODESTATE_REBOOTED
TBDB_NODESTATE_UNKNOWN
TBDB_NODESTATE_SHUTDOWN TBDB_NODESTATE_BOOTING TBDB_NODESTATE_TBSETUP
TBDB_NODESTATE_RELOADSETUP TBDB_NODESTATE_RELOADING
TBDB_NODESTATE_RELOADDONE TBDB_NODESTATE_UNKNOWN
TBDB_NODEOPMODE_NORMAL TBDB_NODEOPMODE_DELAYING
TBDB_NODEOPMODE_UNKNOWNOS TBDB_NODEOPMODE_RELOADING
TBDB_NODEOPMODE_NORMALv1 TBDB_NODEOPMODE_MINIMAL
TBDB_NODEOPMODE_RELOAD TBDB_NODEOPMODE_DELAY
TBDB_NODEOPMODE_BOOTWHAT
TBDB_NODEOPMODE_UNKNOWN
TBDB_EXPT_WORKDIR
TBSetNodeEventState TBGetNodeEventState
TBSetNodeOpMode TBGetNodeOpMode
TB_OSID_MBKERNEL TB_OSID_PXEBOOT TB_OSID_FRISBEE
TBBootWhat TBNodeStateTimeout
TBDB_TBCONTROL_RESET TBDB_TBCONTROL_RELOADDONE
TBDB_TBCONTROL_TIMEOUT TBDB_NO_STATE_TIMEOUT
TBAdmin TBProjAccessCheck TBNodeAccessCheck TBOSIDAccessCheck
TBImageIDAccessCheck TBExptAccessCheck ExpLeader MarkNodeDown
......@@ -285,6 +291,11 @@ sub TB_OSID_DESTROY() { 3; }
sub TB_OSID_MIN() { TB_OSID_READINFO; }
sub TB_OSID_MAX() { TB_OSID_DESTROY; }
# Magic OSID constants
sub TB_OSID_MBKERNEL() { "_KERNEL_"; } # multiboot kernel OSID
sub TB_OSID_PXEBOOT() { "PXEBOOT"; } # osid for def pxe_boot_path
sub TB_OSID_FRISBEE() { "PXEFRISBEE"; }
# ImageIDs
#
# Clarification:
......@@ -324,36 +335,40 @@ sub TB_OPSPID() { $TBOPSPID; }
#
sub TBDB_TBEVENT_NODESTATE { "TBNODESTATE"; }
sub TBDB_TBEVENT_NODEOPMODE { "TBNODEOPMODE"; }
#
# TBNODESTATE Events
#
sub TBDB_TBEVENT_ISUP() { "ISUP"; }
sub TBDB_TBEVENT_REBOOTED() { "REBOOTED"; }
sub TBDB_TBEVENT_REBOOTING() { "REBOOTING"; }
#
# TBNODEOPMODE Events
#
sub TBDB_TBEVENT_NORMAL() { "NORMAL"; }
sub TBDB_TBEVENT_DELAYING() { "DELAYING"; }
sub TBDB_TBEVENT_UNKNOWNOS() { "UNKNOWNOS"; }
sub TBDB_TBEVENT_RELOADING() { "RELOADING"; }
sub TBDB_TBEVENT_CONTROL { "TBCONTROL"; }
#
# For nodes, we use this set of events.
#
sub TBDB_NODESTATE_ISUP() { TBDB_TBEVENT_ISUP; }
sub TBDB_NODESTATE_REBOOTED() { TBDB_TBEVENT_REBOOTED; }
sub TBDB_NODESTATE_REBOOTING() { TBDB_TBEVENT_REBOOTING; }
sub TBDB_NODESTATE_ISUP() { "ISUP"; }
sub TBDB_NODESTATE_REBOOTED() { "REBOOTED"; }
sub TBDB_NODESTATE_REBOOTING() { "REBOOTING"; }
sub TBDB_NODESTATE_SHUTDOWN() { "SHUTDOWN"; }
sub TBDB_NODESTATE_BOOTING() { "BOOTING"; }
sub TBDB_NODESTATE_TBSETUP() { "TBSETUP"; }
sub TBDB_NODESTATE_RELOADSETUP() { "RELOADSETUP"; }
sub TBDB_NODESTATE_RELOADING() { "RELOADING"; }
sub TBDB_NODESTATE_RELOADDONE() { "RELOADDONE"; }
sub TBDB_NODESTATE_UNKNOWN() { "UNKNOWN"; };
sub TBDB_NODEOPMODE_NORMAL { TBDB_TBEVENT_NORMAL; }
sub TBDB_NODEOPMODE_DELAYING { TBDB_TBEVENT_DELAYING; }
sub TBDB_NODEOPMODE_UNKNOWNOS { TBDB_TBEVENT_UNKNOWNOS; }
sub TBDB_NODEOPMODE_RELOADING { TBDB_TBEVENT_RELOADING; }
sub TBDB_NODEOPMODE_NORMAL { "NORMAL"; }
sub TBDB_NODEOPMODE_DELAYING { "DELAYING"; }
sub TBDB_NODEOPMODE_UNKNOWNOS { "UNKNOWNOS"; }
sub TBDB_NODEOPMODE_RELOADING { "RELOADING"; }
sub TBDB_NODEOPMODE_NORMALv1 { "NORMALv1"; }
sub TBDB_NODEOPMODE_MINIMAL { "MINIMAL"; }
sub TBDB_NODEOPMODE_RELOAD { "RELOAD"; }
sub TBDB_NODEOPMODE_DELAY { "DELAY"; }
sub TBDB_NODEOPMODE_BOOTWHAT { "_BOOTWHAT_"; } # A redirection opmode
sub TBDB_NODEOPMODE_UNKNOWN { "UNKNOWN"; }
sub TBDB_TBCONTROL_RESET { "RESET"; }
sub TBDB_TBCONTROL_RELOADDONE { "RELOADDONE"; }
sub TBDB_TBCONTROL_TIMEOUT { "TIMEOUT"; }
# Constant we use for the timeout field when there is no timeout for a state
sub TBDB_NO_STATE_TIMEOUT { 0; }
#
# Node name we use in the widearea_* tables to represent a generic local node.
# All local nodes are considered to have the same network characteristcs.
......@@ -1162,6 +1177,100 @@ sub OSFeatureSupported($$) {
return 0;
}
#
# Find out what osid a node will boot next time it comes up,
# Usually (but not always) the currently running OS as well.
# May also return TB_OSID_MBKERNEL
#
sub TBBootWhat($;$) {
# WARNING!!!
#
# DO NOT change this function without making corresponding changes to
# the C version of this code in the bootinfo_mysql.c . They MUST
# ALWAYS find exactly the same resulting OSID given the same inputs.
# [The only exception is that here we must take into account
# *pxe_boot_path since that can specify an OS as well.]
#
# Boot priorities go like this:
# NEXT_PXE_BOOT_PATH
# PXE_BOOT_PATH
# NEXT_BOOT_PATH multiboot kernel
# DEF_BOOT_PATH multiboot kernel
# NEXT_BOOT_OSID osid from os_info
# DEF_BOOT_OSID osid from os_info
# if all the above are null, error
my $node = shift || return 0; # error if no node
my $d = shift || 0; # debug flag
my $cmd = "select path from os_info where osid='".TB_OSID_PXEBOOT."'";
my $q = DBQueryFatal($cmd);
my @r = $q->fetchrow_array();
my $defpxepath = $r[0];
$cmd = "select next_pxe_boot_path, pxe_boot_path,
next_boot_path, def_boot_path, next_boot_osid, def_boot_osid
from nodes where node_id = '$node'";
$q = DBQueryFatal($cmd);
if ($q->numrows() < 1) {
warn("TBBootWhat: Ignoring invalid node '$node' (non-existent)\n");
return 0;
}
@r = $q->fetchrow_array();
$nextpxepath=$r[0];
$pxepath=$r[1];
$nextpath=$r[2];
$defpath=$r[3];
$nextosid=$r[4];
$defosid=$r[5];
print "TBBootWhat: $node => (".($nextpxepath?"nextpxe=$nextpxepath, ":"").
( $pxepath ne $defpxepath ? "pxe=$pxepath, ":"") .
"np=$nextpath, dp=$defpath, no=$nextosid, do=$defosid)\n" if $d>1;
# With PXE paths, look up the osid for the path. If none, use
# TB_OSID_MBKERNEL. If it is the default pxe path, just go on like normal.
if (defined($nextpxepath) && $nextpxepath) {
if ($nextpxepath ne $defpxepath) {
print "TBBootWhat: Using next_pxe_boot_path $nextpxepath\n" if $d;
my $cmd = "select osid from os_info where path='$nextpxepath'";
my $q = DBQueryFatal($cmd);
if ($q->numrows() > 0) {
my @r = $q->fetchrow_array();
my $osid = $r[0];
return $osid;
} else {
return TB_OSID_MBKERNEL;
}
} # else go on as normal
} else {
if ($pxepath ne $defpxepath) {
print "TBBootWhat: Using pxe_boot_path $pxepath\n" if $d;
my $cmd = "select osid from os_info where path='$pxepath'";
my $q = DBQueryFatal($cmd);
if ($q->numrows() > 0) {
my @r = $q->fetchrow_array();
my $osid = $r[0];
return $osid;
} else {
return TB_OSID_MBKERNEL;
}
} # else go on as normal
}
if ((defined($nextpath) && $nextpath) ||
(defined($defpath) && $defpath)) {
# No OSID. Return a magic one.
print "TBBootWhat: Using {def,next}_boot_path ${nextpath}$defpath\n"
if $d;
return TB_OSID_MBKERNEL;
}
if (defined($nextosid) && $nextosid) {
print "TBBootWhat: Using next_boot_osid $nextosid\n" if $d;
return $nextosid;
}
if (defined($defosid) && $defosid) {
print "TBBootWhat: Using def_boot_osid $defosid\n" if $d;
return $defosid;
}
warn("***Warning: node '$node': All boot info was null!\n");
return TB_OSID_MBKERNEL;
}
#
# Ah, what a hack! I'm tired of seeing regexs for sharks scattered around
# the code. Anyway, this checks to see if a node is a shelf, and fills
......@@ -1555,6 +1664,50 @@ sub TBGetNodeEventState($$)
return 1;
}
#
# Check if a node has timed out in its current state. If it has, it gets
# stated involved to handle the situation.
#
# usage: TBNodeStateTimeout(char *node)
# Returns 1 if it has timed out and stated was notified
# Returns 0 if it is okay (still within time limits)
#
sub TBNodeStateTimeout($)
{
my ($node) = @_;
my $notimeout = TBDB_NO_STATE_TIMEOUT;
my $query_result =
DBQueryFatal("select now() - state_timestamp > timeout as over, ".
"timeout='$notimeout' as none ".
"from nodes as n left join state_timeouts as st ".
"on n.eventstate=st.state and n.op_mode=st.op_mode ".
"where node_id='$node'");
if ($query_result->numrows == 0) {
warn("*** TBNodeStateTimeout: Couldn't check node '$node'\n");
return 0;
}
my ($over,$none) = $query_result->fetchrow_array();
if ($over && !$none) {
# We're overtime... send an event and return 1
if ($EVENTSYS) {
EventSendFatal(objtype => TBDB_TBEVENT_CONTROL,
objname => $node,
eventtype => TBDB_TBCONTROL_TIMEOUT,
host => $BOSSNODE);
} else {
# Don't know what to do... how are state timeouts handled
# if we don't have stated?
}
return 1;
} else {
# We're good... return 0
return 0;
}
}
#
# Set operational mode for a node.
#
......@@ -1562,6 +1715,8 @@ sub TBGetNodeEventState($$)
# Returns 1 if okay.
# Returns 0 if failed.
#
# DEPRECATED - stated handles these transitions now
#
sub TBSetNodeOpMode($$)
{
my ($node, $mode) = @_;
......@@ -1594,7 +1749,7 @@ sub TBGetNodeOpMode($$)
my ($node, $mode) = @_;
my $query_result =
DBQueryFatal("select eventstate from nodes where node_id='$node'");
DBQueryFatal("select op_mode from nodes where node_id='$node'");
if ($query_result->numrows == 0) {
return 0;
......
......@@ -34,6 +34,7 @@ use libdb;
use libtestbed;
my $consetup = "$TB/libexec/console_setup";
my $osselect = "$TB/bin/os_select";
my $reloadpid = "emulab-ops";
my $pendingeid = "reloadpending";
my $reloadeid = "reloading";
......@@ -211,13 +212,17 @@ foreach my $n (@freed_nodes) {
#
my $result =
DBQueryFatal("select control_net,nt.osid,nt.pxe_boot_path, " .
" n.def_boot_osid,n.def_boot_path, ".
" nt.isvirtnode ".
" from node_types as nt " .
"n.def_boot_osid,n.def_boot_path, ".
"nt.isvirtnode, o.osid ".
"from node_types as nt " .
"left join nodes as n on n.type=nt.type " .
"left join os_info as o on o.path=nt.pxe_boot_path " .
"where node_id='$n'");
my ($control,$osid,$pxe_boot_path,$def_boot_osid,$def_boot_path,$isvirt) =
$result->fetchrow_array();
my ($control, $osid, $pxe_boot_path, $def_boot_osid, $def_boot_path,
$isvirt, $pxe_osid) = $result->fetchrow_array();
if (!defined($pxe_osid) || $pxe_osid eq "") {
$pxe_osid = "-p $pxe_boot_path";
}
#
# See if the OS it was running was marked as mustclean or not. Basically,
......@@ -271,6 +276,13 @@ foreach my $n (@freed_nodes) {
}
}
#
# Reset the OS to the default osid for the node type
#
# XXX disabled while forced reload hack is in place
#system("$osselect -m $pxe_osid $n");
#system("$osselect $osid $n");
#
# Clean up the nodes table so that its in a moderately clean state.
#
......@@ -284,11 +296,9 @@ foreach my $n (@freed_nodes) {
#}
#print "\n";
#}
DBQueryWarn("update nodes set def_boot_osid='$osid',def_boot_cmd_line='',".
"def_boot_path='',startupcmd='',rpms='',deltas='', ".
"tarballs='',pxe_boot_path='$pxe_boot_path', ".
"failureaction='fatal', routertype='none', ".
"next_pxe_boot_path='' where node_id='$n'") || $error++;
DBQueryWarn("update nodes set startupcmd='',rpms='',deltas='', ".
"tarballs='',failureaction='fatal', routertype='none' ".
"where node_id='$n'") || $error++;
#
# Clean out the current_reloads table (a just in case measure).
......@@ -340,7 +350,8 @@ foreach my $n (@freed_nodes) {
DBQueryFatal("select node_id,image_id from scheduled_reloads " .
"where node_id='$n'");
if ($result->numrows()) {
# XXX force reload hack!
if (1 || $result->numrows()) {
print "Moving $n to $reloadpid/$pendingeid.\n";
DBQueryWarn("update reserved set ".
......
This diff is collapsed.
......@@ -8,6 +8,7 @@ SRCDIR = @srcdir@
TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ..
SUBDIR = pxe
EVENTSYS = @EVENTSYS@
include $(OBJDIR)/Makeconf
......@@ -37,7 +38,14 @@ INCS = -I/usr/local/include
CFLAGS += $(INCS) $(DBFLAG) -DSOLARIS -DHAVE_SOCKADDR_SA_LEN -DUSE_RECVMSG \
-DCONFPATH='"$(INSTALL_ETCDIR)/"' -DTBDBNAME='"$(TBDBNAME)"' \
-DFALLBACK_HOST='"$(BOSSNODE)"'
-DFALLBACK_HOST='"$(BOSSNODE)"' -DBOSSNODE='"$(BOSSNODE)"'
ifeq ($(EVENTSYS),1)
CFLAGS += -DEVENTSYS -I$(TESTBED_SRCDIR)/event/lib \
`elvin-config --cflags vin4c`
LFLAGS += $(OBJDIR)/event/lib/libevent.a ${OBJDIR}/lib/libtb/libtb.a \
`elvin-config --libs vin4c`
endif
proxydhcp: proxydhcp.o $(PR_DBOBJ)
cc $(CFLAGS) $(DBFLAG) $(INCS) \
......
......@@ -25,6 +25,14 @@ open_bootinfo_db(void)
return 0;
}
/*
WARNING!!!
DO NOT change this function without making corresponding changes to
the perl version of this code in db/libdb.pm . They MUST ALWAYS
return exactly the same result given the same inputs.
*/
int
query_bootinfo_db(struct in_addr ipaddr, boot_what_t *info)
{
......
......@@ -26,6 +26,10 @@
#include <sys/uio.h>
#include <sys/param.h>
#endif
#ifdef EVENTSYS
/*#include "tbdefs.h" Do we need this?*/
#include "event.h"
#endif
#define BOOTPS_PORT 67
#define BOOTPC_PORT 68
......@@ -76,6 +80,17 @@ int close_db(void);
int binlmode = 0;
/*
* Event System interface
*/
#ifdef EVENTSYS
int myevent_send(address_tuple_t address);
static event_handle_t event_handle = NULL;
address_tuple_t tuple;
int ip2nodeid(struct in_addr, char *, int);
char nodeid[16];
#endif
/*
* Fall back to default
*/
......@@ -297,6 +312,36 @@ main(int argc, char *argv[])
continue;
}
#ifdef EVENTSYS
/*
* By this point, we know it is a DHCP packet that we
* need to respond to, so the node must be booting.
* So we send out a change to state BOOTING.
*/
/* XXX: Maybe we don't need to alloc a new tuple every time */
tuple = address_tuple_alloc();
if (tuple != NULL &&
!ip2nodeid(client.sin_addr, nodeid, sizeof(nodeid))) {
tuple->host = BOSSNODE;
tuple->objtype = "TBNODESTATE";
tuple->objname = nodeid;
tuple->eventtype = "BOOTING";
if (myevent_send(tuple)) {
fprintf(stderr, "Couldn't send state "
"event for %s\n",nodeid);
}
printf("Successfully sent state event for %s\n",
nodeid);
address_tuple_free(tuple);
} else {
fprintf(stderr, "Couldn't lookup nodeid for %s\n",
inet_ntoa((*((struct in_addr*)data))));
}
#endif /* EVENTSYS */
if (query_db(client.sin_addr,
&sip, bootprog, sizeof(bootprog))) {
#ifdef FALLBACK_HOST
......@@ -376,3 +421,62 @@ main(int argc, char *argv[])
}
}
}
#ifdef EVENTSYS
/*
* Connect to the event system. It's not an error to call this function if
* already connected. Returns 1 on failure, 0 on sucess.
*/
int
event_connect()
{
if (!event_handle) {
event_handle = event_register("elvin://" BOSSNODE,0);
}
if (event_handle) {
return 0;
} else {
fprintf(stderr,"event_connect: "
"Unable to register with event system!\n");
return 1;
}
}
/*
* Send an event to the event system. Automatically connects (registers)
* if not already done. Returns 0 on sucess, 1 on failure.
*/
int myevent_send(address_tuple_t tuple) {
event_notification_t notification;
if (event_connect()) {
return 1;
}
notification = event_notification_alloc(event_handle,tuple);
if (notification == NULL) {
fprintf(stderr,"myevent_send: Unable to allocate notification!");
return 1;
}
if (event_notify(event_handle, notification) == NULL) {
event_notification_free(event_handle, notification);
fprintf(stderr,"myevent_send: Unable to send notification!");
/*
* Let's try to disconnect from the event system, so that
* we'll reconnect next time around.
*/
if (!event_unregister(event_handle)) {
fprintf(stderr,"myevent_send: "
"Unable to unregister with event system!");
}
event_handle = NULL;
return 1;
} else {
event_notification_free(event_handle,notification);
return 0;
}
}
#endif /* EVENTSYS */
......@@ -41,7 +41,7 @@ query_db(struct in_addr ipaddr, struct in_addr *sip,
char *bootprog, int bootlen)
{
char querybuf[1024];
int n, nrows, ncols, part;
int n, nrows, ncols;
MYSQL db;
MYSQL_RES *res;
MYSQL_ROW row;
......@@ -153,6 +153,96 @@ query_db(struct in_addr ipaddr, struct in_addr *sip,
#undef PXEBOOT_PATH
#undef NEXT_PXEBOOT_PATH
int
ip2nodeid(struct in_addr ipaddr, char *nodeid, int len)
{
char querybuf[1024];
int n, nrows, ncols;
MYSQL db;
MYSQL_RES *res;
MYSQL_ROW row;
char dbquery[] =
"select node_id from interfaces where IP = '%s'";
#define NODE_ID 0
n = snprintf(querybuf, sizeof querybuf, dbquery, inet_ntoa(ipaddr));
if (n > sizeof querybuf) {
syslog(LOG_ERR, "query too long for buffer");
return 1;
}
mysql_init(&db);
if (mysql_real_connect(&db, 0, 0, 0, dbname, 0, 0, 0) == 0) {
syslog(LOG_ERR, "%s: connect failed: %s",
dbname, mysql_error(&db));
return 1;
}
/* Debug message into log:
syslog(LOG_ERR, "USING QUERY: %s", querybuf);
*/
if (mysql_real_query(&db, querybuf, n) != 0) {
syslog(LOG_ERR, "%s: query failed: %s",
dbname, mysql_error(&db));
mysql_close(&db);
return 1;
}
res = mysql_store_result(&db);
if (res == 0) {
syslog(LOG_ERR, "%s: store_result failed: %s",
dbname, mysql_error(&db));
mysql_close(&db);
return 1;
}
mysql_close(&db);
nrows = (int)mysql_num_rows(res);
switch (nrows) {
case 0:
syslog(LOG_ERR, "%s: no entry for host %s",
dbname, inet_ntoa(ipaddr));
mysql_free_result(res);
return 1;
case 1:
break;
default:
syslog(LOG_ERR, "%s: %d entries for IP %s, using first",
dbname, nrows, inet_ntoa(ipaddr));
break;
}
ncols = (int)mysql_num_fields(res);
switch (ncols) {
case 1: /* Should have 1 field */
break;
default:
syslog(LOG_ERR, "%s: %d fields in query for node_id of IP %s!",
dbname, ncols, inet_ntoa(ipaddr));
mysql_free_result(res);
return 1;
}
row = mysql_fetch_row(res);
if (row[NODE_ID] != 0 && row[NODE_ID][0] != '\0') {
if (strlen(row[NODE_ID]) >= len)
goto bad;
strcpy(nodeid, row[NODE_ID]);
mysql_free_result(res);
return 0;
}
bad:
mysql_free_result(res);
return 1;
}
#undef NODE_ID
int
close_db(void)
{
......
......@@ -17,7 +17,7 @@ SUBDIRS = checkpass ns2ir
BIN_STUFF = power snmpit tbend tbswapin tbswapout tbprerun tbreport \
tbresize os_load startexp endexp batchexp swapexp \
node_reboot nscheck node_update savelogs node_control \
portstats checkports eventsys_control
portstats checkports eventsys_control os_select
# Stuff that mere users get on plastic.
USERBINS = os_load node_reboot nscheck node_update savelogs \
......
......@@ -1154,8 +1154,8 @@ foreach $pair (@nodepairs) {
die("*** $0:\n".
" Invalid OS $osname in project $pid!\n");
}
DBQueryFatal("UPDATE nodes set def_boot_osid=\"$osid\"," .
" def_boot_cmd_line='$cmdline'," .
system("os_select $osid $pnode");
DBQueryFatal("UPDATE nodes set def_boot_cmd_line='$cmdline'," .
" startstatus='none'," .
" bootstatus='unknown'," .
" ready=0," .
......@@ -1168,9 +1168,8 @@ foreach $pair (@nodepairs) {
" where node_id='$pnode'");
} elsif (! defined($lannodes{$p2vmap{$pnode}})) {
# Delay node
DBQueryFatal("UPDATE nodes set def_boot_osid=\"" .
$delayosids{$type} . "\"," .
" startstatus=\"none\"," .
system("os_select ". $delayosids{$type} ." $pnode");
DBQueryFatal("UPDATE nodes set startstatus=\"none\"," .
" bootstatus=\"unknown\"," .
" ready=0" .
" where node_id=\"$pnode\"");
......
......@@ -13,7 +13,7 @@ use Getopt::Std;
# usage: node_control [options] node [node ...]
# node_control [options] -e pid,eid
#
# XXX def_boot_osid and virt_nodes osname are not handled properly.
# XXX virt_nodes osname is not handled properly.
#
sub usage()
{
......@@ -38,18 +38,12 @@ my %controlset =
#
# Symbolic name => Admin, Multi args, nodes DB field, virt_nodes DB field
#
default_boot_osid => [0, 0, "def_boot_osid", undef],
default_boot_path => [0, 0, "def_boot_path", undef],
default_boot_cmdline => [0, 0, "def_boot_cmd_line", "cmd_line"],
startup_command => [0, 0, "startupcmd", "startupcmd"],
tarfiles => [0, 1, "tarballs", "tarfiles"],
rpms => [0, 1, "rpms", "rpms"],
deltas => [0, 1, "deltas", "deltas"],
next_boot_osid => [1, 0, "next_boot_osid", undef],
next_boot_path => [1, 0, "next_boot_path", undef],
next_boot_cmdline => [1, 0, "next_boot_cmd_line", undef],
pxe_boot_path => [0, 0, "pxe_boot_path", undef],
next_pxe_boot_path => [0, 0, "next_pxe_boot_path", undef],
bios_version => [1, 0, "bios_version", undef],
);
......
......@@ -370,7 +370,15 @@ sub RebootNode {
# punch the power button.
#
if (WaitTillDead($pc) == 0) {
TBSetNodeEventState($pc,TBDB_NODESTATE_REBOOTING);
my $query_result =
DBQueryFatal("select op_mode from nodes where node_id='$pc'");
my @row = $query_result->fetchrow_array();
my $opmode = $row[0];
my $state = TBDB_NODESTATE_SHUTDOWN;
if ($opmode eq "NORMAL") {
$state = TBDB_NODESTATE_REBOOTING;
}
TBSetNodeEventState($pc,$state);
exit(0);
}
......
......@@ -62,10 +62,10 @@ use libdb;
use libtestbed;
my $NETDISKOSID = "NETDISK-STD";
my $FRISBEEPATH = "$BOSSADDR:/tftpboot/pxeboot.frisbee";
my $FRISBEELAUNCHER = "$TB/sbin/frisbeelauncher";
my $nodereboot = "$TB/bin/node_reboot";
my $schedreload = "$TB/bin/sched_reload";
my $osselect = "$TB/bin/os_select";
my $ping = "/sbin/ping";
my $dbg = 0;
my @row;
......@@ -315,9 +315,7 @@ foreach my $node (@nodes) {
print STDOUT "Changing default OS for $node to $defosid\n";
if (!$TESTMODE) {
DBQueryFatal("update nodes set ".
"def_boot_osid='$defosid',def_boot_path='' ".
"where node_id='$node'");
system("$osselect $defosid $node");
}