All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit 3c1a5bad authored by Timothy Stack's avatar Timothy Stack

Robot related stuff: power via e-mail, client-install fixups, checking
coords against camera boundaries.

	* configure, configure.in: Add tbsetup/power_mail.pm to the list
	of template files.

	* doc/cross-compiling.txt: More stargate notes.

	* event/sched/rpc.cc: Updates for the addition of the cameras
	table.

	* robots/GNUmakefile.in, robots/emc/GNUmakefile.in,
	robots/mtp/GNUmakefile.in, robots/rmcd/GNUmakefile.in,
	robots/tbsetdest/GNUmakefile.in, robots/vmcd/GNUmakefile.in:
	client-install fixups.

	* tbsetup/GNUmakefile.in: Add power_mail.pm.

	* tbsetup/os_setup.in: Don't skip reboot of robots anymore.

	* tbsetup/power.in: Add special case for a power_id of "mail",
	which calls into the power_mail.pm backend.

	* tbsetup/power_mail.pm.in: E-mail backend for power, it sends an
	e-mail to tbops and waits for the outlets.last_power value to be
	updated from the power.php3 web page.

	* tbsetup/ns2ir/parse-ns.in: Add the contents of the cameras table
	to the TBCOMPAT namespace.

	* tbsetup/ns2ir/sim.tcl.in: More checking of "setdest" inputs.

	* tbsetup/ns2ir/topography.tcl: Update the checkdest method to
	check destination points against the camera list.

	* www/powertime.php3: Webpage used to update the last power time
	for nodes.

	* www/shownode.php3: Add "Update Power Time" menu button.
