ctdb-daemon: Add implementation of tunnel controls
[Samba.git] / ctdb / server / eventscript.c
blob41807ffdcb0b7c53e571dd1db5fbdea26ea1921d
1 /*
2 event script handling
4 Copyright (C) Andrew Tridgell 2007
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "replace.h"
21 #include "system/filesys.h"
22 #include "system/network.h"
23 #include "system/wait.h"
24 #include "system/dir.h"
25 #include "system/locale.h"
26 #include "system/time.h"
27 #include "system/dir.h"
29 #include <talloc.h>
30 #include <tevent.h>
32 #include "lib/util/dlinklist.h"
33 #include "lib/util/debug.h"
34 #include "lib/util/samba_util.h"
35 #include "lib/util/sys_rw.h"
37 #include "ctdb_private.h"
39 #include "common/rb_tree.h"
40 #include "common/common.h"
41 #include "common/logging.h"
42 #include "common/reqid.h"
43 #include "common/sock_io.h"
45 #include "protocol/protocol_api.h"
48 * Setting up event daemon
51 struct eventd_context {
52 struct tevent_context *ev;
53 const char *path;
54 const char *script_dir;
55 const char *pidfile;
56 const char *socket;
57 const char *debug_hung_script;
59 /* server state */
60 pid_t eventd_pid;
61 struct tevent_fd *eventd_fde;
63 /* client state */
64 struct reqid_context *idr;
65 struct sock_queue *queue;
66 struct eventd_client_state *calls;
69 static bool eventd_context_init(TALLOC_CTX *mem_ctx,
70 struct ctdb_context *ctdb,
71 struct eventd_context **out)
73 struct eventd_context *ectx;
74 const char *eventd = CTDB_HELPER_BINDIR "/ctdb_eventd";
75 const char *debug_hung_script = CTDB_ETCDIR "/debug-hung-script.sh";
76 const char *value;
77 char *socket;
78 int ret;
80 ectx = talloc_zero(mem_ctx, struct eventd_context);
81 if (ectx == NULL) {
82 return false;
85 ectx->ev = ctdb->ev;
87 value = getenv("CTDB_EVENTD");
88 if (value != NULL) {
89 eventd = value;
92 ectx->path = talloc_strdup(ectx, eventd);
93 if (ectx->path == NULL) {
94 talloc_free(ectx);
95 return false;
98 ectx->script_dir = ctdb->event_script_dir;
100 socket = talloc_strdup(ectx, ctdb_get_socketname(ctdb));
101 if (socket == NULL) {
102 talloc_free(ectx);
103 return false;
106 ectx->socket = talloc_asprintf(ectx, "%s/eventd.sock",
107 dirname(socket));
108 if (ectx->socket == NULL) {
109 talloc_free(ectx);
110 return false;
113 talloc_free(socket);
115 value = getenv("CTDB_DEBUG_HUNG_SCRIPT");
116 if (value != NULL) {
117 if (value[0] == '\0') {
118 debug_hung_script = NULL;
119 } else {
120 debug_hung_script = value;
124 if (debug_hung_script != NULL) {
125 ectx->debug_hung_script = talloc_strdup(ectx,
126 debug_hung_script);
127 if (ectx->debug_hung_script == NULL) {
128 talloc_free(ectx);
129 return false;
133 ret = reqid_init(ectx, 1, &ectx->idr);
134 if (ret != 0) {
135 talloc_free(ectx);
136 return false;
139 ectx->eventd_pid = -1;
141 *out = ectx;
142 return true;
146 * Start and stop event daemon
149 static bool eventd_client_connect(struct eventd_context *ectx);
150 static void eventd_dead_handler(struct tevent_context *ev,
151 struct tevent_fd *fde, uint16_t flags,
152 void *private_data);
154 int ctdb_start_eventd(struct ctdb_context *ctdb)
156 struct eventd_context *ectx;
157 const char **argv;
158 int fd[2];
159 pid_t pid;
160 int ret, i;
161 bool status;
163 if (ctdb->ectx == NULL) {
164 status = eventd_context_init(ctdb, ctdb, &ctdb->ectx);
165 if (! status) {
166 DEBUG(DEBUG_ERR,
167 ("Failed to initialize eventd context\n"));
168 return -1;
172 ectx = ctdb->ectx;
174 if (! sock_clean(ectx->socket)) {
175 return -1;
178 argv = talloc_array(ectx, const char *, 14);
179 if (argv == NULL) {
180 return -1;
183 argv[0] = ectx->path;
184 argv[1] = "-e";
185 argv[2] = ectx->script_dir;
186 argv[3] = "-s";
187 argv[4] = ectx->socket;
188 argv[5] = "-P";
189 argv[6] = talloc_asprintf(argv, "%d", ctdb->ctdbd_pid);
190 argv[7] = "-l";
191 argv[8] = getenv("CTDB_LOGGING");
192 argv[9] = "-d";
193 argv[10] = debug_level_to_string(DEBUGLEVEL);
194 if (ectx->debug_hung_script == NULL) {
195 argv[11] = NULL;
196 argv[12] = NULL;
197 } else {
198 argv[11] = "-D";
199 argv[12] = ectx->debug_hung_script;
201 argv[13] = NULL;
203 if (argv[6] == NULL) {
204 talloc_free(argv);
205 return -1;
208 DEBUG(DEBUG_NOTICE,
209 ("Starting event daemon %s %s %s %s %s %s %s %s %s %s %s\n",
210 argv[0], argv[1], argv[2], argv[3], argv[4], argv[5],
211 argv[6], argv[7], argv[8], argv[9], argv[10]));
213 ret = pipe(fd);
214 if (ret != 0) {
215 return -1;
218 pid = ctdb_fork(ctdb);
219 if (pid == -1) {
220 close(fd[0]);
221 close(fd[1]);
222 return -1;
225 if (pid == 0) {
226 close(fd[0]);
227 ret = execv(argv[0], discard_const(argv));
228 if (ret == -1) {
229 _exit(errno);
231 _exit(0);
234 talloc_free(argv);
235 close(fd[1]);
237 ectx->eventd_fde = tevent_add_fd(ctdb->ev, ectx, fd[0],
238 TEVENT_FD_READ,
239 eventd_dead_handler, ectx);
240 if (ectx->eventd_fde == NULL) {
241 ctdb_kill(ctdb, pid, SIGKILL);
242 close(fd[0]);
243 return -1;
246 tevent_fd_set_auto_close(ectx->eventd_fde);
247 ectx->eventd_pid = pid;
249 /* Wait to connect to eventd */
250 for (i=0; i<10; i++) {
251 status = eventd_client_connect(ectx);
252 if (status) {
253 break;
255 sleep(1);
258 if (! status) {
259 DEBUG(DEBUG_ERR, ("Failed to initialize event daemon\n"));
260 ctdb_stop_eventd(ctdb);
261 return -1;
264 return 0;
267 static void eventd_dead_handler(struct tevent_context *ev,
268 struct tevent_fd *fde, uint16_t flags,
269 void *private_data)
271 struct eventd_context *ectx = talloc_get_type_abort(
272 private_data, struct eventd_context);
274 DEBUG(DEBUG_ERR, ("Eventd went away\n"));
276 TALLOC_FREE(ectx->eventd_fde);
277 ectx->eventd_pid = -1;
280 void ctdb_stop_eventd(struct ctdb_context *ctdb)
282 struct eventd_context *ectx = ctdb->ectx;
284 if (ectx == NULL) {
285 return;
288 TALLOC_FREE(ectx->eventd_fde);
289 if (ectx->eventd_pid != -1) {
290 kill(ectx->eventd_pid, SIGTERM);
291 ectx->eventd_pid = -1;
293 TALLOC_FREE(ctdb->ectx);
297 * Connect to event daemon
300 struct eventd_client_state {
301 struct eventd_client_state *prev, *next;
303 struct eventd_context *ectx;
304 void (*callback)(struct ctdb_event_reply *reply, void *private_data);
305 void *private_data;
307 uint32_t reqid;
308 uint8_t *buf;
309 size_t buflen;
312 static void eventd_client_read(uint8_t *buf, size_t buflen,
313 void *private_data);
314 static int eventd_client_state_destructor(struct eventd_client_state *state);
316 static bool eventd_client_connect(struct eventd_context *ectx)
318 int fd;
320 if (ectx->queue != NULL) {
321 return true;
324 fd = sock_connect(ectx->socket);
325 if (fd == -1) {
326 return false;
329 ectx->queue = sock_queue_setup(ectx, ectx->ev, fd,
330 eventd_client_read, ectx);
331 if (ectx->queue == NULL) {
332 close(fd);
333 return false;
336 return true;
339 static int eventd_client_write(struct eventd_context *ectx,
340 TALLOC_CTX *mem_ctx,
341 struct ctdb_event_request *request,
342 void (*callback)(struct ctdb_event_reply *reply,
343 void *private_data),
344 void *private_data)
346 struct eventd_client_state *state;
347 int ret;
349 if (! eventd_client_connect(ectx)) {
350 return -1;
353 state = talloc_zero(mem_ctx, struct eventd_client_state);
354 if (state == NULL) {
355 return -1;
358 state->ectx = ectx;
359 state->callback = callback;
360 state->private_data = private_data;
362 state->reqid = reqid_new(ectx->idr, state);
363 if (state->reqid == REQID_INVALID) {
364 talloc_free(state);
365 return -1;
368 talloc_set_destructor(state, eventd_client_state_destructor);
370 sock_packet_header_set_reqid(&request->header, state->reqid);
372 state->buflen = ctdb_event_request_len(request);
373 state->buf = talloc_size(state, state->buflen);
374 if (state->buf == NULL) {
375 talloc_free(state);
376 return -1;
379 ret = ctdb_event_request_push(request, state->buf, &state->buflen);
380 if (ret != 0) {
381 talloc_free(state);
382 return -1;
385 ret = sock_queue_write(ectx->queue, state->buf, state->buflen);
386 if (ret != 0) {
387 talloc_free(state);
388 return -1;
391 DLIST_ADD(ectx->calls, state);
393 return 0;
396 static int eventd_client_state_destructor(struct eventd_client_state *state)
398 struct eventd_context *ectx = state->ectx;
400 reqid_remove(ectx->idr, state->reqid);
401 DLIST_REMOVE(ectx->calls, state);
402 return 0;
405 static void eventd_client_read(uint8_t *buf, size_t buflen,
406 void *private_data)
408 struct eventd_context *ectx = talloc_get_type_abort(
409 private_data, struct eventd_context);
410 struct eventd_client_state *state;
411 struct ctdb_event_reply *reply;
412 int ret;
414 if (buf == NULL) {
415 /* connection lost */
416 TALLOC_FREE(ectx->queue);
417 return;
420 reply = talloc_zero(ectx, struct ctdb_event_reply);
421 if (reply == NULL) {
422 return;
425 ret = ctdb_event_reply_pull(buf, buflen, reply, reply);
426 if (ret != 0) {
427 D_ERR("Invalid packet received, ret=%d\n", ret);
428 talloc_free(reply);
429 return;
432 if (buflen != reply->header.length) {
433 D_ERR("Packet size mismatch %zu != %"PRIu32"\n",
434 buflen, reply->header.length);
435 talloc_free(reply);
436 return;
439 state = reqid_find(ectx->idr, reply->header.reqid,
440 struct eventd_client_state);
441 if (state == NULL) {
442 talloc_free(reply);
443 return;
446 if (state->reqid != reply->header.reqid) {
447 talloc_free(reply);
448 return;
451 state = talloc_steal(reply, state);
452 state->callback(reply, state->private_data);
453 talloc_free(reply);
457 * Run an event
460 struct eventd_client_run_state {
461 struct eventd_context *ectx;
462 void (*callback)(int result, void *private_data);
463 void *private_data;
466 static void eventd_client_run_done(struct ctdb_event_reply *reply,
467 void *private_data);
469 static int eventd_client_run(struct eventd_context *ectx,
470 TALLOC_CTX *mem_ctx,
471 void (*callback)(int result,
472 void *private_data),
473 void *private_data,
474 enum ctdb_event event,
475 const char *arg_str,
476 uint32_t timeout)
478 struct eventd_client_run_state *state;
479 struct ctdb_event_request request;
480 struct ctdb_event_request_run rdata;
481 int ret;
483 state = talloc_zero(mem_ctx, struct eventd_client_run_state);
484 if (state == NULL) {
485 return -1;
488 state->ectx = ectx;
489 state->callback = callback;
490 state->private_data = private_data;
492 rdata.event = event;
493 rdata.timeout = timeout;
494 rdata.arg_str = arg_str;
496 request.rdata.command = CTDB_EVENT_COMMAND_RUN;
497 request.rdata.data.run = &rdata;
499 ret = eventd_client_write(ectx, state, &request,
500 eventd_client_run_done, state);
501 if (ret != 0) {
502 talloc_free(state);
503 return ret;
506 return 0;
509 static void eventd_client_run_done(struct ctdb_event_reply *reply,
510 void *private_data)
512 struct eventd_client_run_state *state = talloc_get_type_abort(
513 private_data, struct eventd_client_run_state);
515 state = talloc_steal(state->ectx, state);
516 state->callback(reply->rdata.result, state->private_data);
517 talloc_free(state);
521 * CTDB event script functions
524 int ctdb_event_script_run(struct ctdb_context *ctdb,
525 TALLOC_CTX *mem_ctx,
526 void (*callback)(struct ctdb_context *ctdb,
527 int result, void *private_data),
528 void *private_data,
529 enum ctdb_event event,
530 const char *fmt, va_list ap)
531 PRINTF_ATTRIBUTE(6,0);
533 struct ctdb_event_script_run_state {
534 struct ctdb_context *ctdb;
535 void (*callback)(struct ctdb_context *ctdb, int result,
536 void *private_data);
537 void *private_data;
538 enum ctdb_event event;
541 static bool event_allowed_during_recovery(enum ctdb_event event);
542 static void ctdb_event_script_run_done(int result, void *private_data);
543 static bool check_options(enum ctdb_event call, const char *options);
545 int ctdb_event_script_run(struct ctdb_context *ctdb,
546 TALLOC_CTX *mem_ctx,
547 void (*callback)(struct ctdb_context *ctdb,
548 int result, void *private_data),
549 void *private_data,
550 enum ctdb_event event,
551 const char *fmt, va_list ap)
553 struct ctdb_event_script_run_state *state;
554 char *arg_str;
555 int ret;
557 if ( (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) &&
558 (! event_allowed_during_recovery(event)) ) {
559 DEBUG(DEBUG_ERR,
560 ("Refusing to run event '%s' while in recovery\n",
561 ctdb_eventscript_call_names[event]));
564 state = talloc_zero(mem_ctx, struct ctdb_event_script_run_state);
565 if (state == NULL) {
566 return -1;
569 state->ctdb = ctdb;
570 state->callback = callback;
571 state->private_data = private_data;
572 state->event = event;
574 if (fmt != NULL) {
575 arg_str = talloc_vasprintf(state, fmt, ap);
576 if (arg_str == NULL) {
577 talloc_free(state);
578 return -1;
580 } else {
581 arg_str = NULL;
584 if (! check_options(event, arg_str)) {
585 DEBUG(DEBUG_ERR,
586 ("Bad event script arguments '%s' for '%s'\n",
587 arg_str, ctdb_eventscript_call_names[event]));
588 talloc_free(arg_str);
589 return -1;
592 ret = eventd_client_run(ctdb->ectx, state,
593 ctdb_event_script_run_done, state,
594 event, arg_str, ctdb->tunable.script_timeout);
595 if (ret != 0) {
596 talloc_free(state);
597 return ret;
600 DEBUG(DEBUG_INFO,
601 (__location__ " Running event %s with arguments %s\n",
602 ctdb_eventscript_call_names[event], arg_str));
604 talloc_free(arg_str);
605 return 0;
608 static void ctdb_event_script_run_done(int result, void *private_data)
610 struct ctdb_event_script_run_state *state = talloc_get_type_abort(
611 private_data, struct ctdb_event_script_run_state);
613 if (result == -ETIME) {
614 switch (state->event) {
615 case CTDB_EVENT_START_RECOVERY:
616 case CTDB_EVENT_RECOVERED:
617 case CTDB_EVENT_TAKE_IP:
618 case CTDB_EVENT_RELEASE_IP:
619 DEBUG(DEBUG_ERR,
620 ("Ignoring hung script for %s event\n",
621 ctdb_eventscript_call_names[state->event]));
622 result = 0;
623 break;
625 default:
626 break;
630 state = talloc_steal(state->ctdb, state);
631 state->callback(state->ctdb, result, state->private_data);
632 talloc_free(state);
636 static unsigned int count_words(const char *options)
638 unsigned int words = 0;
640 if (options == NULL) {
641 return 0;
644 options += strspn(options, " \t");
645 while (*options) {
646 words++;
647 options += strcspn(options, " \t");
648 options += strspn(options, " \t");
650 return words;
653 static bool check_options(enum ctdb_event call, const char *options)
655 switch (call) {
656 /* These all take no arguments. */
657 case CTDB_EVENT_INIT:
658 case CTDB_EVENT_SETUP:
659 case CTDB_EVENT_STARTUP:
660 case CTDB_EVENT_START_RECOVERY:
661 case CTDB_EVENT_RECOVERED:
662 case CTDB_EVENT_MONITOR:
663 case CTDB_EVENT_SHUTDOWN:
664 case CTDB_EVENT_IPREALLOCATED:
665 return count_words(options) == 0;
667 case CTDB_EVENT_TAKE_IP: /* interface, IP address, netmask bits. */
668 case CTDB_EVENT_RELEASE_IP:
669 return count_words(options) == 3;
671 case CTDB_EVENT_UPDATE_IP: /* old interface, new interface, IP address, netmask bits. */
672 return count_words(options) == 4;
674 default:
675 DEBUG(DEBUG_ERR,(__location__ "Unknown ctdb_event %u\n", call));
676 return false;
680 /* only specific events are allowed while in recovery */
681 static bool event_allowed_during_recovery(enum ctdb_event event)
683 const enum ctdb_event allowed_events[] = {
684 CTDB_EVENT_INIT,
685 CTDB_EVENT_SETUP,
686 CTDB_EVENT_START_RECOVERY,
687 CTDB_EVENT_SHUTDOWN,
688 CTDB_EVENT_RELEASE_IP,
689 CTDB_EVENT_IPREALLOCATED,
691 int i;
693 for (i = 0; i < ARRAY_SIZE(allowed_events); i++) {
694 if (event == allowed_events[i]) {
695 return true;
699 return false;
703 run the event script in the background, calling the callback when
704 finished. If mem_ctx is freed, callback will never be called.
706 int ctdb_event_script_callback(struct ctdb_context *ctdb,
707 TALLOC_CTX *mem_ctx,
708 void (*callback)(struct ctdb_context *, int, void *),
709 void *private_data,
710 enum ctdb_event call,
711 const char *fmt, ...)
713 va_list ap;
714 int ret;
716 va_start(ap, fmt);
717 ret = ctdb_event_script_run(ctdb, mem_ctx, callback, private_data,
718 call, fmt, ap);
719 va_end(ap);
721 return ret;
725 struct ctdb_event_script_args_state {
726 bool done;
727 int status;
730 static void ctdb_event_script_args_done(struct ctdb_context *ctdb,
731 int status, void *private_data)
733 struct ctdb_event_script_args_state *s =
734 (struct ctdb_event_script_args_state *)private_data;
736 s->done = true;
737 s->status = status;
741 run the event script, waiting for it to complete. Used when the caller
742 doesn't want to continue till the event script has finished.
744 int ctdb_event_script_args(struct ctdb_context *ctdb, enum ctdb_event call,
745 const char *fmt, ...)
747 va_list ap;
748 int ret;
749 struct ctdb_event_script_args_state state = {
750 .status = -1,
751 .done = false,
754 va_start(ap, fmt);
755 ret = ctdb_event_script_run(ctdb, ctdb,
756 ctdb_event_script_args_done, &state,
757 call, fmt, ap);
758 va_end(ap);
759 if (ret != 0) {
760 return ret;
763 while (! state.done) {
764 tevent_loop_once(ctdb->ev);
767 if (state.status == -ETIME) {
768 /* Don't ban self if CTDB is starting up or shutting down */
769 if (call != CTDB_EVENT_INIT && call != CTDB_EVENT_SHUTDOWN) {
770 DEBUG(DEBUG_ERR,
771 (__location__ " eventscript for '%s' timed out."
772 " Immediately banning ourself for %d seconds\n",
773 ctdb_eventscript_call_names[call],
774 ctdb->tunable.recovery_ban_period));
775 ctdb_ban_self(ctdb);
779 return state.status;
782 int ctdb_event_script(struct ctdb_context *ctdb, enum ctdb_event call)
784 /* GCC complains about empty format string, so use %s and "". */
785 return ctdb_event_script_args(ctdb, call, NULL);