merged new event script calling code from ronnnie
authorAndrew Tridgell <tridge@samba.org>
Mon, 20 Aug 2007 01:10:30 +0000 (11:10 +1000)
committerAndrew Tridgell <tridge@samba.org>
Mon, 20 Aug 2007 01:10:30 +0000 (11:10 +1000)
(This used to be ctdb commit bbacad61b3eee4276ffe44ed2a23949aca8152cf)

1  2 
ctdb/server/eventscript.c
ctdb/tests/events.d/00.test
ctdb/tests/start_daemons.sh

index 5e0c42f4b1f2983201b881d9bcefa50a43258510,2b30209cf3376433675e4036048df38819eab6cf..a351807773ec86f0434b21e28dc723bd9722e77f
  #include "includes.h"
  #include "system/filesys.h"
  #include "system/wait.h"
++#include "system/dir.h"
++#include "system/locale.h"
  #include "../include/ctdb_private.h"
  #include "lib/events/events.h"
 -#include <dirent.h>
 -#include <ctype.h>
+ #include "../common/rb_tree.h"
++
++static struct {
++      struct timeval start;
++      const char *script_running;
++} child_state;
++
++/*
++  ctdbd sends us a SIGTERM when we should time out the current script
++ */
++static void sigterm(int sig)
++{
++      DEBUG(0,("Timed out running script '%s' after %.1f seconds\n", 
++               child_state.script_running, timeval_elapsed(&child_state.start)));
++      /* all the child processes will be running in the same process group */
++      kill(-getpgrp(), SIGKILL);
++      exit(1);
++}
  
  /*
    run the event script - varargs version
@@@ -32,30 -37,107 +54,123 @@@ static int ctdb_event_script_v(struct c
        int ret;
        va_list ap2;
        struct stat st;
+       TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+       trbt_tree_t *tree;
+       DIR *dir;
+       struct dirent *de;
+       char *script;
  
-       if (stat(ctdb->takeover.event_script, &st) != 0 && 
++      if (setpgid(0,0) != 0) {
++              DEBUG(0,("Failed to create process group for event scripts - %s\n",
++                       strerror(errno)));
++              talloc_free(tmp_ctx);
++              return -1;              
++      }
++
++      signal(SIGTERM, sigterm);
++
++      child_state.start = timeval_current();
++      child_state.script_running = "startup";
++
+       /*
+         the service specific event scripts 
+       */
+       if (stat(ctdb->takeover.event_script_dir, &st) != 0 && 
            errno == ENOENT) {
-               DEBUG(0,("No event script found at '%s'\n", ctdb->takeover.event_script));
-               return 0;
+               DEBUG(0,("No event script directory found at '%s'\n", ctdb->takeover.event_script_dir));
+               talloc_free(tmp_ctx);
 -              return 0;
++              return -1;
+       }
+       /* create a tree to store all the script names in */
+       tree = trbt_create(tmp_ctx, 0);
+       /* scan all directory entries and insert all valid scripts into the 
+          tree
+       */
+       dir = opendir(ctdb->takeover.event_script_dir);
+       if (dir == NULL) {
+               DEBUG(0,("Failed to open event script directory '%s'\n", ctdb->takeover.event_script_dir));
+               talloc_free(tmp_ctx);
 -              return 0;
++              return -1;
        }
-       va_copy(ap2, ap);
-       options  = talloc_vasprintf(ctdb, fmt, ap2);
-       va_end(ap2);
-       CTDB_NO_MEMORY(ctdb, options);
 +
 -              int num;
