static int enable_notifications_for_obj(int sd, const char* obj, const char* rest) { (void)rest; host* hst; service* svc; nez_find_host_or_service(obj, &hst, &svc); if (svc) { enable_service_notifications(svc); nsock_printf_nul(sd, "NOTIFICATIONS ENABLED FOR SERVICE: %s/%s\n", svc->host_name, svc->display_name); return 200; } if (hst) { enable_host_notifications(hst); nsock_printf_nul(sd, "NOTIFICATIONS ENABLED FOR HOST (AND ITS SERVICES): %s\n", hst->display_name); for (servicesmember* svcmem = hst->services; svcmem; svcmem = svcmem->next) { enable_service_notifications(svcmem->service_ptr); } return 200; } nsock_printf_nul(sd, "NO HOST OR SERVICE FOUND FOR: %s", obj); return 404; }
static int qh_help(int sd, char *buf, unsigned int len) { struct query_handler *qh; if (!*buf || !strcmp(buf, "help")) { nsock_printf_nul(sd, " help <name> show help for handler <name>\n" " help list list registered handlers\n"); return 0; } if (!strcmp(buf, "list")) { for (qh = qhandlers; qh; qh = qh->next_qh) { nsock_printf(sd, "%-10s %s\n", qh->name, qh->description ? qh->description : "(No description available)"); } nsock_printf(sd, "%c", 0); return 0; } if (!(qh = qh_find_handler(buf))) { nsock_printf_nul(sd, "No handler named '%s' is registered\n", buf); } else if (qh->handler(sd, "help", 4) > 200) { nsock_printf_nul(sd, "The handler %s doesn't have any help yet.", buf); } return 0; }
static int worker( const char *path) { int sd, ret; char response[128]; /*set_loadctl_defaults();*/ sd = nsock_unix( path, NSOCK_TCP | NSOCK_CONNECT); if( sd < 0) { printf( "Failed to connect to query socket '%s': %s: %s\n", path, nsock_strerror( sd), strerror( errno)); return 1; } ret = nsock_printf_nul( sd, "@wproc register name=Core Ping Worker %d;pid=%d;plugin=check_ping", getpid(), getpid()); if( ret < 0) { printf( "Failed to register as worker.\n"); return 1; } ret = read( sd, response, 3); if( ret != 3) { printf( "Failed to read response from wproc manager\n"); return 1; } if( memcmp( response, "OK", 3)) { read( sd, response + 3, sizeof(response) - 4); response[ sizeof( response) - 2] = 0; printf( "Failed to register with wproc manager: %s\n", response); return 1; } enter_worker( sd, start_cmd); return 0; }
static int unknown_command(int sd, char* object, char* rest) { (void)object; (void)rest; nsock_printf_nul(sd, "UNKNOWN COMMAND\n"); return 404; }
static int nez_cmd_frenchman(int sd, char* object, char* rest) { (void)object; (void)rest; nsock_printf_nul(sd, "http://yolochocin.co/\n"); return 420; // easter egg }
/* the echo service. stupid, but useful for testing */ static int qh_echo(int sd, char *buf, unsigned int len) { if (!strcmp(buf, "help")) { nsock_printf_nul(sd, "Query handler that simply echoes back what you send it."); return 0; } return nsock_write_all(sd, buf, len); }
static int nerd_qh_handler(int sd, char *request, unsigned int len) { char *chan_name, *fmt; struct nerd_channel *chan; int action; if (!*request || !strcmp(request, "help")) { nsock_printf_nul(sd, "Manage subscriptions to NERD channels.\n" "Valid commands:\n" " list list available channels\n" " subscribe <channel> subscribe to a channel\n" " unsubscribe <channel> unsubscribe to a channel\n"); return 0; } if (!strcmp(request, "list")) { unsigned int i; for (i = 0; i < num_channels; i++) { chan = channels[i]; nsock_printf(sd, "%-15s %s\n", chan->name, chan->description); } nsock_printf(sd, "%c", 0); return 0; } chan_name = strchr(request, ' '); if(!chan_name) return 400; *chan_name = 0; chan_name++; if(!strcmp(request, "subscribe")) action = NERD_SUBSCRIBE; else if(!strcmp(request, "unsubscribe")) action = NERD_UNSUBSCRIBE; else { return 400; } /* might have a format-string */ if((fmt = strchr(chan_name, ':'))) *(fmt++) = 0; chan = find_channel(chan_name); if(!chan) { return 400; } if(action == NERD_SUBSCRIBE) subscribe(sd, chan, fmt); else unsubscribe(sd, chan); return 0; }
static int acknowledge_problem_for_obj(int sd, const char* obj, char* comment) { host* hst; service* svc; nez_find_host_or_service(obj, &hst, &svc); char* author = "nagioseasier"; int sticky = 1; // DO NOT send notifications until this service/host recovers int notify = 1; // DO send a notification that we have ack'd this int persistent = 0; // we don't want persistent comments in Nagios if (svc) { acknowledge_service_problem( svc, author, comment, sticky, notify, persistent); nsock_printf_nul(sd, "ACKNOWLEDGED PROBLEMS ON %s WITH: %s\n", obj, comment); return 200; } if (hst) { acknowledge_host_problem( hst, author, comment, sticky, notify, persistent); nsock_printf_nul(sd, "ACKNOWLEDGED PROBLEMS ON %s WITH: %s\n", obj, comment); return 200; } nsock_printf_nul(sd, "NO HOST OR SERVICE FOUND FOR %s\n", obj); return 404; }
static int show_muted_services(int sd) { for (service* svc = service_list; svc; svc = svc->next) { if (svc->notifications_enabled == 0) { nez_show_status_for_service(sd, svc); } } nsock_printf_nul(sd, "NO SERVICES FOUND"); return 404; }
static int unacknowledge_problem_for_obj(int sd, const char* obj) { host* hst; service* svc; nez_find_host_or_service(obj, &hst, &svc); if (svc) { remove_service_acknowledgement(svc); nsock_printf_nul(sd, "REMOVED ACKNOWLEDGEMENT ON %s\n", obj); return 200; } if (hst) { remove_host_acknowledgement(hst); nsock_printf_nul(sd, "REMOVED ACKNOWLEDGEMENT ON %s\n", obj); return 200; } nsock_printf_nul(sd, "NO HOST OR SERVICE FOUND FOR %s\n", obj); return 404; }
static int qh_command(int sd, char *buf, unsigned int len) { char *space; int mode; if (!*buf || !strcmp(buf, "help")) { nsock_printf_nul(sd, "Query handler for naemon commands.\n" "Available commands:\n" " run <command> Run a command\n" " runkv <command> Run a command as escaped kvvec\n" ); return 0; } if ((space = memchr(buf, ' ', len))) * (space++) = 0; if (space) { mode = 0; if (!strcmp(buf, "run")) { mode = COMMAND_SYNTAX_NOKV; } else if(!strcmp(buf, "runkv")) { mode = COMMAND_SYNTAX_KV; } if(mode != 0) { GError *error = NULL; int res = process_external_command(space, mode, &error); if (res == OK) { return 200; } else { nsock_printf_nul(sd, "400: %s\n", error->message); g_clear_error(&error); return 0; } } } return 404; }
int dump_event_stats(int sd) { unsigned int i; for (i = 0; i < ARRAY_SIZE(event_count); i++) { nsock_printf(sd, "%s=%u;", EVENT_TYPE_STR(i), event_count[i]); /* * VERSIONFIX: Make EVENT_SLEEP and EVENT_USER_FUNCTION * appear in linear order in include/nagios.h when we go * from 4.0 -> 4.1, so we can remove this junk. */ if (i == 16) i = 97; } nsock_printf_nul(sd, "SQUEUE_ENTRIES=%u", squeue_size(nagios_squeue)); return OK; }
static int display_help(int sd) { nsock_printf_nul(sd, "Query handler for actually doing useful shit with this socket.\n" "Available commands:\n" " status <host|service> Display the status of a host or service\n" " check <host|service> Schedule a re-check of the host or service\n" "\n" " enable_notifications <host|service> Enable notifications for a host or host-service\n" " disable_notifications <host|service> Disable notifications for a host or host-service\n" "\n" " acknowledge <host|service> [<comment>] Acknowledge a host/service problem (opt. comment)\n" " unacknowledge <host|service> Unacknowledge a host/service problem\n" "\n" " downtime <host|service> [<minutes> <comment>] Schedule downtime for a host/service (opt. num minutes, comment)\n" "\n" " problems [<svcgroup|hstgroup|host> <state>] Display all services in a non-OK state\n" " muted Display all services that do not have notifications enabled\n" "\n" " stats Display stats about service states as JSON\n" ); return 200; }
static int wproc_query_handler(int sd, char *buf, unsigned int len) { char *space, *rbuf = NULL; if (!*buf || !strcmp(buf, "help")) { nsock_printf_nul(sd, "Control worker processes.\n" "Valid commands:\n" " wpstats Print general job information\n" " register <options> Register a new worker\n" " <options> can be name, pid, max_jobs and/or plugin.\n" " There can be many plugin args."); return 0; } if ((space = memchr(buf, ' ', len)) != NULL) *space = 0; rbuf = space ? space + 1 : buf; len -= (unsigned long)rbuf - (unsigned long)buf; if (!strcmp(buf, "register")) return register_worker(sd, rbuf, len); if (!strcmp(buf, "wpstats")) { unsigned int i; for (i = 0; i < workers.len; i++) { struct wproc_worker *wp = workers.wps[i]; nsock_printf(sd, "name=%s;pid=%d;jobs_running=%u;jobs_started=%u\n", wp->name, wp->pid, wp->jobs_running, wp->jobs_started); } return 0; } return 400; }
/* a service for registering workers */ static int register_worker(int sd, char *buf, unsigned int len) { int i, is_global = 1; struct kvvec *info; struct wproc_worker *worker; logit(NSLOG_INFO_MESSAGE, TRUE, "wproc: Registry request: %s\n", buf); if (!(worker = calloc(1, sizeof(*worker)))) { logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: Failed to allocate worker: %s\n", strerror(errno)); return 500; } info = buf2kvvec(buf, len, '=', ';', 0); if (info == NULL) { free(worker); logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: Failed to parse registration request\n"); return 500; } worker->sd = sd; worker->ioc = iocache_create(1 * 1024 * 1024); iobroker_unregister(nagios_iobs, sd); iobroker_register(nagios_iobs, sd, worker, handle_worker_result); for(i = 0; i < info->kv_pairs; i++) { struct key_value *kv = &info->kv[i]; if (!strcmp(kv->key, "name")) { worker->name = strdup(kv->value); } else if (!strcmp(kv->key, "pid")) { worker->pid = atoi(kv->value); } else if (!strcmp(kv->key, "max_jobs")) { worker->max_jobs = atoi(kv->value); } else if (!strcmp(kv->key, "plugin")) { struct wproc_list *command_handlers; is_global = 0; if (!(command_handlers = dkhash_get(specialized_workers, kv->value, NULL))) { command_handlers = calloc(1, sizeof(struct wproc_list)); command_handlers->wps = calloc(1, sizeof(struct wproc_worker**)); command_handlers->len = 1; command_handlers->wps[0] = worker; dkhash_insert(specialized_workers, strdup(kv->value), NULL, command_handlers); } else { command_handlers->len++; command_handlers->wps = realloc(command_handlers->wps, command_handlers->len * sizeof(struct wproc_worker**)); command_handlers->wps[command_handlers->len - 1] = worker; } worker->wp_list = command_handlers; } } if (!worker->max_jobs) { /* * each worker uses two filedescriptors per job, one to * connect to the master and about 13 to handle libraries * and memory allocation, so this guesstimate shouldn't * be too far off (for local workers, at least). */ worker->max_jobs = (iobroker_max_usable_fds() / 2) - 50; } worker->jobs = fanout_create(worker->max_jobs); if (is_global) { workers.len++; workers.wps = realloc(workers.wps, workers.len * sizeof(struct wproc_worker *)); workers.wps[workers.len - 1] = worker; worker->wp_list = &workers; } wproc_num_workers_online++; kvvec_destroy(info, 0); nsock_printf_nul(sd, "OK"); /* signal query handler to release its iocache for this one */ return QH_TAKEOVER; }
static int qh_input(int sd, int events, void *bq_) { nm_bufferqueue *bq = (nm_bufferqueue *)bq_; int result; size_t len; unsigned int query_len = 0; char *buf, *space; struct query_handler *qh; char *handler = NULL, *query = NULL; result = nm_bufferqueue_read(bq, sd); /* disconnect? */ if (result == 0 || (result < 0 && errno == EPIPE)) { nm_bufferqueue_destroy(bq); iobroker_close(nagios_iobs, sd); qh_running--; return 0; } /* * A request looks like this: '[@|#]<qh>[<SP>][<query>]\0'. * That is, optional '#' (oneshot) or '@' (keepalive), * followed by the name of a registered handler, followed by * an optional space and an optional query. If the handler * has no "default" handler, a query is required or an error * will be thrown. */ /* Use data up to the first nul byte */ nm_bufferqueue_unshift_to_delim(bq, "\0", 1, &len, (void **)&buf); if (!buf) return 0; /* Identify handler part and any magic query bytes */ if (*buf == '@' || *buf == '#') { handler = buf + 1; } else { handler = buf; } /* Locate query (if any) */ if ((space = strchr(buf, ' '))) { *space = 0; query = space + 1; query_len = len - ((unsigned long)query - (unsigned long)buf); } else { query = ""; query_len = 0; } /* locate the handler */ if (!(qh = qh_find_handler(handler))) { /* not found. that's a 404 */ nsock_printf(sd, "404: %s: No such handler", handler); nm_free(buf); iobroker_close(nagios_iobs, sd); nm_bufferqueue_destroy(bq); return 0; } /* strip trailing newlines */ while (query_len > 0 && (query[query_len - 1] == 0 || query[query_len - 1] == '\n')) query[--query_len] = 0; /* now pass the query to the handler */ if ((result = qh->handler(sd, query, query_len)) >= 100) { nsock_printf_nul(sd, "%d: %s", result, qh_strerror(result)); } if (result >= 300 || *buf != '@') { /* error code or one-shot query */ nm_free(buf); iobroker_close(nagios_iobs, sd); nm_bufferqueue_destroy(bq); return 0; } nm_free(buf); /* check for magic handler codes */ switch (result) { case QH_CLOSE: /* oneshot handler */ case -1: /* general error */ iobroker_close(nagios_iobs, sd); /* fallthrough */ case QH_TAKEOVER: /* handler takes over */ case 101: /* switch protocol (takeover + message) */ nm_bufferqueue_destroy(bq); break; } return 0; }