Merge commit 'ronnie/master'
[nivanova/samba-autobuild/.git] / ctdb / server / eventscript.c
1 /* 
2    event script handling
3
4    Copyright (C) Andrew Tridgell  2007
5
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.
10    
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.
15    
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/>.
18 */
19
20 #include "includes.h"
21 #include "system/filesys.h"
22 #include "system/wait.h"
23 #include "system/dir.h"
24 #include "system/locale.h"
25 #include "../include/ctdb_private.h"
26 #include "lib/events/events.h"
27 #include "../common/rb_tree.h"
28
29 static struct {
30         struct timeval start;
31         const char *script_running;
32 } child_state;
33
34 /*
35   ctdbd sends us a SIGTERM when we should time out the current script
36  */
37 static void sigterm(int sig)
38 {
39         DEBUG(DEBUG_ERR,("Timed out running script '%s' after %.1f seconds\n", 
40                  child_state.script_running, timeval_elapsed(&child_state.start)));
41         /* all the child processes will be running in the same process group */
42         kill(-getpgrp(), SIGKILL);
43         exit(1);
44 }
45
46 struct ctdb_event_script_state {
47         struct ctdb_context *ctdb;
48         pid_t child;
49         void (*callback)(struct ctdb_context *, int, void *);
50         int fd[2];
51         void *private_data;
52         const char *options;
53 };
54
55 /*
56   run the event script - varargs version
57   this function is called and run in the context of a forked child
58   which allows it to do blocking calls such as system()
59  */
60 static int ctdb_event_script_v(struct ctdb_context *ctdb, const char *options)
61 {
62         char *cmdstr;
63         int ret;
64         struct stat st;
65         TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
66         trbt_tree_t *tree;
67         DIR *dir;
68         struct dirent *de;
69         char *script;
70         int count;
71
72         if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
73                 /* we guarantee that only some specifically allowed event scripts are run
74                    while in recovery */
75                 const char *allowed_scripts[] = {"startrecovery", "shutdown", "releaseip" };
76                 int i;
77                 for (i=0;i<ARRAY_SIZE(allowed_scripts);i++) {
78                         if (strncmp(options, allowed_scripts[i], strlen(allowed_scripts[i])) == 0) break;
79                 }
80                 if (i == ARRAY_SIZE(allowed_scripts)) {
81                         DEBUG(DEBUG_ERR,("Refusing to run event scripts with option '%s' while in recovery\n",
82                                  options));
83                         return -1;
84                 }
85         }
86
87         if (setpgid(0,0) != 0) {
88                 DEBUG(DEBUG_ERR,("Failed to create process group for event scripts - %s\n",
89                          strerror(errno)));
90                 talloc_free(tmp_ctx);
91                 return -1;              
92         }
93
94         signal(SIGTERM, sigterm);
95
96         child_state.start = timeval_current();
97         child_state.script_running = "startup";
98
99         /*
100           the service specific event scripts 
101         */
102         if (stat(ctdb->event_script_dir, &st) != 0 && 
103             errno == ENOENT) {
104                 DEBUG(DEBUG_CRIT,("No event script directory found at '%s'\n", ctdb->event_script_dir));
105                 talloc_free(tmp_ctx);
106                 return -1;
107         }
108
109         /* create a tree to store all the script names in */
110         tree = trbt_create(tmp_ctx, 0);
111
112         /* scan all directory entries and insert all valid scripts into the 
113            tree
114         */
115         dir = opendir(ctdb->event_script_dir);
116         if (dir == NULL) {
117                 DEBUG(DEBUG_CRIT,("Failed to open event script directory '%s'\n", ctdb->event_script_dir));
118                 talloc_free(tmp_ctx);
119                 return -1;
120         }
121
122         count = 0;
123         while ((de=readdir(dir)) != NULL) {
124                 int namlen;
125                 unsigned num;
126                 char *str;
127
128                 namlen = strlen(de->d_name);
129
130                 if (namlen < 3) {
131                         continue;
132                 }
133
134                 if (de->d_name[namlen-1] == '~') {
135                         /* skip files emacs left behind */
136                         continue;
137                 }
138
139                 if (de->d_name[2] != '.') {
140                         continue;
141                 }
142
143                 if (sscanf(de->d_name, "%02u.", &num) != 1) {
144                         continue;
145                 }
146
147                 /* Make sure the event script is executable */
148                 str = talloc_asprintf(tree, "%s/%s", ctdb->event_script_dir, de->d_name);
149                 if (stat(str, &st) != 0) {
150                         DEBUG(DEBUG_ERR,("Could not stat event script %s. Ignoring this event script\n", str));
151                         continue;
152                 }
153                 if (!(st.st_mode & S_IXUSR)) {
154                         DEBUG(DEBUG_ERR,("Event script %s is not executable. Ignoring this event script\n", str));
155                         continue;
156                 }
157                 
158                 
159                 /* store the event script in the tree */
160                 trbt_insert32(tree, (num<<16)|count++, talloc_strdup(tree, de->d_name));
161         }
162         closedir(dir);
163
164         /* fetch the scripts from the tree one by one and execute
165            them
166          */
167         while ((script=trbt_findfirstarray32(tree, 1)) != NULL) {
168                 cmdstr = talloc_asprintf(tmp_ctx, "%s/%s %s", 
169                                 ctdb->event_script_dir,
170                                 script, options);
171                 CTDB_NO_MEMORY(ctdb, cmdstr);
172
173                 DEBUG(DEBUG_INFO,("Executing event script %s\n",cmdstr));
174
175                 child_state.start = timeval_current();
176                 child_state.script_running = cmdstr;
177
178                 ret = system(cmdstr);
179                 /* if the system() call was successful, translate ret into the
180                    return code from the command
181                 */
182                 if (ret != -1) {
183                         ret = WEXITSTATUS(ret);
184                 }
185                 /* return an error if the script failed */
186                 if (ret != 0) {
187                         DEBUG(DEBUG_ERR,("Event script %s failed with error %d\n", cmdstr, ret));
188                         talloc_free(tmp_ctx);
189                         return ret;
190                 }
191
192                 /* remove this script from the tree */
193                 talloc_free(script);
194         }
195
196         child_state.start = timeval_current();
197         child_state.script_running = "finished";
198         
199         talloc_free(tmp_ctx);
200         return 0;
201 }
202
203 /* called when child is finished */
204 static void ctdb_event_script_handler(struct event_context *ev, struct fd_event *fde, 
205                                       uint16_t flags, void *p)
206 {
207         struct ctdb_event_script_state *state = 
208                 talloc_get_type(p, struct ctdb_event_script_state);
209         void (*callback)(struct ctdb_context *, int, void *) = state->callback;
210         void *private_data = state->private_data;
211         struct ctdb_context *ctdb = state->ctdb;
212         signed char rt = -1;
213
214         read(state->fd[0], &rt, sizeof(rt));
215
216         talloc_set_destructor(state, NULL);
217         talloc_free(state);
218         callback(ctdb, rt, private_data);
219
220         ctdb->event_script_timeouts = 0;
221 }
222
223 static void ctdb_ban_self(struct ctdb_context *ctdb, uint32_t ban_period)
224 {
225         int ret;
226         struct ctdb_ban_info b;
227         TDB_DATA data;
228
229         b.pnn      = ctdb->pnn;
230         b.ban_time = ban_period;
231
232         data.dptr = (uint8_t *)&b;
233         data.dsize = sizeof(b);
234
235         ret = ctdb_daemon_send_message(ctdb, CTDB_BROADCAST_CONNECTED,
236                 CTDB_SRVID_BAN_NODE, data);
237         if (ret != 0) {
238                 DEBUG(DEBUG_ERR,(__location__ " Failed to send ban message\n"));
239         }
240 }
241
242
243 /* called when child times out */
244 static void ctdb_event_script_timeout(struct event_context *ev, struct timed_event *te, 
245                                       struct timeval t, void *p)
246 {
247         struct ctdb_event_script_state *state = talloc_get_type(p, struct ctdb_event_script_state);
248         void (*callback)(struct ctdb_context *, int, void *) = state->callback;
249         void *private_data = state->private_data;
250         struct ctdb_context *ctdb = state->ctdb;
251         char *options;
252
253         DEBUG(DEBUG_ERR,("Event script timed out : %s count : %u\n", state->options, ctdb->event_script_timeouts));
254
255         options = talloc_strdup(ctdb, state->options);
256         CTDB_NO_MEMORY_VOID(ctdb, options);
257
258         talloc_free(state);
259         if (!strcmp(options, "monitor")) {
260                 /* if it is a monitor event, we allow it to "hang" a few times
261                    before we declare it a failure and ban ourself (and make
262                    ourself unhealthy)
263                 */
264                 DEBUG(DEBUG_ERR, (__location__ " eventscript for monitor event timedout.\n"));
265
266                 ctdb->event_script_timeouts++;
267                 if (ctdb->event_script_timeouts > ctdb->tunable.script_ban_count) {
268                         ctdb->event_script_timeouts = 0;
269                         DEBUG(DEBUG_ERR, ("Maximum timeout count %u reached for eventscript. Banning self for %d seconds\n", ctdb->tunable.script_ban_count, ctdb->tunable.recovery_ban_period));
270                         ctdb_ban_self(ctdb, ctdb->tunable.recovery_ban_period);
271                         callback(ctdb, -1, private_data);
272                 } else {
273                         callback(ctdb, 0, private_data);
274                 }
275         } else if (!strcmp(options, "startup")) {
276                 DEBUG(DEBUG_ERR, (__location__ " eventscript for startup event timedout.\n"));
277                 callback(ctdb, -1, private_data);
278         } else {
279                 /* if it is not a monitor event we ban ourself immediately */
280                 DEBUG(DEBUG_ERR, (__location__ " eventscript for NON-monitor/NON-startup event timedout. Immediately banning ourself for %d seconds\n", ctdb->tunable.recovery_ban_period));
281                 ctdb_ban_self(ctdb, ctdb->tunable.recovery_ban_period);
282                 callback(ctdb, -1, private_data);
283         }
284
285         talloc_free(options);
286 }
287
288 /*
289   destroy a running event script
290  */
291 static int event_script_destructor(struct ctdb_event_script_state *state)
292 {
293         DEBUG(DEBUG_ERR,(__location__ " Sending SIGTERM to child pid:%d\n", state->child));
294         kill(state->child, SIGTERM);
295         return 0;
296 }
297
298 /*
299   run the event script in the background, calling the callback when 
300   finished
301  */
302 static int ctdb_event_script_callback_v(struct ctdb_context *ctdb, 
303                                         struct timeval timeout,
304                                         TALLOC_CTX *mem_ctx,
305                                         void (*callback)(struct ctdb_context *, int, void *),
306                                         void *private_data,
307                                         const char *fmt, va_list ap)
308 {
309         struct ctdb_event_script_state *state;
310         int ret;
311
312         state = talloc(mem_ctx, struct ctdb_event_script_state);
313         CTDB_NO_MEMORY(ctdb, state);
314
315         state->ctdb = ctdb;
316         state->callback = callback;
317         state->private_data = private_data;
318         state->options = talloc_vasprintf(state, fmt, ap);
319         CTDB_NO_MEMORY(ctdb, state->options);
320         
321         ret = pipe(state->fd);
322         if (ret != 0) {
323                 talloc_free(state);
324                 return -1;
325         }
326
327         state->child = fork();
328
329         if (state->child == (pid_t)-1) {
330                 close(state->fd[0]);
331                 close(state->fd[1]);
332                 talloc_free(state);
333                 return -1;
334         }
335
336         if (state->child == 0) {
337                 signed char rt;
338
339                 close(state->fd[0]);
340                 if (ctdb->do_setsched) {
341                         ctdb_restore_scheduler(ctdb);
342                 }
343                 set_close_on_exec(state->fd[1]);
344                 rt = ctdb_event_script_v(ctdb, state->options);
345                 while ((ret = write(state->fd[1], &rt, sizeof(rt))) != sizeof(rt)) {
346                         sleep(1);
347                 }
348                 _exit(rt);
349         }
350
351         talloc_set_destructor(state, event_script_destructor);
352
353         close(state->fd[1]);
354
355         event_add_fd(ctdb->ev, state, state->fd[0], EVENT_FD_READ|EVENT_FD_AUTOCLOSE,
356                      ctdb_event_script_handler, state);
357
358         if (!timeval_is_zero(&timeout)) {
359                 event_add_timed(ctdb->ev, state, timeout, ctdb_event_script_timeout, state);
360         } else {
361                 DEBUG(DEBUG_ERR, (__location__ " eventscript %s called with no timeout\n", state->options));
362         }
363
364         return 0;
365 }
366
367
368 /*
369   run the event script in the background, calling the callback when 
370   finished
371  */
372 int ctdb_event_script_callback(struct ctdb_context *ctdb, 
373                                struct timeval timeout,
374                                TALLOC_CTX *mem_ctx,
375                                void (*callback)(struct ctdb_context *, int, void *),
376                                void *private_data,
377                                const char *fmt, ...)
378 {
379         va_list ap;
380         int ret;
381
382         va_start(ap, fmt);
383         ret = ctdb_event_script_callback_v(ctdb, timeout, mem_ctx, callback, private_data, fmt, ap);
384         va_end(ap);
385
386         return ret;
387 }
388
389
390 struct callback_status {
391         bool done;
392         int status;
393 };
394
395 /*
396   called when ctdb_event_script() finishes
397  */
398 static void event_script_callback(struct ctdb_context *ctdb, int status, void *private_data)
399 {
400         struct callback_status *s = (struct callback_status *)private_data;
401         s->done = true;
402         s->status = status;
403 }
404
405 /*
406   run the event script, waiting for it to complete. Used when the caller doesn't want to 
407   continue till the event script has finished.
408  */
409 int ctdb_event_script(struct ctdb_context *ctdb, const char *fmt, ...)
410 {
411         va_list ap;
412         int ret;
413         TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
414         struct callback_status status;
415
416         va_start(ap, fmt);
417         ret = ctdb_event_script_callback_v(ctdb, timeval_zero(), tmp_ctx, event_script_callback, &status, fmt, ap);
418         va_end(ap);
419
420         if (ret != 0) {
421                 talloc_free(tmp_ctx);
422                 return ret;
423         }
424
425         status.status = -1;
426         status.done = false;
427
428         while (status.done == false && event_loop_once(ctdb->ev) == 0) /* noop */;
429
430         talloc_free(tmp_ctx);
431
432         return status.status;
433 }
434
435
436 struct eventscript_callback_state {
437         struct ctdb_req_control *c;
438 };
439
440 /*
441   called when takeip event finishes
442  */
443 static void run_eventscripts_callback(struct ctdb_context *ctdb, int status, 
444                                  void *private_data)
445 {
446         struct eventscript_callback_state *state = 
447                 talloc_get_type(private_data, struct eventscript_callback_state);
448
449         ctdb_enable_monitoring(ctdb);
450
451         if (status != 0) {
452                 DEBUG(DEBUG_ERR,(__location__ " Failed to forcibly run eventscripts\n"));
453                 ctdb_request_control_reply(ctdb, state->c, NULL, status, NULL);
454                 talloc_free(state);
455                 return;
456         }
457
458         /* the control succeeded */
459         ctdb_request_control_reply(ctdb, state->c, NULL, 0, NULL);
460         talloc_free(state);
461         return;
462 }
463
464 /*
465   A control to force running of the eventscripts from the ctdb client tool
466 */
467 int32_t ctdb_run_eventscripts(struct ctdb_context *ctdb,
468                 struct ctdb_req_control *c,
469                 TDB_DATA indata, bool *async_reply)
470 {
471         int ret;
472         struct eventscript_callback_state *state;
473
474         /* kill off any previous invokations of forced eventscripts */
475         if (ctdb->eventscripts_ctx) {
476                 talloc_free(ctdb->eventscripts_ctx);
477         }
478         ctdb->eventscripts_ctx = talloc_new(ctdb);
479         CTDB_NO_MEMORY(ctdb, ctdb->eventscripts_ctx);
480
481         state = talloc(ctdb->eventscripts_ctx, struct eventscript_callback_state);
482         CTDB_NO_MEMORY(ctdb, state);
483
484         state->c = talloc_steal(state, c);
485
486         DEBUG(DEBUG_NOTICE,("Forced running of eventscripts with arguments %s\n", indata.dptr));
487
488         if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
489                 DEBUG(DEBUG_ERR, (__location__ " Aborted running eventscript \"%s\" while in RECOVERY mode\n", indata.dptr));
490                 return -1;
491         }
492
493         ctdb_disable_monitoring(ctdb);
494
495         ret = ctdb_event_script_callback(ctdb, 
496                          timeval_current_ofs(ctdb->tunable.script_timeout, 0),
497                          state, run_eventscripts_callback, state,
498                          (const char *)indata.dptr);
499
500         if (ret != 0) {
501                 ctdb_enable_monitoring(ctdb);
502                 DEBUG(DEBUG_ERR,(__location__ " Failed to run eventscripts with arguments %s\n", indata.dptr));
503                 talloc_free(state);
504                 return -1;
505         }
506
507         /* tell ctdb_control.c that we will be replying asynchronously */
508         *async_reply = true;
509
510         return 0;
511 }
512