parent 254e99e8
......@@ -1916,6 +1916,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/GNUmakefile tbsetup/console_setup tbsetup/spewlogfile \
tbsetup/spewrpmtar tbsetup/gentopofile tbsetup/power_sgmote.pm \
tbsetup/console_reset tbsetup/bwconfig tbsetup/power_rpc27.pm \
tbsetup/power_mail.pm \
tbsetup/os_load tbsetup/os_setup tbsetup/os_select tbsetup/power \
tbsetup/node_reboot tbsetup/webnscheck tbsetup/nscheck \
tbsetup/resetvlans tbsetup/rmuser tbsetup/rmproj \
......
......@@ -623,6 +623,7 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/GNUmakefile tbsetup/console_setup tbsetup/spewlogfile \
tbsetup/spewrpmtar tbsetup/gentopofile tbsetup/power_sgmote.pm \
tbsetup/console_reset tbsetup/bwconfig tbsetup/power_rpc27.pm \
tbsetup/power_mail.pm \
tbsetup/os_load tbsetup/os_setup tbsetup/os_select tbsetup/power \
tbsetup/node_reboot tbsetup/webnscheck tbsetup/nscheck \
tbsetup/resetvlans tbsetup/rmuser tbsetup/rmproj \
......
......@@ -95,3 +95,15 @@ made a fake /sbin/consoletype
copied /etc/sysconfig/network from a pc
added /var/tmp, /var/db to /etc/rcS.d/S05mountall.sh for install-tarfile
rsync flags: -avzpog --exclude-from=garcia.exclude
contents of garcia.exclude:
/proj/*
/share/*
/var/*
/proc/*
/users/*
/dev/*
/tmp/*
/mnt/*
......@@ -323,17 +323,17 @@ RPC_cameralist(FILE *emcd_config, char *area)
ulxr::RpcString tmp;
ulxr::Struct attr;
int port;
attr = cameras.getItem(lpc);
tmp = attr.getMember("host");
tmp = attr.getMember("hostname");
port = ((ulxr::Integer)attr.getMember("port")).getInteger();
fprintf(emcd_config,
"camera %s %s %d %f %f %f %f\n",
area,
tmp.getString().c_str(),
port,
((ulxr::Double)attr.getMember("x")).getDouble(),
((ulxr::Double)attr.getMember("y")).getDouble(),
((ulxr::Double)attr.getMember("loc_x")).getDouble(),
((ulxr::Double)attr.getMember("loc_y")).getDouble(),
((ulxr::Double)attr.getMember("width")).getDouble(),
((ulxr::Double)attr.getMember("height")).getDouble());
}
......
......@@ -27,6 +27,7 @@ SUBDIRS = tbsetdest $(MEZZDIR) mtp $(EMCDIR) vmcd primotion rmcd
all: all-subdirs
client: client-subdirs
client-install: client-install-subdirs
check: check-subdirs
install: install-subdirs
......
......@@ -15,7 +15,7 @@ PROGS = emcd loclistener
TESTS = test_emcd.sh
all: $(PROGS)
client:
client client-install:
include $(TESTBED_SRCDIR)/GNUmakerules
......@@ -23,11 +23,11 @@ OBJS = emcd.o robot_list.o
CFLAGS += -O -g -Wall -I${OBJDIR} -I/usr/local/include
CFLAGS += -I${SRCDIR}/../mtp -I../mtp -I${SRCDIR}/../../event/lib
CFLAGS += -I${SRCDIR}/../../lib/libtb
CFLAGS += `elvin-config --cflags vin4c`
CFLAGS += `$(ELVIN_CONFIG) --cflags vin4c`
LDFLAGS = -L../mtp -L${OBJDIR}/lib/libtb -L${OBJDIR}/event/lib
LIBS += -levent -lcrypto -lmtp -ltb
LIBS += `elvin-config --libs vin4c`
LIBS += `$(ELVIN_CONFIG) --libs vin4c`
test_emcd.sh: emcd
......
......@@ -22,6 +22,7 @@ JARS = $(TESTBED_SRCDIR)/www/mtp.jar
endif
all client: $(MTPLIBS) $(MTPPROGS) $(JARS)
client-install:
include $(TESTBED_SRCDIR)/GNUmakerules
......
......@@ -30,7 +30,7 @@ client-install: client
include $(TESTBED_SRCDIR)/GNUmakerules
CXXFLAGS += -O -g -Wall -I${OBJDIR} -I/usr/local/include
CXXFLAGS += -I${SRCDIR}/../mtp -I../mtp
CXXFLAGS += -I${SRCDIR}/../mtp -I../mtp -pthread -D_REENTRANT
LDFLAGS = -L../mtp -Ldgrobot
......@@ -68,7 +68,7 @@ LDFLAGS += \
-laStem \
-laIO \
-laUI \
-lpthread \
-pthread \
-lm
endif
......
......@@ -12,7 +12,9 @@
#include "config.h"
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#include <signal.h>
#include <string.h>
......@@ -24,6 +26,9 @@
#include <sys/socket.h>
#include <arpa/inet.h>
#include <list>
#include <algorithm>
#include "acpGarcia.h"
#include "acpValue.h"
......@@ -37,6 +42,8 @@
*/
#define PILOT_PORT 2531
static const char *DEFAULT_LOG_PATH = "/tmp/garcia-pilot.log";
/**
* Default path to the battery log.
*/
......@@ -49,6 +56,9 @@ static const char *BATTERY_LOG_PATH = "/var/log/battery.log";
*/
static volatile int looping = 1;
extern char **environ;
static char **reexec_argv;
/**
* Signal handler for SIGINT, SIGTERM, and SIGQUIT signals. Sets looping to
* zero and aborts() if it is called more than three times in case the program
......@@ -89,13 +99,19 @@ static void sigdebug(int sig)
* Signal handler for SIGSEGV and SIGBUS, just prints out the signal number and
* aborts.
*/
static void sigpanic(int sig)
static void sigpanic(int signum)
{
fprintf(stderr,
"panic: signal=%d\n",
sig);
char msg[128];
snprintf(msg, sizeof(msg), "panic: %d; reexec'ing\n", signum);
write(1, msg, strlen(msg));
execve(reexec_argv[0], reexec_argv, environ);
abort();
snprintf(msg, sizeof(msg), "reexec failed %s\n", strerror(errno));
write(1, msg, strlen(msg));
exit(1);
}
/**
......@@ -119,15 +135,21 @@ static void usage(void)
int main(int argc, char *argv[])
{
int c, port = PILOT_PORT, serv_sock, on_off = 1;
const char *logfile = NULL, *pidfile = NULL;
int lpc, c, port = PILOT_PORT, serv_sock, on_off = 1;
const char *logfile = DEFAULT_LOG_PATH, *pidfile = NULL;
const char *batteryfile = BATTERY_LOG_PATH;
int retval = EXIT_SUCCESS;
std::list<int> fd_list;
unsigned long now;
FILE *batterylog;
aIOLib ioRef;
sigset_t ss;
aErr err;
reexec_argv = argv;
sigfillset(&ss);
sigprocmask(SIG_UNBLOCK, &ss, NULL);
while ((c = getopt(argc, argv, "hdp:l:i:b:")) != -1) {
switch (c) {
case 'h':
......@@ -167,7 +189,7 @@ int main(int argc, char *argv[])
if (!debug) {
/* Become a daemon */
daemon(0, 0);
daemon(1, 0);
if (logfile) {
int logfd;
......@@ -187,7 +209,6 @@ int main(int argc, char *argv[])
FILE *fp;
if ((fp = fopen(pidfile, "w")) != NULL) {
fprintf(fp, "%d\n", getpid());
(void) fclose(fp);
}
}
......@@ -198,16 +219,24 @@ int main(int argc, char *argv[])
batteryfile);
}
for (lpc = 3; lpc < 32; lpc++) {
struct stat st;
if (fstat(lpc, &st) == 0) {
fd_list.push_back(lpc);
}
}
acpGarcia garcia;
signal(SIGUSR1, sigdebug);
signal(SIGHUP, sigdebug);
signal(SIGQUIT, sigquit);
signal(SIGTERM, sigquit);
signal(SIGINT, sigquit);
signal(SIGSEGV, (void (*)(int))sigpanic);
signal(SIGBUS, (void (*)(int))sigpanic);
signal(SIGSEGV, sigpanic);
signal(SIGBUS, sigpanic);
signal(SIGPIPE, SIG_IGN);
......@@ -271,12 +300,61 @@ int main(int argc, char *argv[])
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_SET(serv_sock, &readfds);
for (lpc = 3; lpc < 32; lpc++) {
struct stat st;
if ((fstat(lpc, &st) == 0) &&
(std::find(fd_list.begin(),
fd_list.end(),
lpc) == fd_list.end())) {
fcntl(lpc, F_SETFD, 1);
}
}
for (lpc = 3; lpc < 128; lpc++) {
struct sockaddr_in sin;
socklen_t sin_len;
sin_len = sizeof(sin);
if ((lpc != serv_sock) &&
(getpeername(lpc,
(struct sockaddr *)&sin,
&sin_len) == 0)) {
struct mtp_packet ump;
if (debug) {
printf("recovered client: %s:%d\n",
inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
}
pilotClient *pc = new pilotClient(lpc, wm, db);
pc->setFD(&readfds);
pc->setFD(&writefds);
clients.push_back(pc);
mtp_init_packet(&ump,
MA_Opcode, MTP_UPDATE_POSITION,
MA_Role, MTP_ROLE_ROBOT,
MA_Status, MTP_POSITION_STATUS_IDLE,
MA_CommandID, 0,
MA_TAG_DONE);
mtp_send_packet(pc->getHandle(), &ump);
}
}
wm.setDashboard(&db);
do {
fd_set rreadyfds = readfds, wreadyfds = writefds;
struct timeval tv_zero = { 0, 0 };
int rc;
if (debug == 3) {
int *i = 0;
*i = 1;
}
/* Poll the file descriptors, don't block */
rc = select(FD_SETSIZE,
......@@ -381,8 +459,10 @@ int main(int argc, char *argv[])
aIO_ReleaseLibRef(ioRef, &err);
fclose(batterylog);
batterylog = NULL;
if (batterylog) {
fclose(batterylog);
batterylog = NULL;
}
return retval;
}
......@@ -16,6 +16,8 @@
#include "pilotClient.hh"
extern int debug;
/**
* Callback passed to the wheelManager when performing movements.
*/
......@@ -52,7 +54,7 @@ void pilotMoveCallback::call(int status)
pilotClient::iterator i;
mtp_packet_t mp;
mtp_status_t ms;
switch (status) {
case aGARCIA_ERRFLAG_NORMAL:
ms = MTP_POSITION_STATUS_COMPLETE;
......
......@@ -19,6 +19,8 @@
#include "dashboard.hh"
#include "wheelManager.hh"
extern int debug;
/**
* An "execute" callback for a garcia behavior.
*/
......@@ -301,8 +303,16 @@ void wheelManager::stop(void)
void wheelManager::motionStarted(void)
{
if (debug) {
fprintf(stderr, "debug: motion started\n");
}
if ((this->wm_last_status != aGARCIA_ERRFLAG_NORMAL) &&
(this->wm_last_status != aGARCIA_ERRFLAG_ABORT)) {
if (debug) {
fprintf(stderr, "debug: clear error LED\n");
}
this->wm_dashboard->remUserLEDClient(&this->wm_error_notice);
this->wm_last_status = 0;
}
......@@ -315,9 +325,17 @@ void wheelManager::motionFinished(int status, wmCallback *callback)
{
this->wm_last_status = status;
if (debug) {
fprintf(stderr, "debug: motion finished -- %d\n", status);
}
if (status != aGARCIA_ERRFLAG_WONTEXECUTE) {
if ((this->wm_last_status != aGARCIA_ERRFLAG_NORMAL) &&
(this->wm_last_status != aGARCIA_ERRFLAG_ABORT)) {
if (debug) {
fprintf(stderr, "debug: set error LED\n");
}
this->wm_dashboard->addUserLEDClient(&this->wm_error_notice);
}
......
......@@ -15,7 +15,7 @@ PROGS = rmcd
TESTS = test_rmcd.sh test_rmcd2.sh
all: $(PROGS)
client:
client client-install:
include $(TESTBED_SRCDIR)/GNUmakerules
......
......@@ -14,7 +14,7 @@ include $(OBJDIR)/Makeconf
PROGS = tbsetdest
all: $(PROGS)
client:
client client-install:
include $(TESTBED_SRCDIR)/GNUmakerules
......
......@@ -26,7 +26,7 @@ TESTS += test_vmcd.sh test_vmcd2.sh test_vmcd3.sh test_vmcd4.sh
endif
all: $(PROGS)
client:
client client-install:
include $(TESTBED_SRCDIR)/GNUmakerules
......
......@@ -48,7 +48,8 @@ LIB_STUFF = libtbsetup.pm exitonwarn.pm libtestbed.pm snmpit_intel.pm \
snmpit_cisco.pm snmpit_lib.pm snmpit_apc.pm power_rpc27.pm \
snmpit_cisco_stack.pm snmpit_intel_stack.pm power_sgmote.pm \
snmpit_foundry.pm snmpit_stack.pm snmpit_remote.pm \
libaudit.pm libreboot.pm libosload.pm libtestbed.py
libaudit.pm libreboot.pm libosload.pm libtestbed.py \
power_mail.pm
#
# Force dependencies on the scripts so that they will be rerun through
......
......@@ -449,6 +449,18 @@ sub GenDefsFile($)
}
print TCL "\n";
print TCL "# Cameras\n";
$query_result = DBQueryFatal(
"select name,building,loc_x,loc_y,width,height from cameras");
while (my ($name,$building,$loc_x,$loc_y,$width,$height) =
$query_result->fetchrow_array()) {
print TCL "set cameras($name,$building,x) $loc_x\n";
print TCL "set cameras($name,$building,y) $loc_y\n";
print TCL "set cameras($name,$building,width) $width\n";
print TCL "set cameras($name,$building,height) $height\n";
}
print TCL "\n";
if (defined($pid)) {
print TCL "# OSIDs\n";
$query_result =
......
......@@ -1161,15 +1161,14 @@ Simulator instproc make_event {outer event} {
}
set x [lindex $evargs 0]
set y [lindex $evargs 1]
if {$x < 0 || $x >= [$topo set width]} {
perror "$x is out of bounds for node $obj"
if {! [$topo checkdest $self $x $y]} {
return
}
if {$y < 0 || $y >= [$topo set height]} {
perror "$x is out of bounds for node $obj"
set speed [lindex $evargs 2]
if {$speed != 0.0 && $speed != 0.1} {
perror "Speed is currently locked at 0.0 or 0.1"
return
}
set speed [lindex $evargs 2]
::GLOBALS::named-args [lrange $evargs 3 end] {
-orientation 0
}
......
......@@ -63,6 +63,7 @@ Topography instproc initialized {} {
Topography instproc checkdest {obj x y} {
var_import ::TBCOMPAT::obstacles
var_import ::TBCOMPAT::cameras
$self instvar area_name
$self instvar width
$self instvar height
......@@ -82,13 +83,33 @@ Topography instproc checkdest {obj x y} {
set id [lindex [split $key ,] 0]
if {($x >= $obstacles($id,$area_name,x1)) &&
($x < $obstacles($id,$area_name,x2)) &&
($x <= $obstacles($id,$area_name,x2)) &&
($y >= $obstacles($id,$area_name,y1)) &&
($y < $obstacles($id,$area_name,y2))} {
($y <= $obstacles($id,$area_name,y2))} {
perror "Destination $x,$y puts $obj in obstacle $value."
return 0
}
}
set camlist [array get cameras *,$area_name,x]
set in_cam ""
foreach {key value} $camlist {
set id [lindex [split $key ,] 0]
if {($x >= $cameras($id,$area_name,x)) &&
($x < [expr $cameras($id,$area_name,x) + \
$cameras($id,$area_name,width)]) &&
($y >= $cameras($id,$area_name,y)) &&
($y < [expr $cameras($id,$area_name,y) + \
$cameras($id,$area_name,height)])} {
set in_cam $id
}
}
if {$in_cam == ""} {
perror "Destination $x,$y is out of view of the tracking cameras";
return 0
}
}
return 1
}
......@@ -223,7 +223,8 @@ while (my %row = $db_result->fetchhash()) {
elsif ($class eq "robot") {
print "Skipping os_setup for $node cause its a robot.\n";
TBSetNodeAllocState($node, TBDB_ALLOCSTATE_RES_READY);
SetNodeBootStatus($node, NODEBOOTSTATUS_OKAY);
$nodeAllocStates{$node} = TBDB_ALLOCSTATE_RES_READY;
$reboots{$node} = 1;
next;
}
elsif ($subnode) {
......
......@@ -2,7 +2,7 @@
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2004 University of Utah and the Flux Group.
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# All rights reserved.
#
......@@ -28,6 +28,7 @@ use libdb;
use libxmlrpc;
use power_rpc27;
use power_sgmote;
use power_mail;
use snmpit_apc;
use libtestbed;
use strict;
......@@ -210,7 +211,8 @@ foreach my $node (@machines) {
if (! ($time_ok || ($UID == 0)) ) {
warn "$node was power cycled recently. Skipping...\n";
next;
} else {
} elsif ( $power_id ne "mail" ) {
print "updating last_power\n";
DBQueryFatal("update outlets set last_power=CURRENT_TIMESTAMP " .
"where node_id = '$node'");
}
......@@ -240,21 +242,32 @@ foreach my $power_id (keys %outlets) {
}
my $nodestr = join(",",@nodes);
#
# Find out some information about this power controller
#
my $result = DBQueryFatal("select n.type, i.IP, t.class ".
"from nodes as n " .
"left join interfaces as i on n.node_id=i.node_id " .
"left join node_types as t on n.type=t.type " .
"where n.node_id='$power_id'");
if ($result->num_rows() == 0) {
warn "No entry found for power controller $power_id. Skipping " .
"$nodestr\n";
$exitval++;
next;
my $type;
my $IP;
my $class;
if ($power_id eq "mail") {
$type = "mail";
$IP = "";
$class = "";
}
else {
#
# Find out some information about this power controller
#
my $result = DBQueryFatal("select n.type, i.IP, t.class ".
"from nodes as n " .
"left join interfaces as i on n.node_id=i.node_id " .
"left join node_types as t on n.type=t.type " .
"where n.node_id='$power_id'");
if ($result->num_rows() == 0) {
warn "No entry found for power controller $power_id. Skipping " .
"$nodestr\n";
$exitval++;
next;
}
($type, $IP, $class) = $result->fetchrow();
}
my ($type, $IP, $class) = $result->fetchrow();
#
# Finally, we look at the controller type and construct the proper type
......@@ -285,6 +298,11 @@ foreach my $power_id (keys %outlets) {
print "Control of $nodestr failed.\n"; $exitval++;
$errors++;
}
} elsif ($type eq "mail") {
if (mailctrl($op,@nodes)) {
print "Control of $nodestr failed.\n"; $exitval++;
$errors++;
}
} else {
print "power: Unknown power type '$type'\n";
$errors++;
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005 University of Utah and the Flux Group.
# All rights reserved.
#
# A perl module to power cycle nodes using email to the operators.
package power_mail;
use Exporter;
@ISA = ("Exporter");
@EXPORT = qw( mailctrl );
use lib "@prefix@/lib";
use libdb;
use libtestbed;
my $WWW = "@WWW@";
my $TBOPS = "@TBOPSEMAIL@";
my $default_tries = 10;
# Turn off line buffering on output
$| = 1;
# usage: mailctrl(cmd, nodes)
# cmd = { "cycle" | "on" | "off" }
# nodes = list of one or more physcial node names
#
# Returns 0 on success. Non-zero on failure.
#
sub mailctrl($@) {
my ($cmd, @nodes) = @_;
my %actual = ();
# Check to see if we have to send mail first.
foreach my $node (@nodes) {
my $dbres = DBQueryFatal(
"select (CURRENT_TIMESTAMP - last_power) < 500 " .
"from outlets where node_id='$node'");
if ($dbres->num_rows() == 0) {
print "Unknown node $node";
next;
}
($ok) = $dbres->fetchrow();