Nagios clients in Python and C

Here are Nagios clients in Python and C, written by Thomas Guyot-Sionnest <moc.liamg|toyugt#moc.liamg|toyugt> aka 'dermoth':

#!/usr/bin/env python
#
# NagiosLogger Client
# Author: Thomas Guyot-Sionnest <tguyot@gmail.com>
#
 
import sys, zmq
 
def LogEvent(URL, server, notype, stateid, host, service, message):
    # Raw stateid test - will throw an exception if failed
    int(stateid)
 
    ctx = zmq.Context(1, 1)
    socket = zmq.Socket(ctx, zmq.REQ)
    socket.connect(URL)
 
    # Format is: server(str)[Tab]notificationtype(str)[Tab]stateid(int)[Tab]host(str)[Tab]service(str)[Tab]message(str)
    msg = ''.join([server, "\t", notype, "\t", stateid, "\t", host, "\t", service, "\t", message])
    socket.send(msg)
    # FIXME: Workaround the lack of poll in the python API
    import time
    msg = None
    for i in range(10):
        time.sleep(0.1)
        msg = socket.recv(zmq.NOBLOCK)
        if msg: return True
    return False
 
def usage(error=None):
    if error:
        print 'Error:', error
    print
    print 'Usage:', sys.argv[0], '<ZMQ_URL> <Server> <Notification Type> <Service State ID> <Host> <Service Desc> <Message>'
    print 'Usage:', sys.argv[0], '<ZMQ_URL> <Server> <Notification Type> <Host State ID> <Host> <Message>'
    if error: sys.exit(1)
    sys.exit(0)
 
if len(sys.argv) > 1 and sys.argv[1] in ('-h', '--help'):
    usage()
elif len(sys.argv) == 7:
    # Host notification
    if LogEvent(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], '', sys.argv[6]):
        print "Successfully sent Host Alert event to", sys.argv[1]
    else:
        print "Failed sending Host Alert event to", sys.argv[1]
        sys.exit(1)
elif len(sys.argv) == 8:
    # Service notification
    if LogEvent(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6], sys.argv[7]):
        print "Successfully sent Service Alert event to", sys.argv[1]
    else:
        print "Failed sending Service Alert event to", sys.argv[1]
        sys.exit(1)
else:
    usage('Wrong number of arguments')

And:

/* NagiosLogger C Client
 * Version 0.91
 * Author: Thomas Guyot-Sionnest <tguyot@gmail.com>
 * This code has been released to the public domain.
 *
 * Dev build:
 *   gcc -Wall -lzmq -o client client.c
 *
 * Normal build:
 *   gcc -O2 -DNDEBUG -lzmq -o client client.c && strip client
 *
 */

/* This is the send timeout in microseconds */
#define SEND_TIMEOUT 1000000 /* 1 second */

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <zmq.h>

/* wrapper around zmq_poll which may return zero without reaching the
 * specified timeout */
int
my_zmqpoll(zmq_pollitem_t *items, const int nitems, const long timeout)
{
        struct timeval tv, te;
        int rc, ret;
        long tmleft;

        /* Populate te with timeout value */
        te.tv_sec = timeout / 1000000;
        te.tv_usec = timeout - (te.tv_sec * 1000000);

        rc = gettimeofday(&tv, NULL);
        assert(rc == 0);

        /* Add current time to the timeout (end time) */
        te.tv_sec += tv.tv_sec;
        te.tv_usec += tv.tv_usec;
        te.tv_sec += te.tv_usec / 1000000;
        te.tv_usec %= 1000000;

        /* Loop over, return either >0, or 0 after a timeout */
        tmleft = timeout;
        while (1) {
                ret = zmq_poll(items, nitems, tmleft);
                assert(ret >= 0);

                rc = gettimeofday(&tv, NULL);
                assert(rc == 0);

                if (ret == 0) {
                        /* Keep on looping unless time's up */
                        if (te.tv_sec < tv.tv_sec ||
                                        (te.tv_sec == tv.tv_sec && te.tv_usec <= tv.tv_usec))
                                return ret;
                        tmleft = ((te.tv_sec - tv.tv_sec) * 1000000) + (te.tv_usec - tv.tv_usec);
                } else {
                        return ret;
                }
        }
}

