/* CTDB event daemon control tool Copyright (C) Amitay Isaacs 2016 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . */ #include "replace.h" #include "system/network.h" #include "system/time.h" #include #include #include "lib/util/debug.h" #include "protocol/protocol_api.h" #include "client/client_event.h" #include "common/logging.h" struct tool_context { struct tevent_context *ev; struct ctdb_event_context *eclient; }; static void usage(void); static char *compact_args(const char **argv, int argc, int from) { char *arg_str = NULL; int i; for (i = from; i < argc; i++) { arg_str = talloc_asprintf_append(arg_str, "%s ", argv[i]); if (arg_str == NULL) { fprintf(stderr, "talloc_asprintf_append() failed\n"); exit(1); } } return arg_str; } static int command_run(TALLOC_CTX *mem_ctx, struct tool_context *tctx, int argc, const char **argv) { struct tevent_req *req; enum ctdb_event event; const char *arg_str; int timeout; int eargs; int ret, result; bool status; if (argc < 2) { usage(); } event = ctdb_event_from_string(argv[0]); if (event == CTDB_EVENT_MAX) { fprintf(stderr, "Invalid event '%s'\n", argv[0]); return 1; } timeout = atoi(argv[1]); if (timeout < 0) { timeout = 0; } switch (event) { case CTDB_EVENT_INIT: case CTDB_EVENT_SETUP: case CTDB_EVENT_STARTUP: case CTDB_EVENT_MONITOR: case CTDB_EVENT_IPREALLOCATED: eargs = 0; break; case CTDB_EVENT_TAKE_IP: case CTDB_EVENT_RELEASE_IP: eargs = 3; break; case CTDB_EVENT_UPDATE_IP: eargs = 4; break; default: eargs = -1; break; } if (eargs < 0) { fprintf(stderr, "Cannot run event %s\n", argv[0]); return 1; } if (argc != 2 + eargs) { fprintf(stderr, "Insufficient arguments for event %s\n", argv[0]); return 1; } arg_str = compact_args(argv, argc, 2); req = ctdb_event_run_send(mem_ctx, tctx->ev, tctx->eclient, event, timeout, arg_str); if (req == NULL) { return ENOMEM; } tevent_req_poll(req, tctx->ev); status = ctdb_event_run_recv(req, &ret, &result); talloc_free(req); if (! status) { fprintf(stderr, "Failed to run event %s, ret=%d\n", argv[0], ret); return ret; } if (result == -ETIME) { fprintf(stderr, "Event %s timed out\n", argv[0]); } else if (result == -ECANCELED) { fprintf(stderr, "Event %s got cancelled\n", argv[0]); } else if (result != 0) { fprintf(stderr, "Failed to run event %s, result=%d\n", argv[0], result); } ret = (result < 0) ? -result : result; return ret; } static double timeval_delta(struct timeval *tv2, struct timeval *tv) { return (tv2->tv_sec - tv->tv_sec) + (tv2->tv_usec - tv->tv_usec) * 1.0e-6; } static void print_status_one(struct ctdb_script *script) { if (script->status == -ETIME) { printf("%-20s %-10s %s", script->name, "TIMEDOUT", ctime(&script->start.tv_sec)); } else if (script->status == -ENOEXEC) { printf("%-20s %-10s\n", script->name, "DISABLED"); } else if (script->status < 0) { printf("%-20s %-10s (%s)\n", script->name, "CANNOT RUN", strerror(-script->status)); } else if (script->status == 0) { printf("%-20s %-10s %.3lf %s", script->name, "OK", timeval_delta(&script->finished, &script->start), ctime(&script->start.tv_sec)); } else { printf("%-20s %-10s %.3lf %s", script->name, "ERROR", timeval_delta(&script->finished, &script->start), ctime(&script->start.tv_sec)); } if (script->status != 0 && script->status != -ENOEXEC) { printf(" OUTPUT: %s\n", script->output); } } static int command_status(TALLOC_CTX *mem_ctx, struct tool_context *tctx, int argc, const char **argv) { struct tevent_req *req; struct ctdb_script_list *script_list; enum ctdb_event event; uint32_t state; int ret, result, event_status, i; bool status; if (argc < 1) { event = CTDB_EVENT_MONITOR; } else { event = ctdb_event_from_string(argv[0]); if (event == CTDB_EVENT_MAX) { fprintf(stderr, "Invalid event '%s'\n", argv[0]); return EINVAL; } } if (argc < 2) { state = CTDB_EVENT_LAST_RUN; } else { if (strcmp(argv[1], "lastrun") == 0) { state = CTDB_EVENT_LAST_RUN; } else if (strcmp(argv[1], "lastpass") == 0) { state = CTDB_EVENT_LAST_PASS; } else if (strcmp(argv[1], "lastfail") == 0) { state = CTDB_EVENT_LAST_FAIL; } else { fprintf(stderr, "Invalid state %s\n", argv[1]); return EINVAL; } } req = ctdb_event_status_send(mem_ctx, tctx->ev, tctx->eclient, event, state); if (req == NULL) { return ENOMEM; } tevent_req_poll(req, tctx->ev); status = ctdb_event_status_recv(req, &ret, &result, &event_status, mem_ctx, &script_list); talloc_free(req); if (! status) { fprintf(stderr, "Failed to get event %s status, ret=%d\n", ctdb_event_to_string(event), ret); return ret; } if (result != 0) { fprintf(stderr, "Failed to get event %s status, result=%d\n", ctdb_event_to_string(event), result); return result; } if (script_list == NULL) { if (state == CTDB_EVENT_LAST_RUN) { printf("Event %s has never run\n", ctdb_event_to_string(event)); } else if (state == CTDB_EVENT_LAST_PASS) { printf("Event %s has never passed\n", ctdb_event_to_string(event)); } else if (state == CTDB_EVENT_LAST_FAIL) { printf("Event %s has never failed\n", ctdb_event_to_string(event)); } } else { for (i=0; inum_scripts; i++) { print_status_one(&script_list->script[i]); } talloc_free(script_list); } ret = (event_status < 0) ? -event_status : event_status; return ret; } static int command_script_list(TALLOC_CTX *mem_ctx, struct tool_context *tctx, int argc, const char **argv) { struct tevent_req *req; struct ctdb_script_list *script_list = NULL; int ret, result, i; bool status; if (argc != 0) { usage(); } req = ctdb_event_script_list_send(mem_ctx, tctx->ev, tctx->eclient); if (req == NULL) { return ENOMEM; } tevent_req_poll(req, tctx->ev); status = ctdb_event_script_list_recv(req, &ret, &result, mem_ctx, &script_list); talloc_free(req); if (! status) { fprintf(stderr, "Failed to get script list, ret=%d\n", ret); return ret; } if (result != 0) { fprintf(stderr, "Failed to get script list, result=%d\n", result); return result; } if (script_list == NULL || script_list->num_scripts == 0) { printf("No event scripts found\n"); } else { for (i=0; inum_scripts; i++) { struct ctdb_script *s; s = &script_list->script[i]; if (s->status == -ENOEXEC) { printf("%-20s DISABLED\n", s->name); } else { printf("%-20s\n", s->name); } } talloc_free(script_list); } return 0; } static int command_script_enable(TALLOC_CTX *mem_ctx, struct tool_context *tctx, int argc, const char **argv) { struct tevent_req *req; int ret, result; bool status; if (argc != 1) { usage(); } req = ctdb_event_script_enable_send(mem_ctx, tctx->ev, tctx->eclient, argv[0]); if (req == NULL) { return ENOMEM; } tevent_req_poll(req, tctx->ev); status = ctdb_event_script_enable_recv(req, &ret, &result); talloc_free(req); if (! status) { fprintf(stderr, "Failed to enable script %s, ret=%d\n", argv[0], ret); return ret; } if (result == -ENOENT) { fprintf(stderr, "Script %s does not exist\n", argv[0]); } else if (result == -EINVAL) { fprintf(stderr, "Script name %s is invalid\n", argv[0]); } else if (result != 0) { fprintf(stderr, "Failed to enable script %s, result=%d\n", argv[0], result); } ret = (result < 0) ? -result : result; return ret; } static int command_script_disable(TALLOC_CTX *mem_ctx, struct tool_context *tctx, int argc, const char **argv) { struct tevent_req *req; int ret, result; bool status; if (argc != 1) { usage(); } req = ctdb_event_script_disable_send(mem_ctx, tctx->ev, tctx->eclient, argv[0]); if (req == NULL) { return ENOMEM; } tevent_req_poll(req, tctx->ev); status = ctdb_event_script_disable_recv(req, &ret, &result); talloc_free(req); if (! status) { fprintf(stderr, "Failed to disable script %s, ret=%d\n", argv[0], ret); return ret; } if (result == -ENOENT) { fprintf(stderr, "Script %s does not exist\n", argv[0]); } else if (result == -EINVAL) { fprintf(stderr, "Script name %s is invalid\n", argv[0]); } else if (result != 0) { fprintf(stderr, "Failed to disable script %s, result=%d\n", argv[0], result); } ret = (result < 0) ? -result : result; return ret; } static const struct ctdb_event_cmd { const char *name; const char *str1; const char *str2; int (*fn)(TALLOC_CTX *, struct tool_context *, int, const char **); const char *msg; const char *args; } ctdb_event_commands[] = { { "run", "run", NULL, command_run, "Run an event", " " }, { "status", "status", NULL, command_status, "Get last status of an event", "[] [lastrun|lastpass|lastfail]" }, { "script list", "script", "list", command_script_list, "Get list of event scripts", NULL }, { "script enable", "script", "enable", command_script_enable, "Enable an event script", "