Commit d30542c8 authored by Ryan Jackson's avatar Ryan Jackson

Copy event scheduler to new directory

parent 9ab46722
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2007 University of Utah and the Flux Group.
# All rights reserved.
#
SRCDIR = @srcdir@
TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ../..
SUBDIR = event/sched
include $(OBJDIR)/Makeconf
all: event-sched_rrpc
include $(TESTBED_SRCDIR)/GNUmakerules
CFLAGS += -g -pthread -DBINDIR='"$(INSTALL_BINDIR)"'
CFLAGS += -DSBINDIR='"$(INSTALL_SBINDIR)"'
#CFLAGS += -DDEBUG
CFLAGS += -O -Wall
CFLAGS += -I. -I${OBJDIR} -I$(SRCDIR)/../lib -I$(TESTBED_SRCDIR)/lib/libtb
CFLAGS += -I/usr/local/include
LDFLAGS += -pthread
LDFLAGS += -L../lib -L${OBJDIR}/lib/libtb
LDFLAGS += $(LDSTATIC)
DBLIBS = -L/usr/local/lib/mysql -lmysqlclient -lz
LIBS += -levent_r -ltb -lz
ULXRINC = -I/usr/local/include -I/usr/local/include/ulxmlrpcpp
CXXFLAGS += -pthread -O $(ULXRINC) -I$(OBJDIR) -I$(TESTBED_SRCDIR)/lib/libtb
CXXFLAGS += -I$(SRCDIR)/../lib
ULXRLIBS = -L/usr/local/lib -lulsshxmlrpcpp -lulxmlrpcpp -lexpat
#
# XXX elvin-config adds -lc which is rather bogus, and messes up -pthread
# build on freebsd. I made a vain attempt to filter it out, but
# gave up quickly. Deal with it later.
#
#LIBS += `elvin-config --libs vin4mt`
LIBS += -L/usr/local/lib -lpubsub_r -lssl -lcrypto -lm
OBJS = event-sched.o
version.c: event-sched.c
echo >$@ "char build_info[] = \"Built on `date +%d-%b-%Y` by `id -nu`@`hostname | sed 's/\..*//'`:`pwd`\";"
OBJS = \
console-agent.o \
error-record.o \
event-sched_rpc.o \
group-agent.o \
listNode.o \
local-agent.o \
node-agent.o \
queue.o \
rrpc.o \
simulator-agent.o \
timeline-agent.o \
version.o
event-sched_rrpc: $(OBJS) event-sched.h ../lib/libevent.a
$(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(ULXRLIBS) $(LIBS)
DEPS = \
console-agent.h error-record.h event-sched.h group-agent.h listNode.h \
local-agent.h node-agent.h rpc.h simulator-agent.h timeline-agent.h \
../lib/event.h
queue.o: queue.c $(DEPS)
listNode.o: listNode.c $(DEPS)
error-record.o: error-record.c $(DEPS)
local-agent.o: local-agent.c $(DEPS)
group-agent.o: group-agent.c $(DEPS)
simulator-agent.o: simulator-agent.cc $(DEPS)
console-agent.o: console-agent.cc $(DEPS)
node-agent.o: node-agent.cc $(DEPS)
event-sched_rpc.o: event-sched.c $(DEPS)
$(CC) $(CFLAGS) -DRPC -c -o $@ $<
rpc.o: rpc.cc rpc.h event-sched.h
$(CXX) $(CXXFLAGS) -DSSHRPC $(ULXRINC) -c $<
rrpc.o: rpc.cc $(DEPS)
$(CXX) -g $(CXXFLAGS) -DSSLRPC $(ULXRINC) -c -o rrpc.o $<
install: event-sched_rrpc
-mkdir -p $(INSTALL_DIR)/opsdir/sbin
$(INSTALL_PROGRAM) $< $(INSTALL_DIR)/opsdir/sbin/event-sched
-mkdir -p $(INSTALL_DIR)/opsdir/man/man8
$(INSTALL) -m 0644 $(SRCDIR)/event-sched.8 \
$(INSTALL_DIR)/opsdir/man/man8/event-sched.8
-mkdir -p $(INSTALL_DIR)/opsdir/bin
$(INSTALL_PROGRAM) $(SRCDIR)/elog2xplot \
$(INSTALL_DIR)/opsdir/bin/elog2xplot
control-install: event-sched_rrpc
$(INSTALL_PROGRAM) $< $(INSTALL_SBINDIR)/event-sched
# not a client thing
client:
client-install: client
clean:
/bin/rm -f *.o event-sched event-sched_rpc event-sched_rrpc version.c
#
# EMULAB-COPYRIGHT
# Copyright (c) 2002 University of Utah and the Flux Group.
# All rights reserved.
#
# Makefile for building event scheduler
#
# $Id: Makefile,v 1.5 2006-12-01 22:59:37 mike Exp $
CC = gcc
CFLAGS = -g -I. -I../lib -Wall -DDEBUG
LDFLAGS =
LIBS = -lpthread -L../lib -levent
CFLAGS += `elvin-config --cflags vin4mt`
LIBS += `elvin-config --libs vin4mt`
MV = mv -f
RM = rm -f
program = event-sched
source = event-sched.c queue.c
object = event-sched.o queue.o
header = event-sched.h
.c.o:
$(CC) $(CFLAGS) -c $<
default: $(program)
$(program): $(object)
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(LIBS)
$(program): ../lib/libevent.a
$(object): $(header) ../lib/event.h
clean:
$(RM) $(program) $(object)
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2004, 2005, 2007 University of Utah and the Flux Group.
* All rights reserved.
*/
#include "config.h"
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
#include <string.h>
#include "console-agent.h"
#ifndef min
#define min(x, y) ((x) < (y)) ? (x) : (y)
#endif
/**
* A "looper" function for console agents that dequeues and processes events
* for a particular console. This function will be passed to pthread_create
* when a new thread needs to be created to handle events.
*
* @param arg The console agent object to handle events for.
* @return NULL
*
* @see reload_with
* @see do_reboot
* @see local_agent_queue
* @see local_agent_dequeue
*/
static void *console_agent_looper(void *arg);
console_agent_t create_console_agent(void)
{
console_agent_t ca, retval;
if ((ca = (console_agent_t)
malloc(sizeof(struct _console_agent))) == NULL) {
retval = NULL;
errno = ENOMEM;
}
else if (local_agent_init(&ca->ca_local_agent) != 0) {
retval = NULL;
}
else {
ca->ca_local_agent.la_flags |= LAF_MULTIPLE;
ca->ca_local_agent.la_looper = console_agent_looper;
ca->ca_mark = -1;
retval = ca;
ca = NULL;
}
free(ca);
ca = NULL;
return retval;
}
int console_agent_invariant(console_agent_t ca)
{
assert(ca != NULL);
assert(local_agent_invariant(&ca->ca_local_agent));
}
static void do_start(console_agent_t ca, sched_event_t *se)
{
int lpc;
assert(ca != NULL);
assert(console_agent_invariant(ca));
assert(se != NULL);
for (lpc = 0; lpc < se->length; lpc++) {
char path[MAXPATHLEN];
struct agent *agent;
struct stat st;
if (se->length == 1)
agent = se->agent.s;
else
agent = se->agent.m[lpc];
snprintf(path, sizeof(path),
"%s/%s.run",
TIPLOGDIR, agent->nodeid);
if (stat(path, &st) < 0) {
error("could not stat %s\n", path);
}
else {
ca = (console_agent_t)agent->handler;
ca->ca_mark = st.st_size;
}
}
}
static void do_stop(console_agent_t ca, sched_event_t *se, char *args)
{
char *filename;
int rc, lpc;
assert(ca != NULL);
assert(console_agent_invariant(ca));
assert(se != NULL);
assert(args != NULL);
if (ca->ca_mark == -1) {
error("CONSOLE STOP event without a START");
return;
}
if ((rc = event_arg_get(args, "FILE", &filename)) < 0) {
error("no filename given in CONSOLE STOP event");
return;
}
filename[rc] = '\0';
for (lpc = 0; lpc < se->length; lpc++) {
char path[MAXPATHLEN], outpath[MAXPATHLEN];
int infd = -1, outfd = -1;
struct agent *agent;
size_t end_mark;
struct stat st;
if (se->length == 1)
agent = se->agent.s;
else
agent = se->agent.m[lpc];
snprintf(path, sizeof(path),
"%s/%s.run",
TIPLOGDIR, agent->nodeid);
if (stat(path, &st) < 0) {
error("could not stat %s\n", path);
ca->ca_mark = -1;
continue;
}
snprintf(outpath, sizeof(outpath),
"logs/%s-%s.log",
agent->name,
filename);
ca = (console_agent_t)agent->handler;
end_mark = st.st_size;
if ((infd = open(path, O_RDONLY)) < 0) {
error("could not open %s\n", path);
}
else if (lseek(infd, ca->ca_mark, SEEK_SET) < 0) {
error("could not seek to right place\n");
}
else if ((outfd = open(outpath,
O_WRONLY|O_CREAT|O_TRUNC,
0640)) < 0) {
error("could not create output file\n");
}
else {
size_t remaining = end_mark - ca->ca_mark;
char buffer[4096];
while ((rc = read(infd,
buffer,
min(remaining,
sizeof(buffer)))) > 0) {
write(outfd, buffer, rc);
remaining -= rc;
}
}
if (infd != -1)
close(infd);
if (outfd != -1)
close(outfd);
ca->ca_mark = -1;
}
}
static void *console_agent_looper(void *arg)
{
console_agent_t ca = (console_agent_t)arg;
event_handle_t handle;
void *retval = NULL;
sched_event_t se;
assert(arg != NULL);
handle = ca->ca_local_agent.la_handle;
while (local_agent_dequeue(&ca->ca_local_agent, 0, &se) == 0) {
char evtype[TBDB_FLEN_EVEVENTTYPE];
event_notification_t en;
char argsbuf[BUFSIZ];
en = se.notification;
if (!event_notification_get_eventtype(
handle, en, evtype, sizeof(evtype))) {
error("couldn't get event type from notification %p\n",
en);
}
else {
struct agent **agent_array, *agent_singleton[1];
int rc, lpc, token = ~0;
event_notification_get_arguments(handle,
en,
argsbuf,
sizeof(argsbuf));
event_notification_get_int32(handle,
en,
"TOKEN",
(int32_t *)&token);
argsbuf[sizeof(argsbuf) - 1] = '\0';
if (strcmp(evtype, TBDB_EVENTTYPE_START) == 0) {
do_start(ca, &se);
}
else if (strcmp(evtype, TBDB_EVENTTYPE_STOP) == 0) {
do_stop(ca, &se, argsbuf);
}
else {
error("cannot handle CONSOLE event %s.",
evtype);
rc = -1;
}
}
sched_event_free(handle, &se);
}
return retval;
}
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2005 University of Utah and the Flux Group.
* All rights reserved.
*/
/**
* @file console-agent.h
*/
#ifndef _console_agent_h
#define _console_agent_h
#include "event-sched.h"
#include "local-agent.h"
#ifdef __cplusplus
extern "C" {
#endif
#define TIPLOGDIR "/var/log/tiplogs"
/**
* A local agent structure for Console objects.
*/
struct _console_agent {
struct _local_agent ca_local_agent; /*< Local agent base. */
off_t ca_mark;
};
/**
* Pointer type for the _console_agent structure.
*/
typedef struct _console_agent *console_agent_t;
/**
* Create a console agent and intialize it with the default values.
*
* @return An initialized console agent object.
*/
console_agent_t create_console_agent(void);
/**
* Check a console agent object against the following invariants:
*
* @li na_local_agent is sane
*
* @param na An initialized console agent object.
* @return True.
*/
int console_agent_invariant(console_agent_t na);
#ifdef __cplusplus
}
#endif
#endif
#! /usr/bin/awk -f
#
# EMULAB-COPYRIGHT
# Copyright (c) 2006 University of Utah and the Flux Group.
# All rights reserved.
#
BEGIN {
printf("timeval unsigned\n");
printf("title\n");
printf("Event Timeline\n");
printf("xlabel\n");
printf("time\n");
printf("ylabel\n");
printf("agent\n");
printf("white\n");
firsttime = 0;
agents = 0;
}
/Agent: / {
agents += 1;
agent[$2] = agents;
}
/Fire: / {
split($3, tv, /:/);
split($5, aname, /:/);
if (firsttime == 0 || tv[2] < firsttime)
firsttime = tv[2];
if (aname[2] in agent) {
printf("x %s.%s %s\n", tv[2], tv[3], agent[aname[2]]);
}
}
END {
for (ag in agent) {
printf("rtext %s.0 %d\n%s\n", firsttime - 5, agent[ag], ag);
}
printf("go\n");
}
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2004, 2005, 2007 University of Utah and the Flux Group.
* All rights reserved.
*/
/**
* @file error-record.c
*
* Implementation of the error-record code.
*/
#include "config.h"
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <sys/param.h>
#include <string.h>
#include <limits.h>
#include "tbdefs.h"
#include "popenf.h"
#include "error-record.h"
/**
* Dump a digested version of the program-agent's "status" file to the given
* output. The status file is a 'key=value' formatted file that describes a
* particular invocation of a program agent. The file is written out by the
* agent after the program finishes, pulled back to ops by a 'loghole sync' and
* then gets included in the Simulator's report through this function.
*
* @param er An error record for a failed program-agent invocation.
* @param out The file to write any output to.
* @return Zero on success, -1 otherwise.
*
* @see send_report
*/
static int dump_agent_status(error_record_t er, FILE *out);
/**
* Utility function to pipe the tail of a file to the given output file. After
* the program-agent's "status" file is dumped to the output, the tail of the
* file gets included as well so the user can get an idea of what went wrong.
*
* @param path The path of the file whose tail should be written to the output
* file.
* @param out The file to write any output to.
* @return Zero on success, -1 otherwise.
*
* @see dump_agent_status
*/
static int tail_file(char *path, FILE *out);
error_record_t create_error_record(void)
{
error_record_t retval = NULL;
if ((retval = calloc(1, sizeof(struct _error_record))) == NULL) {
errno = ENOMEM;
}
else {
retval->er_agent = NULL;
retval->er_token = -1;
retval->er_error = 0;
}
return retval;
}
void delete_error_record(error_record_t er)
{
if (er != NULL) {
free(er);
er = NULL;
}
}
int error_record_invariant(error_record_t er)
{
assert(er != NULL);
assert(er->er_agent != NULL);
assert(agent_invariant(er->er_agent));
assert(er->er_token != -1);
return 1;
}
void delete_error_records(struct lnList *list)
{
error_record_t er;
assert(list != NULL);
lnCheck(list);
while ((er = (error_record_t)lnRemHead(list)) != NULL) {
delete_error_record(er);
er = NULL;
}
lnCheck(list);
assert(lnEmptyList(list));
}
static int dump_agent_status(error_record_t er, FILE *out)
{
/*
* The format of the path for the status file:
* logs/<node>/<LOGDIR>/<agent>.<token>.status
*/
static char *file_format = "logs/%s" LOGDIR "/%s.status.%lu";
/*
* A map of status file 'keys' that people may be interested in and
* some human-readable prefix text.
*/
static struct {
char *key;
char *desc;
} status_map[] = {
{ "DIR", " Directory:\t" },
{ "COMMAND", " Command:\t" },
{ "START_TIME", " Started at:\t" },
{ "EXIT_CODE", " Exit code:\t" },
{ "TIMEOUT_FIRED", " Timeout Fired:\t" },
{ NULL, NULL }
};
char buffer[BUFSIZ];
int retval;
FILE *file;
assert(er != NULL);
assert(error_record_invariant(er));
assert(strcmp(er->er_agent->objtype, TBDB_OBJECTTYPE_PROGRAM) == 0);
assert(out != NULL);
snprintf(buffer,
sizeof(buffer),
file_format,
er->er_agent->vnode,
er->er_agent->name,
er->er_token);
/*
* We expect the file to have been brought over already, so just try
* to open out.
*/
if ((file = fopen(buffer, "r")) == NULL) {
fprintf(out, "warning: missing status file: '%s'\n", buffer);
retval = 0;
}
else {
/* Print out a short header, then */
fprintf(out,
"Program agent: '%s' located on node '%s'\n",
er->er_agent->name,
er->er_agent->vnode);
/* ... write out the data most people would care about. */
while (fgets(buffer, sizeof(buffer), file) != NULL) {
char *value;
if ((value = strchr(buffer, '=')) == NULL) {
warning("Bad line in status file: %s\n",
buffer);
}
else {
int lpc;
*value = '\0';
value += 1;
for (lpc = 0; status_map[lpc].key; lpc++) {
if (strcmp(buffer,
status_map[lpc].key) == 0) {
fprintf(out,
"%s%s",
status_map[lpc].desc,
value);
}
}
}
}
fclose(file);
file = NULL;
retval = 0;
}
return retval;
}
static int tail_file(char *path, FILE *out)
{
FILE *tail_in;
int retval;
assert(path != NULL);
assert(strlen(path) > 0);
assert(out != NULL);
if (access(path, R_OK) != 0) {
fprintf(out, "warning: missing log file: '%s'\n", path);
retval = 0; // Non-fatal error...
}
else if ((tail_in = popenf("tail %s", "r", path)) == NULL) {
fprintf(out, "error: cannot tail log '%s'\n", path);
retval = -1;
}
else {
char buffer[1024];
int rc;
/* Print a separator header, */
fprintf(out, ">> Tail of log '%s' <<\n", path);
/* ... the tail of the file, and */
while ((rc = fread(buffer,
1,
sizeof(buffer),
tail_in)) > 0) {
fwrite(buffer, 1, rc, out);
}
if (pclose(tail_in) == -1) {
warning("pclose for tail %s failed\n", path);
}
tail_in = NULL;
/* ... a separator footer. */
memset(buffer, '=', 79);
buffer[79] = '\0';
fprintf(out, "%s\n\n", buffer);
retval = 0;
}
return retval;
}
int dump_error_record(error_record_t er, FILE *out)
{
char path[PATH_MAX];
int lpc, retval = 0;
assert(er != NULL);
assert(error_record_invariant(er));
assert(out != NULL);
if (strcmp(er->er_agent->objtype, TBDB_OBJECTTYPE_PROGRAM) == 0) {