/* Send formatted message to url */
int
logevent(const char *url, const char *message)
{
        int rc, result;
        void *ctx, *socket;
        zmq_msg_t query;
        zmq_pollitem_t items[1];

        /* Send the message */
        rc = zmq_msg_init_size(&query, strlen(message));
        assert(rc == 0);

        memcpy(zmq_msg_data(&query), message, strlen(message));

        ctx = zmq_init (1, 1, ZMQ_POLL);
        assert(ctx);

        socket = zmq_socket(ctx, ZMQ_REQ);
        assert(socket);

        rc = zmq_connect(socket, url);
        assert(rc == 0);

        rc = zmq_send(socket, &query, 0);
        assert(rc == 0);

        zmq_msg_close(&query);

        /* Wait for a reply */
        rc = zmq_msg_init(&query);
        assert(rc == 0);

        items[0].socket = socket;
        items[0].events = ZMQ_POLLIN;
        rc = my_zmqpoll(items, 1, SEND_TIMEOUT);
        assert(rc >= 0);

        rc = zmq_recv(socket, &query, ZMQ_NOBLOCK);
        if (rc == -1 && errno == EAGAIN) {
                result = 0;
        } else {
                assert(rc == 0);
                zmq_msg_close(&query);
                result = 1;
        }

        /* Clean up - FIXME: random SEGV on zmq_term
        zmq_close(socket);
        zmq_term(ctx);
        */

        return result;
}

/* Print usage and exit */
void
usage(const char *progname, const char *error_msg)
{

        assert(progname != NULL);
        if (error_msg)
                printf("Error: %s\n", error_msg);

        printf("\n");
        printf("Usage: %s <ZMQ_URL> <Server> <Notification Type> <Service State ID> <Host> <Service Desc> <Message>\n", progname);
        printf("Usage: %s <ZMQ_URL> <Server> <Notification Type> <Host State ID> <Host> <Message>\n", progname);

        if (error_msg)
                exit(1);

        exit(0);
}

/* Parse arguments and format message */
int
main(int argc, char **argv)
{
        int i, rc;
        char *url, *server, *notype, *stateid, *host, *message;
        char *fmt_msg = NULL;
        char *service = NULL;
        const char *paramtype = "";

        if (argc < 7 || argc > 8) {
                for (i=1; i<argc; i++) {
                        if (strcmp(argv[i], "-h") == 0 ||
                            strcmp(argv[i], "--help") == 0) {
                                usage(argv[0], NULL);
                        }
                }
                usage(argv[0], "Wrong number of arguments");
        }

        for (i=1; i<argc; i++) {
                switch (i) {
                        case 1:
                                url = strdup(argv[i]);
                                break;
                        case 2:
                                server = strdup(argv[i]);
                                break;
                        case 3:
                                notype = strdup(argv[i]);
                                break;
                        case 4:
                                stateid = strdup(argv[i]);
                                if (strlen(stateid) != strspn(stateid, "0123456789"))
                                        usage(argv[0], "State ID is not a number");
                                break;
                        case 5:
                                host = strdup(argv[i]);
                                break;
                        case 6:
                                if (argc == 7) {
                                        message = strdup(argv[i]);
                                        paramtype = "Host";
                                }       else {
                                        service = strdup(argv[i]);
                                        paramtype = "Service";
                                }
                                break;
                        case 7:
                                message = strdup(argv[i]);
                                break;
                }
        }

        /* Format is: server(str)[Tab]notificationtype(str)[Tab]stateid(int)[Tab]host(str)[Tab]service(str)[Tab]message(str) */
        i = strlen(server) + strlen(notype) + strlen(stateid) + strlen(host) + (service ? strlen(service) : 0) + strlen(message) + 5 ;
        fmt_msg = malloc(i+1);
        assert(fmt_msg != NULL);
        rc = snprintf(fmt_msg, i+1, "%s\t%s\t%s\t%s\t%s\t%s", server, notype, stateid, host, service ? service : "", message);
        assert(rc == i);

        if (logevent(url, fmt_msg)) {
                printf("Successfully sent %s Alert event to %s\n", paramtype, url);
                exit(0);
        }
        printf("Failed sending %s Alert event to %s\n", paramtype, url);
        exit(1);

}

Thomas has released this code to the public domain. Enjoy!