diff --git a/src/lyskom/Makefile b/src/lyskom/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0255c75f341765d780bd03cd8e81b9c5d80bc71c --- /dev/null +++ b/src/lyskom/Makefile @@ -0,0 +1,26 @@ +# Makefile for lyskom Nagios utilities + +COBJS=lyskom.o buffer.o + +CFLAGS=-g -O + +boo: + @echo "Enter 'make linux' or 'make solaris'" + +linux: + $(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS)" all + +solaris: + $(MAKE) LIBS="-lnsl -lsocket" CC="$(CC)" CFLAGS="$(CFLAGS)" all + + +all: notify_lyskom check_lyskom + +notify_lyskom: notify_lyskom.o $(COBJS) + $(CC) -o notify_lyskom notify_lyskom.o $(COBJS) $(LIBS) + +check_lyskom: check_lyskom.o $(COBJS) + $(CC) -o check_lyskom check_lyskom.o $(COBJS) $(LIBS) -lm + +distclean clean: + -rm -f core notify_lyskom check_lyskom *.o *~ \#* diff --git a/src/lyskom/README b/src/lyskom/README new file mode 100644 index 0000000000000000000000000000000000000000..8157481e37bfed5c2812cd1cc9e5655fe8a1a434 --- /dev/null +++ b/src/lyskom/README @@ -0,0 +1,43 @@ +Author: Peter Eriksson <pen@lysator.liu.se> + +This directory contains two tools - + +notify_lyskom + Can be used to send notification (alerts or write messages) to LysKOM + +check_lyskom + Test that the LysKOM server is running smoothly (checks time, login capability, + number of connected clients, and number of clients in the run queue) + + +=== BUILD INSTRUCTIONS === + +Possibly modify the Makefile, then "make solaris" or "make linux" + + +=== INSTALL INSTRUCTIONS === + + +NAGIOS misccommands.cfg sample below. + +Replace LYSKOMSERVERIP, LYSKOMUSERID and SECRETPASSWORD. + +Note: +LYSKOMSERVERIP must be an *IP* address, not a hostname. +LYSKOMUSERID must be a numerical user id - not a text string. + + +define command { + command_name notify-by-lyskom + + command_line /usr/bin/printf "%b" "***** Nagios *****\n\nNotification Type: $NOTIFICATIONTYPE$\n\nService: $SERVICEDESC$\nHost: $HOSTNAME$ ($HOSTALIAS$)\nAddress: $HOSTADDRESS$\nState: $SERVICESTATE$\n\nDate/Time: $LONGDATETIME$\n\nAdditional Info:\n\n$SERVICEOUTPUT$" | /ifm/bin/lyskom_notify -HLYSKOMSERVERIP -uLYSKOMUSERID -pSECRETPASSWORD -s"** $NOTIFICATIONTYPE$ alert - $SERVICEDESC$@$HOSTNAME$ is $SERVICESTATE$ **" $CONTACTEMAIL$ + +} + + +define command { + command_name host-notify-by-lyskom + + command_line /usr/bin/printf "%b" "***** Nagios *****\n\nNotification Type: $NOTIFICATIONTYPE$\nState: $HOSTSTATE$\nHost: $HOSTNAME$ ($HOSTALIAS$)\nAddress: $HOSTADDRESS$\nInfo: $SERVICEOUTPUT$\n\nDate/Time: $LONGDATETIME$\n" | /ifm/bin/lyskom_notify -HLYSKOMSERVERIP -uLYSKOMUSERID -pSECRETPASSWORD -s"Host $HOSTSTATE$ : $HOSTNAME$ ($HOSTALIAS$)" $CONTACTEMAIL$ +} + diff --git a/src/lyskom/buffer.c b/src/lyskom/buffer.c new file mode 100644 index 0000000000000000000000000000000000000000..457c3319ba072573f75fc258709b708e0ef0287a --- /dev/null +++ b/src/lyskom/buffer.c @@ -0,0 +1,155 @@ +/* +** buffer.c +** +** Simple character buffer subroutines +** +** Copyright (c) 2006 Peter Eriksson <pen@lysator.liu.se> +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "buffer.h" + + +void +buf_init(BUFFER *bp) +{ + bp->buf = NULL; + bp->size = 0; + bp->len = 0; +} + + + +int +buf_putc(BUFFER *bp, + char c) +{ + if (bp->len >= bp->size) + { + if (!bp->buf) + bp->buf = malloc((bp->size = 256)+1); + else + bp->buf = realloc(bp->buf, (bp->size += 256)+1); + if (!bp->buf) + return -1; + + memset(bp->buf+bp->len, 0, bp->size+1-bp->len); + } + + bp->buf[bp->len++] = c; + return bp->len; +} + + + +int +buf_puts(BUFFER *bp, + const char *s) +{ + int rc = 0; + + while (rc >= 0 && *s) + rc = buf_putc(bp, *s++); + + return rc; +} + + + +void +buf_clear(BUFFER *bp) +{ + free(bp->buf); + bp->size = 0; + bp->len = 0; +} + + +char * +buf_getall(BUFFER *bp) +{ + return bp->buf ? bp->buf : ""; +} + + +int +buf_save(BUFFER *bp, + FILE *fp) +{ + return fwrite(bp->buf, 1, bp->len, fp); +} + + +int +buf_load(BUFFER *bp, + FILE *fp) +{ + int rc, nsize; + struct stat sb; + + + if (fstat(fileno(fp), &sb) < 0 || !S_ISREG(sb.st_mode)) + { + while ((rc = getc(fp)) != EOF) + buf_putc(bp, rc); + + return bp->len; + } + + nsize = sb.st_size + bp->len; + if (nsize >= bp->size) + { + char *nbuf = realloc(bp->buf, nsize+1); + + if (!nbuf) + return -1; + + bp->buf = nbuf; + bp->size = nsize; + + memset(bp->buf+bp->len, 0, bp->size+1-bp->len); + } + + + rc = fread(bp->buf+bp->len, 1, sb.st_size, fp); + if (rc > 0) + bp->len += rc; + + if (rc < 0) + return -1; + + return bp->len; +} + + +int +buf_length(BUFFER *bp) +{ + return bp->len; +} + + +int +buf_strip(BUFFER *bp) +{ + int i; + + for (i = 0; i < bp->len && isspace(bp->buf[i]); ++i) + ; + if (i < bp->len) + memcpy(bp->buf, bp->buf+i, bp->len-i); + + bp->len -= i; + + for (i = bp->len; i > 0 && isspace(bp->buf[i-1]); --i) + ; + bp->len = i; + + return bp->len; +} diff --git a/src/lyskom/buffer.h b/src/lyskom/buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..1f1096b1274195f716a9ee8590ca507811cfeb43 --- /dev/null +++ b/src/lyskom/buffer.h @@ -0,0 +1,51 @@ +/* +** buffer.h +** +** Simple character buffer subroutines +** +** Copyright (c) 2006 Peter Eriksson <pen@lysator.liu.se> +*/ + +#ifndef BUFFER_H +#define BUFFER_H 1 + +typedef struct buffer +{ + char *buf; + int len; + int size; +} BUFFER; + + +extern void +buf_init(BUFFER *bp); + +extern int +buf_putc(BUFFER *bp, + char c); + +extern int +buf_puts(BUFFER *bp, + const char *s); + +extern void +buf_clear(BUFFER *bp); + +extern char * +buf_getall(BUFFER *bp); + +extern int +buf_save(BUFFER *bp, + FILE *fp); + +extern int +buf_load(BUFFER *bp, + FILE *fp); + +extern int +buf_length(BUFFER *bp); + +extern int +buf_strip(BUFFER *bp); + +#endif diff --git a/src/lyskom/check_lyskom.c b/src/lyskom/check_lyskom.c new file mode 100644 index 0000000000000000000000000000000000000000..39b096389f76031d3539ff13ae72437dd7b864aa --- /dev/null +++ b/src/lyskom/check_lyskom.c @@ -0,0 +1,200 @@ +/* +** check_lyskom.c +** +** A simple Nagios plugin to verify LysKOM server status +** +** Copyright (c) 2006 Peter Eriksson <pen@lysator.liu.se> +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <errno.h> +#include <time.h> +#include <math.h> + +#include "lyskom.h" + + +char *host = "130.236.254.15"; +int port = 4894; + +char *ident = NULL; +int user = 0; +char *pass = NULL; + +char *argv0 = "check_lyskom"; + +int clients_crit = 10000; +int clients_warn = 1000; +int rqclients_crit = 10; +int rqclients_warn = 2; + +void +error(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + printf("CRITICAL - "); + vprintf(msg, ap); + putchar('\n'); + va_end(ap); + exit(2); +} + + + + +int +main(int argc, + char *argv[]) +{ + int i, rc, clients_c, clients_rq; + struct tm tmb; + time_t lyskom_t, our_t; + double d; +#if 0 + int proto; + char *ksoft, *kver; +#endif + + + argv0 = strdup(argv[0]); + + for (i = 1; i < argc && argv[i][0] == '-'; i++) + switch (argv[i][1]) + { + case '-': + ++i; + goto End; + + case 'H': + host = strdup(argv[i]+2); + break; + + case 'P': + if (sscanf(argv[i]+2, "%u", &port) != 1) + error("Invalid argument: %s", argv[i]); + break; + + case 'I': + ident = strdup(argv[i]+2); + break; + + case 'u': + if (sscanf(argv[i]+2, "%u", &user) != 1) + error("Invalid argument: %s", argv[i]); + break; + + case 'p': + pass = strdup(argv[i]+2); + break; + + case 'c': + if (sscanf(argv[i]+2, "%u", &clients_crit) != 1) + error("Invalid argument: %s", argv[i]); + break; + + case 'w': + if (sscanf(argv[i]+2, "%u", &clients_warn) != 1) + error("Invalid argument: %s", argv[i]); + break; + + case 'C': + if (sscanf(argv[i]+2, "%u", &rqclients_crit) != 1) + error("Invalid argument: %s", argv[i]); + break; + + case 'W': + if (sscanf(argv[i]+2, "%u", &rqclients_warn) != 1) + error("Invalid argument: %s", argv[i]); + break; + + case 'h': + printf("Usage: %s [options]\n", argv[0]); + puts("Options:"); + puts("\t-H<lyskom-server-addr>"); + puts("\t-P<lyskom-server-port>"); + puts("\t-u<lyskom-userid>"); + puts("\t-p<password>"); + puts("\t-c<clients-connected-critical-level>"); + puts("\t-w<clients-connected-warning-level>"); + puts("\t-C<clients-runqueue-critical-level>"); + puts("\t-W<clients-runqueue-warning-level>"); + return 0; + + default: + error("Invalid switch: %s", argv[i]); + } + + End: + if (kom_connect(host, port, ident ? ident : "unknown") != 0) + error("Connect failed: Host=%s, Port=%u", host, port); + + if (user > 0) + { + if (kom_login(user, pass ? pass : "") != 0) + error("Login failed: User=%u", user); + } + + rc = kom_time(&tmb); + if (rc != 0) + error("Request failed: Server Time: rc=%u", rc); + + lyskom_t = mktime(&tmb); + time(&our_t); + + d = fabs(difftime(lyskom_t, our_t)); + + if (d > 60.0) + { + printf("CRITICAL - Server time is %d minute(s) off\n", (int) (d/60.0)); + return 1; + } + + if (d > 1.0) + { + printf("WARNING - Server time is %d second(s) off\n", (int) d); + return 1; + } + +#if 0 + if (kom_version(&proto, &ksoft, &kver) != 0) + error("Request failed: Server version"); +#endif + if (kom_clients(&clients_c) != 0) + error("Request failed: Connected clients"); + + if (clients_c > clients_crit) + { + printf("CRITICAL - Connected clients: %u\n", clients_c); + return 2; + } + + if (clients_c > clients_warn) + { + printf("WARNING - Connected clients: %u\n", clients_c); + return 1; + } + + if (kom_runqueue(&clients_rq) != 0) + error("Request failed: Clients in run-queue"); + + if (clients_rq > rqclients_crit) + { + printf("CRITICAL - Clients in run-queue: %u\n", clients_rq); + return 2; + } + + if (clients_rq > rqclients_warn) + { + printf("WARNING - Clients in run-queue: %u\n", clients_rq); + return 1; + } + + printf("OK - Clients: %u (%u in run-queue), Time: %s", + clients_c, clients_rq, asctime(&tmb)); + return 0; +} diff --git a/src/lyskom/lyskom.c b/src/lyskom/lyskom.c new file mode 100644 index 0000000000000000000000000000000000000000..2a14446bea51b432c0d411c89a0b6abbfb0d98f5 --- /dev/null +++ b/src/lyskom/lyskom.c @@ -0,0 +1,306 @@ +/* +** lyskom.c +** +** Simple LysKOM communications routines +** +** Copyright (c) 2006 Peter Eriksson <pen@lysator.liu.se> +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <errno.h> +#include <ctype.h> +#include <unistd.h> +#include <time.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "lyskom.h" + + +static FILE *rfp = NULL; +static FILE *wfp = NULL; +static int rqid = 0; + + + +static int +kom_get_response(FILE *fp, + char *buf, + size_t bufsize) +{ + int c, p = 0; + + + if (bufsize < 1) + return -1; + + while ((c = getc(fp)) != EOF && isspace(c)) + ; + if (c == EOF) + return 0; + + buf[p++] = c; + while (p < bufsize-1 && (c = getc(fp)) != EOF && !(c == '\n' || c == '\r')) + buf[p++] = c; + buf[p] = '\0'; + return 1; +} + + +int +kom_connect(const char *host, + int port, + const char *ident) +{ + struct sockaddr_in sin; + int fd, rc; + char buf[1024]; + + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = inet_addr(host); + sin.sin_port = htons(port); + + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) + return -1; + + while ((rc = connect(fd, (struct sockaddr *) &sin, sizeof(sin))) < 0 && + errno == EINTR) + ; + if (rc < 0) + { + close(fd); + return -2; + } + + rfp = fdopen(fd, "r"); + wfp = fdopen(dup(fd), "w"); + + fprintf(wfp, "A %uH%s\r", strlen(ident), ident); + fflush(wfp); + if (fgets(buf, sizeof(buf), rfp) == NULL) + { + fclose(rfp); + fclose(wfp); + return -3; + } + + if (strncmp(buf, "LysKOM", 6) != 0) + { + fclose(rfp); + fclose(wfp); + return -4; + } + + return 0; +} + + +int +kom_request(const char *msg, ...) +{ + char buf[1024]; + va_list ap; + int id, rc, rs; + + + va_start(ap, msg); + fprintf(wfp, "%u ", ++rqid); + vfprintf(wfp, msg, ap); + putc('\n', wfp); + fflush(wfp); + va_end(ap); + + do { + if (kom_get_response(rfp, buf, sizeof(buf)) < 1) + return -1; + } while (buf[0] == ':'); /* Loop in case of Async Msg */ + + if (sscanf(buf, "=%u", &id) == 1 && id == rqid) + return 0; + + else if (sscanf(buf, "%%%u %u %u", &id, &rc, &rs) == 3) + return rc; + + return -1; +} + + +int +kom_login(int user, + const char *pass) +{ + return kom_request("62 %u %uH%s 1", user, strlen(pass), pass); +} + + +int +kom_time(struct tm *tp) +{ + char buf[1024]; + int id, rc, rs; + + + fprintf(wfp, "%u ", ++rqid); + fprintf(wfp, "35"); + putc('\n', wfp); + fflush(wfp); + + do { + if (kom_get_response(rfp, buf, sizeof(buf)) < 1) + return -1; + } while (buf[0] == ':'); /* Loop in case of Async Msg */ + + if (sscanf(buf, "=%u %u %u %u %u %u %u %u %u %u", &id, + &tp->tm_sec, &tp->tm_min, &tp->tm_hour, &tp->tm_mday, &tp->tm_mon, &tp->tm_year, + &tp->tm_wday, &tp->tm_yday, &tp->tm_isdst) == 10 && id == rqid) + { + return 0; + } + + else if (sscanf(buf, "%%%u %u %u", &id, &rc, &rs) == 3) + return rc; + + return -1; +} + + +char * +kom_geth(const char *buf, + int *ip) +{ + char *rp; + int len; + + + while (isspace(buf[*ip])) + ++*ip; + + if (sscanf(buf+*ip, "%u", &len) != 1) + return NULL; + + while (isdigit(buf[*ip])) + ++*ip; + + if (buf[*ip] != 'H') + return NULL; + + ++*ip; + + rp = malloc(len+1); + if (!rp) + return NULL; + + memcpy(rp, buf+*ip, len); + *ip += len; + rp[len] = '\0'; + + return rp; +} + + +int +kom_version(int *proto, + char **stype, + char **sver) +{ + char buf[1024]; + int id, rc, rs, i; + + + fprintf(wfp, "%u ", ++rqid); + fprintf(wfp, "75"); + putc('\n', wfp); + fflush(wfp); + + do { + if (kom_get_response(rfp, buf, sizeof(buf)) < 1) + return -1; + } while (buf[0] == ':'); /* Loop in case of Async Msg */ + + if (sscanf(buf, "=%u %u", &id, proto) == 2 && id == rqid) + { + for (i = 1; isdigit(buf[i]); ++i) + ; + for (;isspace(buf[i]); ++i) + ; + for (;isdigit(buf[i]); ++i) + ; + for (;isspace(buf[i]); ++i) + ; + *stype = kom_geth(buf, &i); + *sver = kom_geth(buf, &i); + return 0; + } + + else if (sscanf(buf, "%%%u %u %u", &id, &rc, &rs) == 3) + return rc; + + return -1; +} + + +int +kom_clients(int *clients) +{ + char buf[1024]; + int id, rc, rs, n; + + + fprintf(wfp, "%u ", ++rqid); + fprintf(wfp, "112 7Hclients"); + putc('\n', wfp); + fflush(wfp); + + do { + if (kom_get_response(rfp, buf, sizeof(buf)) < 1) + return -1; + } while (buf[0] == ':'); /* Loop in case of Async Msg */ + + if (sscanf(buf, "=%u %u { %u", &id, &n, clients) == 3 && id == rqid) + return 0; + + else if (sscanf(buf, "%%%u %u %u", &id, &rc, &rs) == 3) + return rc; + + return -1; +} + +int +kom_runqueue(int *clients) +{ + char buf[1024]; + int id, rc, rs, n; + + + fprintf(wfp, "%u ", ++rqid); + fprintf(wfp, "112 16Hrun-queue-length"); + putc('\n', wfp); + fflush(wfp); + + do { + if (kom_get_response(rfp, buf, sizeof(buf)) < 1) + return -1; + } while (buf[0] == ':'); /* Loop in case of Async Msg */ + + if (sscanf(buf, "=%u %u { %u", &id, &n, clients) == 3 && id == rqid) + return 0; + + else if (sscanf(buf, "%%%u %u %u", &id, &rc, &rs) == 3) + return rc; + + return -1; +} + + + + + diff --git a/src/lyskom/lyskom.h b/src/lyskom/lyskom.h new file mode 100644 index 0000000000000000000000000000000000000000..bb85ae15d31737856b951320d47f4610c56dccfe --- /dev/null +++ b/src/lyskom/lyskom.h @@ -0,0 +1,32 @@ +/* +** lyskom.h +** +** Simple LysKOM communications routines +** +** Copyright (c) 2006 Peter Eriksson <pen@lysator.liu.se> +*/ + +#ifndef LYSKOM_H + +#include <time.h> + +extern int kom_connect(const char *host, + int port, + const char *ident); + +extern int kom_login(int user, + const char *pass); + +extern int kom_request(const char *msg, ...); + +extern int kom_time(struct tm *tp); + +extern int kom_version(int *proto, + char **stype, + char **sver); + +extern int kom_clients(int *clients); + +extern int kom_runqueue(int *clients); + +#endif diff --git a/src/lyskom/notify_lyskom.c b/src/lyskom/notify_lyskom.c new file mode 100644 index 0000000000000000000000000000000000000000..9526976bce71ca8f10cf168662744a11429d9ad3 --- /dev/null +++ b/src/lyskom/notify_lyskom.c @@ -0,0 +1,134 @@ +/* +** notify_lyskom.c +** +** A simple tool to send alerts/write messages in a LysKOM database +** +** Copyright (c) 2006 Peter Eriksson <pen@lysator.liu.se> +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> + +#include "lyskom.h" +#include "buffer.h" + + +char *host = "130.236.254.15"; +int port = 4894; + +char *ident = NULL; +int user = -1; +char *pass = NULL; + +char *argv0 = "notify_lyskom"; + +void +error(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + fprintf(stderr, "%s: ", argv0); + vfprintf(stderr, msg, ap); + putc('\n', stderr); + va_end(ap); + exit(1); +} + + + + +int +main(int argc, + char *argv[]) +{ + int async = 0, i, rc, target; + char *subject = NULL; + BUFFER buf; + + + argv0 = strdup(argv[0]); + + for (i = 1; i < argc && argv[i][0] == '-'; i++) + switch (argv[i][1]) + { + case '-': + ++i; + goto End; + + case 'H': + host = strdup(argv[i]+2); + break; + + case 'P': + if (sscanf(argv[i]+2, "%u", &port) != 1) + error("invalid argument: %s", argv[i]); + break; + + case 'I': + ident = strdup(argv[i]+2); + break; + + case 'u': + if (sscanf(argv[i]+2, "%u", &user) != 1) + error("invalid argument: %s", argv[i]); + break; + + case 'p': + pass = strdup(argv[i]+2); + break; + + case 'a': + ++async; + break; + + case 's': + subject = strdup(argv[i]+2); + break; + + default: + error("invalid switch: %s", argv[i]); + } + + End: + buf_init(&buf); + buf_load(&buf, stdin); + buf_strip(&buf); + + if (kom_connect(host, port, ident ? ident : "unknown") != 0) + error("kom_connect: host=%s, port=%u", host, port); + + if (user < 0 || !pass) + error("missing user/password"); + + if (kom_login(user, pass) != 0) + error("kom_login: user=%u", user); + + while (i < argc) + { + if (sscanf(argv[i], "%u", &target) != 1) + error("invalid target: %s", argv[i]); + + if (async) + rc = kom_request("53 %u %uH%s", target, buf_length(&buf), buf_getall(&buf)); + else + { + + + rc = kom_request("86 %uH%s\n%s 1 { 0 %u } 0 { }", + strlen(subject ? subject : "")+buf_length(&buf)+1, + (subject ? subject : ""), buf_getall(&buf), target); + + } + + if (rc != 0) + error("kom_request: rc=%u", rc); + + ++i; + } + + return 0; +}