+       while ((de=readdir(dir)) != NULL) {
+               int namlen;
++              unsigned num;
+               namlen = strlen(de->d_name);
+               if (namlen < 3) {
+                       continue;
+               }
  
-       cmdstr = talloc_asprintf(ctdb, "%s %s", ctdb->takeover.event_script, options);
-       CTDB_NO_MEMORY(ctdb, cmdstr);
+               if (de->d_name[namlen-1] == '~') {
+                       /* skip files emacs left behind */
+                       continue;
+               }
  
-       ret = system(cmdstr);
-       if (ret != -1) {
-               ret = WEXITSTATUS(ret);
+               if (de->d_name[2] != '.') {
+                       continue;
+               }
 -              if ( (!isdigit(de->d_name[0])) || (!isdigit(de->d_name[1])) ) {
++              if (sscanf(de->d_name, "%02u.", &num) != 1) {
+                       continue;
+               }
 -
 -              sscanf(de->d_name, "%2d.", &num);
+               
+               /* store the event script in the tree */                
 -              script = trbt_insert32(tree, num, talloc_strdup(tmp_ctx, de->d_name));
++              script = trbt_insert32(tree, num, talloc_strdup(tree, de->d_name));
+               if (script != NULL) {
 -                      DEBUG(0,("CONFIG ERROR: Multiple event scripts with the same prefix : %s and %s. Each event script MUST have a unique prefix\n", script, de->d_name));
++                      DEBUG(0,("CONFIG ERROR: Multiple event scripts with the same prefix : '%s' and '%s'. Each event script MUST have a unique prefix\n", script, de->d_name));
+                       talloc_free(tmp_ctx);
+                       closedir(dir);
+                       return -1;
+               }
        }
 -
+       closedir(dir);
+       /* fetch the scripts from the tree one by one and execute
+          them
+        */
+       while ((script=trbt_findfirstarray32(tree, 1)) != NULL) {
+               va_copy(ap2, ap);
+               options  = talloc_vasprintf(tmp_ctx, fmt, ap2);
+               va_end(ap2);
+               CTDB_NO_MEMORY(ctdb, options);
+               cmdstr = talloc_asprintf(tmp_ctx, "%s/%s %s", 
+                               ctdb->takeover.event_script_dir,
+                               script, options);
+               CTDB_NO_MEMORY(ctdb, cmdstr);
  
-       talloc_free(cmdstr);
-       talloc_free(options);
+               DEBUG(1,("Executing event script %s\n",cmdstr));
  
-       return ret;
++              child_state.start = timeval_current();
++              child_state.script_running = cmdstr;
++
+               ret = system(cmdstr);
+               /* if the system() call was successful, translate ret into the
+                  return code from the command
+               */
+               if (ret != -1) {
+                       ret = WEXITSTATUS(ret);
+               }
+               /* return an error if the script failed */
+               if (ret != 0) {
+                       DEBUG(0,("Event script %s failed with error %d\n", cmdstr, ret));
+                       talloc_free(tmp_ctx);
+                       return ret;
+               }
+               /* remove this script from the tree */
+               talloc_free(script);
+       }
++
++      child_state.start = timeval_current();
++      child_state.script_running = "finished";
+       
+       talloc_free(tmp_ctx);
+       return 0;
  }
  
  struct ctdb_event_script_state {
@@@ -106,7 -188,7 +221,7 @@@ static void ctdb_event_script_timeout(s
   */
  static int event_script_destructor(struct ctdb_event_script_state *state)
  {
--      kill(state->child, SIGKILL);
++      kill(state->child, SIGTERM);
        waitpid(state->child, NULL, 0);
        return 0;
  }
Simple merge
index d3c99d075a69ed15929b4374bc29e507cf5daaa2,d3c99d075a69ed15929b4374bc29e507cf5daaa2..f577ef42bee244e01346dd18c4b50386ce0b7a93
@@@ -7,7 -7,7 +7,7 @@@ shif
  
  killall -q ctdbd
  
--CTDB_OPTIONS="--reclock=rec.lock --nlist $NODES --event-script=tests/events --logfile=-  --dbdir=test.db $*"
++CTDB_OPTIONS="--reclock=rec.lock --nlist $NODES --event-script-dir=tests/events.d --logfile=-  --dbdir=test.db $*"
  if [ `id -u` -eq 0 ]; then
      CTDB_OPTIONS="$CTDB_OPTIONS --public-addresses=tests/public_addresses --public-interface=lo"
  fi