diff --git a/configure b/configure index ef3d3d9f9c7a808a238b53aba04787d62762a27c..bf13ebc77b6bbce25e9fc8ce4ebc7581c1c0d65e 100755 --- a/configure +++ b/configure @@ -1032,10 +1032,11 @@ fi if test "$enable_events" = "yes"; then - elvinfiles="event/GNUmakefile event/lib/GNUmakefile \ - event/sched/GNUmakefile event/test/GNUmakefile"; + eventfiles="event/GNUmakefile event/lib/GNUmakefile \ + event/sched/GNUmakefile event/test/GNUmakefile \ + event/tbgen/GNUmakefile event/tbgen/tbmevd.restart"; else - elvinfiles=""; + eventfiles=""; fi # @@ -1072,7 +1073,7 @@ fi # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:1076: checking for a BSD compatible install" >&5 +echo "configure:1077: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1181,7 +1182,7 @@ outfiles="$outfiles Makeconf GNUmakefile \ vis/GNUmakefile vis/vistopology vis/webvistopology vis/top2gif \ rc.d/GNUmakefile rc.d/2.mysql-server.sh rc.d/3.testbed.sh \ rc.d/cvsupd.sh \ - $elvinfiles \ + $eventfiles \ apache/GNUmakefile apache/apache.conf " # diff --git a/configure.in b/configure.in index 44281c6701753870a3e45e4ad84d9f8cb6a20fda..847c90c2d57e11a885a3191219470ba40a0454a5 100755 --- a/configure.in +++ b/configure.in @@ -177,10 +177,11 @@ AC_ARG_ENABLE(events, --disable-events Disable events (requires Elvin libraries)]) if test "$enable_events" = "yes"; then - elvinfiles="event/GNUmakefile event/lib/GNUmakefile \ - event/sched/GNUmakefile event/test/GNUmakefile"; + eventfiles="event/GNUmakefile event/lib/GNUmakefile \ + event/sched/GNUmakefile event/test/GNUmakefile \ + event/tbgen/GNUmakefile event/tbgen/tbmevd.restart"; else - elvinfiles=""; + eventfiles=""; fi # @@ -260,7 +261,7 @@ outfiles="$outfiles Makeconf GNUmakefile \ vis/GNUmakefile vis/vistopology vis/webvistopology vis/top2gif \ rc.d/GNUmakefile rc.d/2.mysql-server.sh rc.d/3.testbed.sh \ rc.d/cvsupd.sh \ - $elvinfiles \ + $eventfiles \ apache/GNUmakefile apache/apache.conf " # diff --git a/event/GNUmakefile.in b/event/GNUmakefile.in index 162712da4cd3cb256ef55a8ee12e251d5cfb0413..c744cce5bd817b91efbf9ee842edefaaf6e4c1c0 100644 --- a/event/GNUmakefile.in +++ b/event/GNUmakefile.in @@ -8,7 +8,7 @@ SUBDIR = event include $(OBJDIR)/Makeconf -SUBDIRS = lib sched test +SUBDIRS = lib sched tbgen all: $(SUBDIRS) @@ -20,19 +20,23 @@ lib: sched: @$(MAKE) -C sched all +tbgen: + @$(MAKE) -C tbgen all + test: @$(MAKE) -C test all install: @$(MAKE) -C lib install @$(MAKE) -C sched install - @$(MAKE) -C test install + @$(MAKE) -C tbgen install clean: subdir-clean subdir-clean: @$(MAKE) -C lib clean @$(MAKE) -C sched clean + @$(MAKE) -C tbgen clean @$(MAKE) -C test clean distclean: subdir-distclean diff --git a/event/lib/event.c b/event/lib/event.c index baeda0ace8f5afeddfe267de007f736673ab2c7f..cdb217fe9ea8646f84c8799199972d76ea2c0260 100644 --- a/event/lib/event.c +++ b/event/lib/event.c @@ -7,14 +7,14 @@ * @COPYRIGHT@ */ -static char rcsid[] = "$Id: event.c,v 1.11 2002-02-19 17:12:52 stoller Exp $"; - #include #include #include #include #include #include "event.h" +#undef TRACE +#define TRACE(fmt,...) static char hostname[MAXHOSTNAMELEN]; @@ -259,8 +259,6 @@ int event_schedule(event_handle_t handle, event_notification_t notification, struct timeval *time) { - event_type_t type; - if (!handle || !notification || !time) { ERROR("invalid parameter\n"); return 0; @@ -269,38 +267,12 @@ event_schedule(event_handle_t handle, event_notification_t notification, TRACE("scheduling event notification %p to be sent at time (%ld, %ld)\n", notification, time->tv_sec, time->tv_usec); - /* Change the event type to EVENT_SCHEDULE, saving the old event - type in the notification structure so the event scheduler can - change it back when the event is scheduled: */ - - if (event_notification_get_int32(handle, notification, "type", - (int *) &type) - == 0) - { - ERROR("could not get old type attribute from notification %p\n", - notification); - return 0; - } - - if (event_notification_remove(handle, notification, "type") == 0) { - ERROR("could not remove old type attribute from notification %p\n", - notification); - return 0; - } - - if (event_notification_put_int32(handle, notification, "type", - EVENT_SCHEDULE) - == 0) - { - ERROR("could not add new type attribute to notification %p\n", - notification); - return 0; - } - if (event_notification_put_int32(handle, notification, "old_type", - type) - == 0) - { - ERROR("could not add old type attribute to notification %p\n", + /* + * Add an attribute that signifies its a scheduler operation. + */ + if (! event_notification_remove(handle, notification, "SCHEDULER") || + ! event_notification_put_int32(handle, notification, "SCHEDULER", 1)) { + ERROR("could not add scheduler attribute to notification %p\n", notification); return 0; } @@ -332,25 +304,22 @@ event_schedule(event_handle_t handle, event_notification_t notification, /* - * Allocate an event notification. The HOST parameter specifies - * the hostname of the node that should receive the notification, - * or EVENT_HOST_ANY if the notification should go to all hosts. - * The TYPE parameter specifies the event type. Returns - * a pointer to an event notification structure if the operation - * is successful, 0 otherwise. + * Allocate an event notification. The address TUPLE defines who + * should receive the notification. Returns a pointer to an event + * notification structure if the operation is successful, 0 otherwise. */ event_notification_t -event_notification_alloc(event_handle_t handle, char *host, event_type_t type) +event_notification_alloc(event_handle_t handle, address_tuple_t tuple) { elvin_notification_t notification; - if (!handle || !host || !type) { + if (!handle || !tuple) { ERROR("invalid paramater\n"); return NULL; } - TRACE("allocating notification (host=\"%s\", type=%d)\n", host, type); + TRACE("allocating notification (tuple=%p)\n", tuple); notification = elvin_notification_alloc(handle->status); if (notification == NULL) { @@ -360,22 +329,23 @@ event_notification_alloc(event_handle_t handle, char *host, event_type_t type) } TRACE("allocated notification %p\n", notification); - - /* Add hostname to notification: */ - if (event_notification_put_string(handle, notification, "host", host) - == 0) - { - ERROR("could not add host attribute to notification %p\n", - notification); - return NULL; - } - - /* Add type to notification: */ - if (event_notification_put_int32(handle, notification, "type", type) - == 0) - { - ERROR("could not add type attribute to notification %p\n", - notification); +#define EVPUT(name, field) \ +({ \ + char *foo = (tuple->field ? tuple->field : ADDRESSTUPLE_ALL); \ + \ + event_notification_put_string(handle, notification, name, foo); \ +}) + + /* Add the target address stuff to the notification */ + if (!EVPUT("SITE", site) || + !EVPUT("EXPT", expt) || + !EVPUT("GROUP", group) || + !EVPUT("HOST", host) || + !EVPUT("OBJTYPE", objtype) || + !EVPUT("OBJNAME", objname) || + !EVPUT("EVENTTYPE", eventtype) || + ! event_notification_put_int32(handle, notification, "SCHEDULER", 0)) { + ERROR("could not add attributes to notification %p\n", notification); return NULL; } @@ -818,38 +788,77 @@ static void notify_callback(elvin_handle_t server, * * void callback(event_handle_t handle, * event_notification_t notification, - * char *host, - * event_type_t type, * void *data); * * where HANDLE is the handle to the event server, NOTIFICATION is the - * event notification, HOST and TYPE are the respective attributes of - * the event notification, and DATA is the arbitrary pointer passed to + * event notification, and DATA is the arbitrary pointer passed to * event_subscribe. Returns a pointer to an event * subscription structure if the operation is successful, 0 otherwise. */ event_subscription_t event_subscribe(event_handle_t handle, event_notify_callback_t callback, - event_type_t type, void *data) + address_tuple_t tuple, void *data) { elvin_subscription_t subscription; struct notify_callback_arg *arg; char expression[EXPRESSION_LENGTH]; + int index = 0; /* XXX: The declaration of expression has to go last, or the local variables on the stack after it get smashed. Check Elvin for buffer overruns. */ - if (!handle || !callback || !type) { + if (!handle || !callback || !tuple) { ERROR("invalid parameter\n"); return NULL; } - snprintf(expression, EXPRESSION_LENGTH, - "(host == \"*\" || host == \"%s\") && type == %d", - hostname, - type); + if (tuple->site) { + index += snprintf(&expression[index], sizeof(expression) - index, + "SITE == \"%s\" ", + tuple->site); + } + if (tuple->expt) { + index += snprintf(&expression[index], sizeof(expression) - index, + "%s EXPT == \"%s\" ", + (index ? "&&" : ""), + tuple->expt); + } + if (tuple->group) { + index += snprintf(&expression[index], sizeof(expression) - index, + "%s GROUP == \"%s\" ", + (index ? "&&" : ""), + tuple->group); + } + if (tuple->host) { + index += snprintf(&expression[index], sizeof(expression) - index, + "%s HOST == \"%s\" ", + (index ? "&&" : ""), + tuple->host); + } + if (tuple->objtype) { + index += snprintf(&expression[index], sizeof(expression) - index, + "%s OBJTYPE == \"%s\" ", + (index ? "&&" : ""), + tuple->objtype); + } + if (tuple->objname) { + index += snprintf(&expression[index], sizeof(expression) - index, + "%s OBJNAME == \"%s\" ", + (index ? "&&" : ""), + tuple->objname); + } + if (tuple->eventtype) { + index += snprintf(&expression[index], sizeof(expression) - index, + "%s EVENTTYPE == \"%s\" ", + (index ? "&&" : ""), + tuple->eventtype); + } + index += snprintf(&expression[index], sizeof(expression) - index, + "%s SCHEDULER == %d ", + (index ? "&&" : ""), + tuple->scheduler); TRACE("subscribing to event %s\n", expression); @@ -910,8 +919,6 @@ notify_callback(elvin_handle_t server, struct notify_callback_arg *arg = (struct notify_callback_arg *) rock; event_notify_callback_t callback; void *data; - char host[MAXHOSTNAMELEN]; - event_type_t type; TRACE("received event notification\n"); @@ -921,23 +928,25 @@ notify_callback(elvin_handle_t server, handle.server = server; handle.status = status; - if (event_notification_get_string(&handle, notification, "host", - host, MAXHOSTNAMELEN) - == 0) - { - ERROR("could not get host attribute from notification %p\n", - notification); - return; - } + callback(&handle, notification, data); +} - if (event_notification_get_int32(&handle, notification, "type", - (int *) &type) - == 0) - { - ERROR("could not get type attribute from notification %p\n", - notification); - return; - } +/* + * address tuple alloc and free. + */ +address_tuple_t +address_tuple_alloc(void) +{ + address_tuple_t tuple = xmalloc(sizeof(address_tuple)); + + bzero(tuple, sizeof(address_tuple)); + + return tuple; +} - callback(&handle, notification, host, type, data); +int +address_tuple_free(address_tuple_t tuple) +{ + free(tuple); + return 1; } diff --git a/event/lib/event.h b/event/lib/event.h index 965e9b2b31b86f31a7436d30a1b754883aaca444..daf518be4d307f17f2218d700c5898bca7667feb 100644 --- a/event/lib/event.h +++ b/event/lib/event.h @@ -5,7 +5,7 @@ * * @COPYRIGHT@ * - * $Id: event.h,v 1.6 2002-02-19 15:45:24 imurdock Exp $ + * $Id: event.h,v 1.7 2002-02-21 17:49:38 stoller Exp $ */ #ifndef __EVENT_H__ @@ -44,6 +44,43 @@ typedef elvin_notification_t event_notification_t; /* Event subscription: */ typedef elvin_subscription_t event_subscription_t; +/* + * A tuple defines the target of the event, or if you are a subscriber, + * what events you want to subscribe to. + */ +typedef struct { + char *site; /* Which Emulab site. God only */ + char *expt; /* Project and experiment IDs */ + char *group; /* User defined group of nodes */ + char *host; /* A specific host */ + char *objtype; /* LINK, TRAFGEN, etc ... */ + char *objname; /* link0, cbr0, cbr1, etc ... */ + char *eventtype; /* START, STOP, UP, DOWN, etc ... */ + int scheduler; /* A dynamic event to schedule */ +} address_tuple, *address_tuple_t; +#define ADDRESSTUPLE_ANY NULL +#define ADDRESSTUPLE_ALL "*" +#define OBJECTTYPE_TESTBED "TBCONTROL" + +address_tuple_t address_tuple_alloc(void); +int address_tuple_free(address_tuple_t); + +#define event_notification_get_site(handle, note, buf, len) \ + event_notification_get_string(handle, note, "SITE", buf, len) +#define event_notification_get_expt(handle, note, buf, len) \ + event_notification_get_string(handle, note, "EXPT", buf, len) +#define event_notification_get_group(handle, note, buf, len) \ + event_notification_get_string(handle, note, "GROUP", buf, len) +#define event_notification_get_host(handle, note, buf, len) \ + event_notification_get_string(handle, note, "HOST", buf, len) +#define event_notification_get_objtype(handle, note, buf, len) \ + event_notification_get_string(handle, note, "OBJTYPE", buf, len) +#define event_notification_get_objname(handle, note, buf, len) \ + event_notification_get_string(handle, note, "OBJNAME", buf, len) +#define event_notification_get_eventtype(handle, note, buf, len) \ + event_notification_get_string(handle, note, "EVENTTYPE", buf, len) + + /* The "any host" string: */ #define EVENT_HOST_ANY "*" @@ -60,11 +97,10 @@ typedef enum { and called whenever the specified event is triggered. HANDLE is the handle to the event server, NOTIFICATION is the event notification itself, and DATA is an arbitrary value passed to - event_subscribe (argument 4). HOST and TYPE are attributes from the - event notification. */ + event_subscribe (argument 4). + */ typedef void (*event_notify_callback_t)(event_handle_t handle, event_notification_t notification, - char *host, event_type_t type, void *data); /* @@ -74,8 +110,10 @@ typedef void (*event_notify_callback_t)(event_handle_t handle, #define ERROR(fmt,...) fprintf(stderr, __FUNCTION__ ": " fmt, ## __VA_ARGS__) #ifdef DEBUG #define TRACE(fmt,...) printf(__FUNCTION__ ": " fmt, ## __VA_ARGS__) +#define DBG(fmt,...) printf(fmt, ## __VA_ARGS__) #else #define TRACE(fmt,...) +#define DBG(fmt,...) #endif /* DEBUG */ /* @@ -90,7 +128,7 @@ int event_notify(event_handle_t handle, event_notification_t notification); int event_schedule(event_handle_t handle, event_notification_t notification, struct timeval *time); event_notification_t event_notification_alloc(event_handle_t handle, - char *host, event_type_t type); + address_tuple_t tuple); int event_notification_free(event_handle_t handle, event_notification_t notification); int event_notification_get_double(event_handle_t handle, @@ -127,7 +165,7 @@ int event_notification_remove(event_handle_t handle, event_notification_t notification, char *name); event_subscription_t event_subscribe(event_handle_t handle, event_notify_callback_t callback, - event_type_t type, void *data); + address_tuple_t tuple, void *data); /* util.c */ void *xmalloc(int size); diff --git a/event/sched/GNUmakefile.in b/event/sched/GNUmakefile.in index ff546ad8c3d907cab9474cc09f2399f6cb9f02f1..fc29aace70eee34ff52d24075ec0303fda93989d 100644 --- a/event/sched/GNUmakefile.in +++ b/event/sched/GNUmakefile.in @@ -9,19 +9,19 @@ all: event-sched include $(TESTBED_SRCDIR)/GNUmakerules -CFLAGS += -O -g -static -I. -I$(SRCDIR)/../lib -Wall -pthread -DDEBUG +CFLAGS += -O -g -I. -I${OBJDIR} -I$(SRCDIR)/../lib -Wall -pthread -DDEBUG CFLAGS += `elvin-config --cflags vin4mt` -LDFLAGS += -pthread -L../lib -LIBS += -levent -lcipher +LDFLAGS += -pthread -L../lib +LIBS += -levent -lcipher -L/usr/local/lib/mysql -lmysqlclient LIBS += `elvin-config --libs vin4mt` -OBJS = event-sched.o queue.o +OBJS = event-sched.o queue.o libdb.o event-sched: $(OBJS) $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) -$(OBJS): event-sched.h +$(OBJS): event-sched.h ../lib/libevent.a clean: /bin/rm -f *.o event-sched diff --git a/event/sched/event-sched.c b/event/sched/event-sched.c index bc4593a2ee02d20163c8a7b214ff1d88b19f777a..859dcaa68e0ef73023f67a5b40e6828ed84fbdb9 100644 --- a/event/sched/event-sched.c +++ b/event/sched/event-sched.c @@ -16,32 +16,79 @@ #include #include #include +#include +#include #include "event-sched.h" +#include "libdb.h" -static void enqueue(event_handle_t handle, event_notification_t notification, - char *host, event_type_t type, void *data); +static void enqueue(event_handle_t handle, + event_notification_t notification, void *data); static void dequeue(event_handle_t handle); +static char *progname; +static char *pid, *eid; +static int get_static_events(event_handle_t handle); + +void +usage() +{ + fprintf(stderr, "Usage: %s [-s server] [-p port] \n", + progname); + exit(-1); +} + int main(int argc, char **argv) { + address_tuple_t tuple; event_handle_t handle; char *server = NULL; + char *port = NULL; + char buf[BUFSIZ]; int c; /* Initialize event queue semaphores: */ sched_event_init(); - while ((c = getopt(argc, argv, "s:")) != -1) { + while ((c = getopt(argc, argv, "s:p:")) != -1) { switch (c) { case 's': server = optarg; break; + case 'p': + port = optarg; + break; default: fprintf(stderr, "Usage: %s [-s SERVER]\n", argv[0]); return 1; } } + argc -= optind; + argv += optind; + + if (argc != 2) + usage(); + pid = argv[0]; + eid = argv[1]; + + /* + * Set up DB state. + */ + if (!dbinit()) + return 1; + + /* + * Convert server/port to elvin thing. + * + * XXX This elvin string stuff should be moved down a layer. + */ + if (server) { + snprintf(buf, sizeof(buf), "elvin://%s%s%s", + server, + (port ? ":" : ""), + (port ? port : "")); + server = buf; + } /* Register with the event system: */ handle = event_register(server, 1); @@ -50,9 +97,26 @@ main(int argc, char **argv) return 1; } - /* Subscribe to the EVENT_SCHEDULE event, and enqueue events as - they arrive: */ - if (event_subscribe(handle, enqueue, EVENT_SCHEDULE, NULL) == NULL) { + /* + * Read the static events list and schedule. + */ + if (!get_static_events(handle)) { + ERROR("could not get static event list\n"); + return 1; + } + + /* + * Construct an address tuple for event subscription. We set the scheduler + * flag to indicate we want to capture those notifications. + */ + tuple = address_tuple_alloc(); + if (tuple == NULL) { + ERROR("could not allocate an address tuple\n"); + return 1; + } + tuple->scheduler = 1; + + if (event_subscribe(handle, enqueue, tuple, NULL) == NULL) { ERROR("could not subscribe to EVENT_SCHEDULE event\n"); return 1; } @@ -71,11 +135,9 @@ main(int argc, char **argv) /* Enqueue event notifications as they arrive. */ static void -enqueue(event_handle_t handle, event_notification_t notification, char *host, - event_type_t type, void *data) +enqueue(event_handle_t handle, event_notification_t notification, void *data) { sched_event_t event; - event_type_t old_type; /* Clone the event notification, since we want the notification to live beyond the callback function: */ @@ -87,28 +149,11 @@ enqueue(event_handle_t handle, event_notification_t notification, char *host, return; } - /* Restore the original event type: */ - - if (event_notification_get_int32(handle, event.notification, "old_type", - (int *) &old_type) - == 0) - { - ERROR("could not restore type attribute of notification %p\n", - event.notification); - return; - } - - if (event_notification_remove(handle, event.notification, "type") == 0) { - ERROR("could not restore type attribute of notification %p\n", - event.notification); - return; - } - - if (event_notification_put_int32(handle, event.notification, "type", - old_type) - == 0) - { - ERROR("could not restore type attribute of notification %p\n", + /* Clear the scheduler flag */ + if (! event_notification_remove(handle, event.notification, "SCHEDULER") || + ! event_notification_put_int32(handle, + event.notification, "SCHEDULER", 0)) { + ERROR("could not clear scheduler attribute of notification %p\n", event.notification); return; } @@ -163,17 +208,23 @@ dequeue(event_handle_t handle) { sched_event_t next_event; struct timeval next_event_wait, now; + int foo; while (sched_event_dequeue(&next_event, 1) != 0) { /* Determine how long to wait before firing the next event. */ + again: next_event_wait = sched_time_until_event_fires(next_event); /* If the event's firing time is in the future, then use select to wait until the event should fire. */ if (next_event_wait.tv_sec >= 0 && next_event_wait.tv_usec > 0) { - if (select(0, NULL, NULL, NULL, &next_event_wait) != 0) { - ERROR("select did not timeout\n"); - return; + if ((foo = select(0, NULL, NULL, NULL, &next_event_wait)) != 0) { + /* + * I'll assume that this fails cause of a pthread + * related signal issue. + */ + ERROR("select did not timeout %d %d\n", foo, errno); + goto again; } } @@ -198,3 +249,106 @@ dequeue(event_handle_t handle) event_notification_free(handle, next_event.notification); } } + +/* + * Get the static event list from the DB and schedule according to + * the relative time stamps. + */ +static int +get_static_events(event_handle_t handle) +{ + MYSQL_RES *res; + MYSQL_ROW row; + int nrows; + struct timeval now, time; + address_tuple_t tuple; + char pideid[BUFSIZ]; + + res = mydb_query("select ex.time,ex.vnode,ex.vname,ex.arguments," + " ot.type,et.type,i.IP from %s_%s_events as ex " + "left join event_eventtypes as et on " + " ex.eventtype=et.idx " + "left join event_objecttypes as ot on " + " ex.objecttype=ot.idx " + "left join reserved as r on " + " ex.vnode=r.vname and r.pid='%s' and r.eid='%s' " + "left join nodes as n on r.node_id=n.node_id " + "left join node_types as nt on nt.type=n.type " + "left join interfaces as i on " + " i.node_id=r.node_id and i.iface=nt.control_iface", + 7, pid, eid, pid, eid); +#define EXTIME row[0] +#define EXVNODE row[1] +#define EXVNAME row[2] +#define EXARGS row[3] +#define OBJTYPE row[4] +#define EVTTYPE row[5] +#define IPADDR row[6] + + if (!res) { + ERROR("getting static event list for %s/%s", pid, eid); + return 0; + } + + if ((nrows = (int)mysql_num_rows(res)) == 0) { + mysql_free_result(res); + return 1; + } + + /* + * Construct an address tuple for the notifications. We can reuse + * the same one over and over since the data is copied out. + */ + tuple = address_tuple_alloc(); + if (tuple == NULL) { + ERROR("could not allocate an address tuple\n"); + return 1; + } + + sprintf(pideid, "%s/%s", pid, eid); + gettimeofday(&now, NULL); + + while (nrows) { + sched_event_t event; + double firetime; + + row = mysql_fetch_row(res); + firetime = atof(EXTIME); + + DBG("EV: %8s %10s %10s %10s %10s %10s %10s\n", + row[0], row[1], row[2], + row[3] ? row[3] : "", + row[4], row[5], + row[6] ? row[6] : ""); + + + tuple->expt = pideid; + tuple->host = IPADDR; + tuple->objname = EXVNAME; + tuple->objtype = OBJTYPE; + tuple->eventtype = EVTTYPE; + + event.notification = event_notification_alloc(handle, tuple); + if (! event.notification) { + ERROR("could not allocate notification\n"); + mysql_free_result(res); + return 1; + } + + time.tv_sec = now.tv_sec + (int)firetime; + time.tv_usec = now.tv_usec + + (int)((firetime - (floor(firetime))) * 1000000); + + if (time.tv_usec >= 1000000) { + time.tv_sec += 1; + time.tv_usec -= 1000000; + } + event.time.tv_sec = time.tv_sec; + event.time.tv_usec = time.tv_usec; + sched_event_enqueue(event); + nrows--; + } + mysql_free_result(res); + return 1; +} + diff --git a/event/sched/libdb.c b/event/sched/libdb.c new file mode 100644 index 0000000000000000000000000000000000000000..9bb57db21b65419d92a68a9461d2410eabc6305e --- /dev/null +++ b/event/sched/libdb.c @@ -0,0 +1,93 @@ +/* + * DB interface. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "event-sched.h" +#include "libdb.h" +#include "config.h" + +/* + * DB stuff + */ +static MYSQL db; +static char *dbname = TBDBNAME; + +int +dbinit(void) +{ + mysql_init(&db); + if (mysql_real_connect(&db, 0, 0, 0, + dbname, 0, 0, CLIENT_INTERACTIVE) == 0) { + ERROR("%s: connect failed: %s", dbname, mysql_error(&db)); + return 0; + } + return 1; +} + +MYSQL_RES * +mydb_query(char *query, int ncols, ...) +{ + MYSQL_RES *res; + char querybuf[2*BUFSIZ]; + va_list ap; + int n; + + va_start(ap, ncols); + n = vsnprintf(querybuf, sizeof(querybuf), query, ap); + if (n > sizeof(querybuf)) { + ERROR("query too long for buffer"); + return (MYSQL_RES *) 0; + } + + if (mysql_real_query(&db, querybuf, n) != 0) { + ERROR("%s: query failed: %s", dbname, mysql_error(&db)); + return (MYSQL_RES *) 0; + } + + res = mysql_store_result(&db); + if (res == 0) { + ERROR("%s: store_result failed: %s", dbname, mysql_error(&db)); + return (MYSQL_RES *) 0; + } + + if (ncols && ncols != (int)mysql_num_fields(res)) { + ERROR("%s: Wrong number of fields returned " + "Wanted %d, Got %d", + dbname, ncols, (int)mysql_num_fields(res)); + mysql_free_result(res); + return (MYSQL_RES *) 0; + } + return res; +} + +int +mydb_update(char *query, ...) +{ + char querybuf[2*BUFSIZ]; + va_list ap; + int n; + + va_start(ap, query); + n = vsnprintf(querybuf, sizeof(querybuf), query, ap); + if (n > sizeof(querybuf)) { + ERROR("query too long for buffer"); + return 1; + } + if (mysql_real_query(&db, querybuf, n) != 0) { + ERROR("%s: query failed: %s", dbname, mysql_error(&db)); + return 1; + } + return 0; +} + diff --git a/event/sched/libdb.h b/event/sched/libdb.h new file mode 100644 index 0000000000000000000000000000000000000000..024d28bab275469b7de6dfd40db0fc83a0fc6e15 --- /dev/null +++ b/event/sched/libdb.h @@ -0,0 +1,16 @@ +/* + * Testbed DB interface and support. + */ +#include +#include + +/* + * Generic interface. + */ +int dbinit(void); + +/* + * mysql specific routines. + */ +MYSQL_RES *mydb_query(char *query, int ncols, ...); +int mydb_update(char *query, ...); diff --git a/event/tbgen/GNUmakefile.in b/event/tbgen/GNUmakefile.in new file mode 100644 index 0000000000000000000000000000000000000000..039005c4ff4964079f99ec753274ef48848ae8ce --- /dev/null +++ b/event/tbgen/GNUmakefile.in @@ -0,0 +1,46 @@ +SRCDIR = @srcdir@ +TESTBED_SRCDIR = @top_srcdir@ +OBJDIR = ../.. +SUBDIR = event/tbgen + +PROGRAMS = tbmevc tbmevd sample-client tbmevd.restart + +include $(OBJDIR)/Makeconf + +all: $(PROGRAMS) + +include $(TESTBED_SRCDIR)/GNUmakerules + +CFLAGS += -O -g -static -I. -I$(SRCDIR)/../lib -Wall -pthread -DDEBUG +CFLAGS += `elvin-config --cflags vin4mt` + +LDFLAGS += -static -pthread -L../lib +LIBS += -levent -lcipher -lc_r + +# +# 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 -lvin4mt -lvin4c -lvin4 -lssl -lcrypto -lm + +tbmevc: tbmevc.o + $(CC) $(LDFLAGS) -o $@ tbmevc.o $(LIBS) + +tbmevd: tbmevd.o + $(CC) $(LDFLAGS) -o $@ tbmevd.o $(LIBS) + +sample-client: sample-client.o + $(CC) $(LDFLAGS) -o $@ sample-client.o $(LIBS) + +$(PROGRAMS): ../lib/libevent.a ../lib/event.h + +install: $(INSTALL_SBINDIR)/tbmevd \ + $(INSTALL_SBINDIR)/tbmevd.restart + +client-install: + $(INSTALL_PROGRAM) tbmevc /etc/testbed/tbmevc + +clean: + /bin/rm -f *.o $(PROGRAMS) diff --git a/event/tbgen/sample-client.c b/event/tbgen/sample-client.c new file mode 100644 index 0000000000000000000000000000000000000000..8c3f2cecdd7f7ec85ef7d4d20bf3c8f24b6c0ca9 --- /dev/null +++ b/event/tbgen/sample-client.c @@ -0,0 +1,170 @@ +/* + * This is a sample client to run on a testbed node to capture all + * testbed events for the node. Modify as needed of course. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "event.h" + +static char *progname; + +static void +callback(event_handle_t handle, + event_notification_t notification, void *data); + +void +usage() +{ + fprintf(stderr, + "Usage: %s [-s server] [-p port]\n", progname); + exit(-1); +} + +int +main(int argc, char **argv) +{ + event_handle_t handle; + address_tuple_t tuple; + char *server = NULL; + char *port = NULL; + char *ipaddr = NULL; + char buf[BUFSIZ], ipbuf[BUFSIZ]; + int c; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "s:p:i:")) != -1) { + switch (c) { + case 's': + server = optarg; + break; + case 'p': + port = optarg; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + /* + * Get our IP address. Thats how we name ourselves to the + * Testbed Event System. + */ + if (ipaddr == NULL) { + struct hostent *he; + struct in_addr myip; + + if (gethostname(buf, sizeof(buf)) < 0) { + ERROR("could not get hostname\n"); + return 1; + } + + if (! (he = gethostbyname(buf))) { + ERROR("could not get IP address from hostname\n"); + return 1; + } + memcpy((char *)&myip, he->h_addr, he->h_length); + strcpy(ipbuf, inet_ntoa(myip)); + ipaddr = ipbuf; + } + + /* + * Convert server/port to elvin thing. + * + * XXX This elvin string stuff should be moved down a layer. + */ + if (server) { + snprintf(buf, sizeof(buf), "elvin://%s%s%s", + server, + (port ? ":" : ""), + (port ? port : "")); + server = buf; + } + + /* + * Construct an address tuple for subscribing to events for + * this node. + */ + tuple = address_tuple_alloc(); + if (tuple == NULL) { + ERROR("could not allocate an address tuple\n"); + return 1; + } + /* + * Change this stuff as needed. + */ + tuple->host = ipaddr; + tuple->site = ADDRESSTUPLE_ANY; + tuple->group = ADDRESSTUPLE_ANY; + tuple->expt = ADDRESSTUPLE_ANY; /* pid/eid */ + tuple->objtype = ADDRESSTUPLE_ANY; + tuple->objname = ADDRESSTUPLE_ANY; + tuple->eventtype = ADDRESSTUPLE_ANY; + + /* + * Register with the event system. + */ + handle = event_register(server, 0); + if (handle == NULL) { + ERROR("could not register with event system\n"); + return 1; + } + + /* + * Subscribe to the event we specified above. + */ + if (! event_subscribe(handle, callback, tuple, NULL)) { + ERROR("could not subscribe to event\n"); + return 1; + } + + /* + * Begin the event loop, waiting to receive event notifications: + */ + event_main(handle); + + /* + * Unregister with the event system: + */ + if (event_unregister(handle) == 0) { + ERROR("could not unregister with event system\n"); + return 1; + } + + return 0; +} + +/* + * Handle Testbed Control events. + */ +static void +callback(event_handle_t handle, event_notification_t notification, void *data) +{ + char buf[7][64]; + int len = 64; + struct timeval now; + + gettimeofday(&now, NULL); + + event_notification_get_site(handle, notification, buf[0], len); + event_notification_get_expt(handle, notification, buf[1], len); + event_notification_get_group(handle, notification, buf[2], len); + event_notification_get_host(handle, notification, buf[3], len); + event_notification_get_objtype(handle, notification, buf[4], len); + event_notification_get_objname(handle, notification, buf[5], len); + event_notification_get_eventtype(handle, notification, buf[6], len); + + printf("Event: %lu %s %s %s %s %s %s %s\n", now.tv_sec, + buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], buf[6]); +} diff --git a/event/tbgen/tbmevc.c b/event/tbgen/tbmevc.c new file mode 100644 index 0000000000000000000000000000000000000000..851741bfd8a223b47c8c636894262d4ede8fb6e9 --- /dev/null +++ b/event/tbgen/tbmevc.c @@ -0,0 +1,150 @@ +/* + * This is used to send Testbed events (reboot, ready, etc.) to the + * testbed event client. It is intended to be wrapped up by a perl + * script that will use the tmcc to figure out where the event server + * lives (host/port) to construct the server string. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "event.h" + +static char *progname; + +void +usage() +{ + fprintf(stderr, + "Usage: %s [-s server] [-p port] [-i ipaddr] \n", + progname); + exit(-1); +} + +int +main(int argc, char **argv) +{ + event_handle_t handle; + event_notification_t notification; + address_tuple_t tuple; + char *server = NULL; + char *port = NULL; + char *ipaddr = NULL; + char buf[BUFSIZ], ipbuf[BUFSIZ], *bp; + int c; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "s:p:i:")) != -1) { + switch (c) { + case 's': + server = optarg; + break; + case 'p': + port = optarg; + break; + case 'i': + ipaddr = optarg; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc != 1) + usage(); + + /* + * Uppercase event tags for now. Should be wired in list instead. + */ + bp = argv[0]; + while (*bp) { + *bp = toupper(*bp); + bp++; + } + + /* + * Get our IP address. Thats how we name ourselves to the + * Testbed Event System. + */ + if (ipaddr == NULL) { + struct hostent *he; + struct in_addr myip; + + if (gethostname(buf, sizeof(buf)) < 0) { + ERROR("could not get hostname\n"); + return 1; + } + + if (! (he = gethostbyname(buf))) { + ERROR("could not get IP address from hostname\n"); + return 1; + } + memcpy((char *)&myip, he->h_addr, he->h_length); + strcpy(ipbuf, inet_ntoa(myip)); + ipaddr = ipbuf; + } + + /* + * Convert server/port to elvin thing. + * + * XXX This elvin string stuff should be moved down a layer. + */ + if (server) { + snprintf(buf, sizeof(buf), "elvin://%s%s%s", + server, + (port ? ":" : ""), + (port ? port : "")); + server = buf; + } + + /* + * Construct an address tuple for generating the event. + */ + tuple = address_tuple_alloc(); + if (tuple == NULL) { + ERROR("could not allocate an address tuple\n"); + return 1; + } + tuple->objtype = OBJECTTYPE_TESTBED; + tuple->objname = argv[0]; + tuple->host = ipaddr; + + /* Register with the event system: */ + handle = event_register(server, 0); + if (handle == NULL) { + ERROR("could not register with event system\n"); + return 1; + } + + /* Generate the event */ + notification = event_notification_alloc(handle, tuple); + + if (notification == NULL) { + ERROR("could not allocate notification\n"); + return 1; + } + + if (event_notify(handle, notification) == 0) { + ERROR("could not send test event notification\n"); + return 1; + } + + event_notification_free(handle, notification); + + /* Unregister with the event system: */ + if (event_unregister(handle) == 0) { + ERROR("could not unregister with event system\n"); + return 1; + } + + return 0; +} diff --git a/event/tbgen/tbmevd.c b/event/tbgen/tbmevd.c new file mode 100644 index 0000000000000000000000000000000000000000..513809f9e6e1b4e3be69dd3457ffde0f04ae07d5 --- /dev/null +++ b/event/tbgen/tbmevd.c @@ -0,0 +1,125 @@ +/* + * This is used to send Testbed Control Event Daemon. Its purpose + * is to handle TBCONTROL events. + * + * TODO: Needs to be daemonized. + */ + +#include +#include +#include +#include "event.h" + +static char *progname; + +void +usage() +{ + fprintf(stderr, "Usage: %s [-s server] [-p port]\n", + progname); + exit(-1); +} + +static void +callback(event_handle_t handle, + event_notification_t notification, void *data); + +int +main(int argc, char **argv) +{ + event_handle_t handle; + address_tuple_t tuple; + char *server = NULL; + char *port = NULL; + char buf[BUFSIZ]; + int c; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "s:p:")) != -1) { + switch (c) { + case 's': + server = optarg; + break; + case 'p': + port = optarg; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + /* + * Convert server/port to elvin thing. + * + * XXX This elvin string stuff should be moved down a layer. + */ + if (server) { + snprintf(buf, sizeof(buf), "elvin://%s%s%s", + server, + (port ? ":" : ""), + (port ? port : "")); + server = buf; + } + + /* + * Construct an address tuple for generating the event. + */ + tuple = address_tuple_alloc(); + if (tuple == NULL) { + ERROR("could not allocate an address tuple\n"); + return 1; + } + tuple->objtype = OBJECTTYPE_TESTBED; + + /* Register with the event system: */ + handle = event_register(server, 0); + if (handle == NULL) { + ERROR("could not register with event system\n"); + return 1; + } + + /* Subscribe to the test event: */ + if (! event_subscribe(handle, callback, tuple, "event received")) { + ERROR("could not subscribe to event\n"); + return 1; + } + + /* Begin the event loop, waiting to receive event notifications: */ + event_main(handle); + + /* Unregister with the event system: */ + if (event_unregister(handle) == 0) { + ERROR("could not unregister with event system\n"); + return 1; + } + + return 0; +} + +/* + * Handle Testbed Control events. + */ +static void +callback(event_handle_t handle, event_notification_t notification, void *data) +{ + char buf[7][64]; + int len = 64; + struct timeval now; + + gettimeofday(&now, NULL); + + event_notification_get_site(handle, notification, buf[0], len); + event_notification_get_expt(handle, notification, buf[1], len); + event_notification_get_group(handle, notification, buf[2], len); + event_notification_get_host(handle, notification, buf[3], len); + event_notification_get_objtype(handle, notification, buf[4], len); + event_notification_get_objname(handle, notification, buf[5], len); + event_notification_get_eventtype(handle, notification, buf[6], len); + + printf("Event: %lu %s %s %s %s %s %s %s\n", now.tv_sec, + buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], buf[6]); +} diff --git a/event/tbgen/tbmevd.restart.in b/event/tbgen/tbmevd.restart.in new file mode 100644 index 0000000000000000000000000000000000000000..abaa446ab4354a8a9a85d1df0ddd772a702afc13 --- /dev/null +++ b/event/tbgen/tbmevd.restart.in @@ -0,0 +1,7 @@ +#!/bin/csh + +TBDIR=@prefix@ + +killall tbevd +exec ${TBDIR}/sbin/tbevd >>& $TBDIR/log/tbevd.log +