Commit ca06dc59 authored by Kirk Webb's avatar Kirk Webb

Add RRDtool storage/collection support to sdcollectd

The slothd collector daemon now as the ability to store statistics
in RRD files.  These files will be created under @prefix@/data/slothd_rrd
This feature is enabled by specifying "SD_USE_RRDTOOL" in the defs file.

Another companion script will be written to query these RRD files.
parent d2f219c4
......@@ -28,6 +28,11 @@ SYSTEM := $(shell uname -s)
SLOTHD_DIR = unknownclient
TBLIB = $(TESTBED_LIBOBJDIR)/libtb/libtb.a
SD_USER = nobody
SD_GROUP = nobody
SD_DATADIR = $(INSTALL_TOPDIR)/data/slothd_rrd
SD_USE_RRDTOOL = @SD_USE_RRDTOOL@
SBIN_SCRIPTS = sdisrunning sddeploy
SDPROGS = sdcollectd$(EXE) slothd$(EXE)
......@@ -42,7 +47,12 @@ CFLAGS+= -Wall -I${OBJDIR} -I/usr/local/include -I$(TESTBED_LIBSRCDIR)/libtb \
LDFLAGS+= $(LDSTATIC) -L${TESTBED_LIBOBJDIR}/libtb -L/usr/local/lib/mysql
SDLIBS+= -ltb -lmysqlclient
LIBS= $(MLIBS)
CP= cp -pf
ifeq ($(SD_USE_RRDTOOL),1)
CFLAGS+= -DUSE_RRDTOOL
LDFLAGS+= -L/usr/local/lib
SDLIBS+= -lrrd
endif
ifeq ($(findstring CYGWIN_NT,$(SYSTEM)),CYGWIN_NT)
# Cygwin on Windows XP/7
......@@ -83,6 +93,9 @@ boss-install: $(addprefix $(INSTALL_SBINDIR)/, $(SBIN_SCRIPTS) sdcollectd) webfe
$(INSTALL_PROGRAM) $(SRCDIR)/digest-slothd $(INSTALL_LIBEXECDIR)
$(INSTALL_PROGRAM) $(SRCDIR)/digest-slothd $(INSTALL_DIR)/opsdir/sbin/digest-slothd
$(INSTALL_PROGRAM) webfeedback $(INSTALL_LIBEXECDIR)
ifeq ($(SD_USE_RRDTOOL),1)
$(SUDO) $(INSTALL) -d -m 0755 -o $(SD_USER) -g $(SD_GROUP) $(SD_DATADIR)
endif
client-install: client
$(INSTALL_PROGRAM) slothd$(EXE) $(DESTDIR)$(CLIENT_BINDIR)/slothd$(EXE)
......
......@@ -39,7 +39,7 @@ void usage(void) {
printf("Usage:\tslothd -h\n"
"\tslothd [-d] [-p <port>]\n"
"\t -h\t This message.\n"
"\t -o\t DO populate old idlestats tables.\n"
"\t -s\t Populate statistics tables/files.\n"
"\t -d\t Debug mode; do not fork into background.\n"
"\t -p <port>\t Listen on port <port> (default is %d).\n",
SDCOLLECTD_PORT);
......@@ -51,16 +51,16 @@ int parse_args(int argc, char **argv) {
char ch;
/* setup defaults. */
opts->popold = 0;
opts->dostats = 0;
opts->debug = 0;
opts->port = SDCOLLECTD_PORT;
while ((ch = getopt(argc, argv, "odp:h")) != -1) {
while ((ch = getopt(argc, argv, "sdp:h")) != -1) {
switch (ch) {
case 'o':
info("Populating old node_idlestats, and iface_counters tables");
opts->popold = 1;
case 's':
info("Populating statistics tables/files");
opts->dostats = 1;
break;
case 'd':
......@@ -201,7 +201,17 @@ int main(int argc, char **argv) {
bzero(&iddata, sizeof(IDLE_DATA)); /* cleanse out old values, if any */
if (CollectData(sd, &iddata)) {
if (ParseRecord(&iddata)) {
PutDBRecord(&iddata);
if (opts->debug) {
PrintRecord(&iddata);
}
UpdateDBRecord(&iddata);
if (opts->dostats) {
#ifdef USE_RRDTOOL
PutRRDStats(&iddata);
#else
PutDBStats(&iddata);
#endif
}
}
}
}
......@@ -422,81 +432,169 @@ int ParseRecord(IDLE_DATA *iddata) {
}
void PutDBRecord(IDLE_DATA *iddata) {
void PrintRecord(IDLE_DATA *iddata) {
int i;
printf("Received and parsed packet. Contents:\n"
"Version: %u\n"
"Node: %s\n"
"Last TTY: %s"
"Load averages (1, 5, 15): %f, %f, %f\n"
"Active bits: 0x%04x\n",
iddata->version,
iddata->id,
ctime(&iddata->mis),
iddata->l1m,
iddata->l5m,
iddata->l15m,
iddata->actbits);
for (i = 0; i < iddata->ifcnt; ++i) {
printf("Interface %s: ipkts: %lu opkts: %lu\n",
iddata->ifaces[i].mac,
iddata->ifaces[i].ipkts,
iddata->ifaces[i].opkts);
}
printf("\n\n");
return;
}
void UpdateDBRecord(IDLE_DATA *iddata) {
int i;
time_t now = time(NULL);
char curstamp[100];
char tmpstr[(NUMACTTYPES+1)*sizeof(curstamp)];
char *actstr[] = ACTSTRARRAY;
sprintf(curstamp, "FROM_UNIXTIME(%lu)", (long unsigned int)now);
printf("now: %s\n", ctime(&now));
if (opts->debug) {
printf("\nReceived and parsed packet. Contents:\n"
"Version: %u\n"
"Node: %s\n"
"Last TTY: %s"
"Load averages (1, 5, 15): %f, %f, %f\n"
"Active bits: 0x%04x\n",
iddata->version,
iddata->id,
ctime(&iddata->mis),
iddata->l1m,
iddata->l5m,
iddata->l15m,
iddata->actbits);
for (i = 0; i < iddata->ifcnt; ++i) {
printf("Interface %s: ipkts: %lu opkts: %lu\n",
iddata->ifaces[i].mac,
iddata->ifaces[i].ipkts,
iddata->ifaces[i].opkts);
sprintf(curstamp, "FROM_UNIXTIME(%lu)", (long unsigned int)now);
sprintf(tmpstr, "last_report=%s", curstamp);
for (i = 0; i < NUMACTTYPES; ++i) {
if (iddata->actbits & (1<<i)) {
sprintf(tmpstr, "%s, %s=%s",
tmpstr,
actstr[i],
curstamp);
}
printf("\n\n");
}
if (opts->popold) {
if (!mydb_update("INSERT INTO node_idlestats VALUES ('%s', FROM_UNIXTIME(%lu), FROM_UNIXTIME(%lu), %f, %f, %f)",
iddata->id,
now,
iddata->mis,
iddata->l1m,
iddata->l5m,
iddata->l15m)) {
error("Error inserting data into node_idlestats table");
}
if(!mydb_update("UPDATE node_activity SET %s WHERE node_id = '%s'",
tmpstr,
iddata->id)) {
error("Error updating stamps in node_activity table");
}
return;
}
void PutDBStats(IDLE_DATA *iddata) {
int i;
time_t now = time(NULL);
char curstamp[100];
char tmpstr[(NUMACTTYPES+1)*sizeof(curstamp)];
char *actstr[] = ACTSTRARRAY;
sprintf(curstamp, "FROM_UNIXTIME(%lu)", (long unsigned int)now);
if (!mydb_update("INSERT INTO node_idlestats VALUES ('%s', FROM_UNIXTIME(%lu), FROM_UNIXTIME(%lu), %f, %f, %f)",
iddata->id,
now,
iddata->mis,
iddata->l1m,
iddata->l5m,
iddata->l15m)) {
error("Error inserting data into node_idlestats table");
}
for (i = 0; i < iddata->ifcnt; ++i) {
if (!mydb_update("INSERT INTO iface_counters VALUES ('%s', FROM_UNIXTIME(%lu), '%s', %lu, %lu)",
iddata->id,
now,
iddata->ifaces[i].mac,
iddata->ifaces[i].ipkts,
iddata->ifaces[i].opkts)) {
error("Error inserting data into iface_counters table");
}
for (i = 0; i < iddata->ifcnt; ++i) {
if (!mydb_update("INSERT INTO iface_counters VALUES ('%s', FROM_UNIXTIME(%lu), '%s', %lu, %lu)",
iddata->id,
now,
iddata->ifaces[i].mac,
iddata->ifaces[i].ipkts,
iddata->ifaces[i].opkts)) {
error("Error inserting data into iface_counters table");
}
}
if (iddata->version >= 2) {
sprintf(tmpstr, "last_report=%s", curstamp);
for (i = 0; i < NUMACTTYPES; ++i) {
if (iddata->actbits & (1<<i)) {
sprintf(tmpstr, "%s, %s=%s",
tmpstr,
actstr[i],
curstamp);
return;
}
#ifdef USE_RRDTOOL
void PutRRDStats(IDLE_DATA *iddata) {
int i;
time_t now = time(NULL);
char rrdfile[sizeof(SD_RRD_STORAGEDIR) + TBDB_FLEN_NODEID + MACADDRLEN + 7];
char updstr[100];
rrd_clear_error(); /* Precautionary */
/* Create the RRD file if it doesn't exist. */
sprintf(rrdfile, "%s/%s.rrd", SD_RRD_STORAGEDIR, iddata->id);
if (access(rrdfile, F_OK) == -1) {
if (errno == ENOENT) {
if (rrd_create_r(rrdfile,
SD_RRD_STEPSIZE,
now - 10,
sizeof(SD_RRD_NODE_LAYOUT),
SD_RRD_NODE_LAYOUT) != 0) {
error("Failed to create RRD file for node %s: %s",
iddata->id,
rrd_get_error());
return;
}
} else {
errorc("RRD file check failed for node %s", iddata->id);
return;
}
}
if(!mydb_update("UPDATE node_activity SET %s WHERE node_id = '%s'",
tmpstr,
iddata->id)) {
error("Error updating stamps in node_activity table");
}
/* Update RRD with new data. */
sprintf(updstr, "N:%lu:%f:%f:%f",
iddata->mis, iddata->l1m, iddata->l5m, iddata->l15m);
if (rrd_update_r(rrdfile, NULL, 1, &updstr) != 0) {
error("Failed to update RRD file for node: %s: %s",
iddata->id,
rrd_get_error());
return;
}
/* Now do the same for each network interface. One RRD for each iface. */
for (i = 0; i < iddata->ifcnt; i++) {
sprintf(rrdfile, "%s/%s-%s.rrd", SD_RRD_STORAGEDIR,
iddata->id, iddata->ifaces[i].mac);
if (access(rrdfile, F_OK) == -1) {
if (errno == ENOENT) {
if (rrd_create_r(rrdfile,
SD_RRD_STEPSIZE,
now - 10,
sizeof(SD_RRD_IFACE_LAYOUT),
SD_RRD_IFACE_LAYOUT) != 0) {
error("Failed to create RRD file for node/iface %s/%s: %s",
iddata->id, iddata->ifaces[i],
rrd_get_error());
return;
}
} else {
errorc("RRD file check failed for node/iface %s/%s",
iddata->id, iddata->ifaces[i]);
return;
}
}
sprintf(updstr, "N:%lu:%lu",
iddata->ifaces[i].ipkts, iddata->ifaces[i].opkts);
if (rrd_update_r(rrdfile, NULL, 1, &updstr) != 0) {
error("Failed to update RRD file for node: %s: %s",
iddata->id,
rrd_get_error());
return;
}
}
return;
}
#endif
......@@ -67,8 +67,35 @@
#define NUMACTTYPES 4
#define ACTSTRARRAY {"last_tty_act", "last_cpu_act", "last_net_act", "last_ext_act"}
#ifdef USE_RRDTOOL
#include <rrd.h>
#define SD_RRD_STORAGEDIR TBROOT "/slothd_rrd"
#define SD_RRD_STEPSIZE 300 /* five minutes. */
char *SD_RRD_NODE_LAYOUT[] = {
"DS:last_tty:DERIVE:600:0:U",
"DS:load_1min:GAUGE:600:0:U",
"DS:load_5min:GAUGE:600:0:U",
"DS:load_15min:GAUGE:600:0:U",
"RRA:MAX:0.5:5m:1d",
"RRA:AVERAGE:0.5:5m:1d",
"RRA:MAX:0.5:1h:1w",
"RRA:AVERAGE:0.5:1h:1w"
};
char *SD_RRD_IFACE_LAYOUT[] = {
"DS:ipkts:DERIVE:600:0:U",
"DS:opkts:DERIVE:600:0:U",
"RRA:MAX:0.5:5m:1d",
"RRA:AVERAGE:0.5:5m:1d",
"RRA:MAX:0.5:1h:1w",
"RRA:AVERAGE:0.5:1h:1w"
};
#endif
typedef struct {
u_char popold;
u_char dostats;
u_char debug;
u_short port;
} SDCOLLECTD_OPTS;
......@@ -96,7 +123,10 @@ extern int errno;
int CollectData(int, IDLE_DATA*);
int ParseRecord(IDLE_DATA*);
void PutDBRecord(IDLE_DATA*);
void PrintRecord(IDLE_DATA*);
void UpdateDBRecord(IDLE_DATA*);
void PutDBStats(IDLE_DATA*);
void PutRRDStats(IDLE_DATA*);
char *tbmac(char*, char**);
......
......@@ -317,6 +317,7 @@ AC_SUBST(ATTENUATOR)
AC_SUBST(CLUSTER_PORTAL)
AC_SUBST(CLUSTER_PUBSUBD_PORT)
AC_SUBST(EXPIRE_PASSWORDS)
AC_SUBST(SD_USE_RRDTOOL)
#
# Offer both versions of the email addresses that have the @ escaped
......@@ -484,6 +485,7 @@ ATTENUATOR=""
CLUSTER_PORTAL=""
CLUSTER_PUBSUBD_PORT=""
EXPIRE_PASSWORDS=1
SD_USE_RRDTOOL=0
#
# XXX You really don't want to change these!
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment