call the service specific event scripts directly from the forked child
authorRonnie Sahlberg <sahlberg@ronnie>
Wed, 15 Aug 2007 04:44:03 +0000 (14:44 +1000)
committerRonnie Sahlberg <sahlberg@ronnie>
Wed, 15 Aug 2007 04:44:03 +0000 (14:44 +1000)
instead for from /etc/ctdb/events so that we can get better debugging
output in the logs when something fails in the scripts

config/ctdb.sysconfig
config/events
include/ctdb_private.h
server/ctdb_takeover.c
server/ctdbd.c
server/eventscript.c

index 2ee0b8581c0356c73d4aab91ac2cc4af7c181125..686a17af97f683fecc03c524deedfef80c409a18 100644 (file)
 # defaults to /var/ctdb
 # CTDB_DBDIR=/var/ctdb
 
-# the script to run when ctdb needs to ask the OS for help,
+# the main script to run when ctdb needs to ask the OS for help,
 # such as when a IP address needs to be taken or released
 # defaults to /etc/ctdb/events
 # CTDB_EVENT_SCRIPT=/etc/ctdb/events
 
+# the directory where service specific event scripts are stored
+# defaults to /etc/ctdb/events.d
+# CTDB_EVENT_SCRIPT_DIR=/etc/ctdb/events.d
+
 # the location of the local ctdb socket
 # defaults to /tmp/ctdb.socket
 # CTDB_SOCKET=/tmp/ctdb.socket
index cc74a6c8715a204de47c73ad9af7930cb50e0f5c..c12d58c542476e5bf48631457372ebcdd1ab10c5 100755 (executable)
@@ -35,17 +35,5 @@ case $cmd in
        ;;
 esac
 
-#######################################
-# call all application or local scripts
-[ -d /etc/ctdb/events.d ] && {
-    # only accept scripts of the form NN.name
-    scripts=`/bin/ls /etc/ctdb/events.d | /bin/grep '^[0-9]*\.\w*$' | sort -n`
-    for SCRIPT in $scripts; do
-       [ -x /etc/ctdb/events.d/$SCRIPT ] && {
-           /etc/ctdb/events.d/$SCRIPT $cmd "$1" "$2" "$3" || exit 1
-       }
-    done
-}
-
 # all OK
 exit 0
index 7542b3100fc1ae05dc45fe1cd456da7caf47315c..aaf849ef4418fbe534513357a3f2403d17ce2655 100644 (file)
@@ -301,7 +301,8 @@ enum ctdb_freeze_mode {CTDB_FREEZE_NONE, CTDB_FREEZE_PENDING, CTDB_FREEZE_FROZEN
 struct ctdb_takeover {
        bool enabled;
        const char *interface;
-       const char *event_script;
+       const char *main_event_script;
+       const char *event_script_dir;
        TALLOC_CTX *last_ctx;
 };
 
@@ -1040,6 +1041,7 @@ int ctdb_sys_send_tcp(int fd,
 
 int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist);
 int ctdb_set_event_script(struct ctdb_context *ctdb, const char *script);
+int ctdb_set_event_script_dir(struct ctdb_context *ctdb, const char *script_dir);
 int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap);
 
 int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, 
index d46783b3794f836df01fb0b8bc607b562b923724..bb7473ef637cf2038d3cc0ea04c661a155a19152 100644 (file)
@@ -371,8 +371,18 @@ int32_t ctdb_control_release_ip(struct ctdb_context *ctdb,
 */
 int ctdb_set_event_script(struct ctdb_context *ctdb, const char *script)
 {
-       ctdb->takeover.event_script = talloc_strdup(ctdb, script);
-       CTDB_NO_MEMORY(ctdb, ctdb->takeover.event_script);
+       ctdb->takeover.main_event_script = talloc_strdup(ctdb, script);
+       CTDB_NO_MEMORY(ctdb, ctdb->takeover.main_event_script);
+       return 0;
+}
+
+/*
+  setup the event script directory
+*/
+int ctdb_set_event_script_dir(struct ctdb_context *ctdb, const char *script_dir)
+{
+       ctdb->takeover.event_script_dir = talloc_strdup(ctdb, script_dir);
+       CTDB_NO_MEMORY(ctdb, ctdb->takeover.event_script_dir);
        return 0;
 }
 
index 287af59616cfd7de9fa8bdeebf89b737f9894676..778eff33b08157d5fb3915770af246c4350ebc7b 100644 (file)
@@ -44,6 +44,7 @@ static struct {
        const char *public_address_list;
        const char *public_interface;
        const char *event_script;
+       const char *event_script_dir;
        const char *logfile;
        const char *recovery_lock_file;
        const char *db_dir;
@@ -52,6 +53,7 @@ static struct {
        .nlist = ETCDIR "/ctdb/nodes",
        .transport = "tcp",
        .event_script = ETCDIR "/ctdb/events",
+       .event_script_dir = ETCDIR "/ctdb/events.d",
        .logfile = VARDIR "/log/log.ctdb",
        .db_dir = VARDIR "/ctdb",
 };
@@ -103,6 +105,7 @@ int main(int argc, const char *argv[])
                { "public-addresses", 0, POPT_ARG_STRING, &options.public_address_list, 0, "public address list file", "filename" },
                { "public-interface", 0, POPT_ARG_STRING, &options.public_interface, 0, "public interface", "interface"},
                { "event-script", 0, POPT_ARG_STRING, &options.event_script, 0, "event script", "filename" },
+               { "event-script-dir", 0, POPT_ARG_STRING, &options.event_script_dir, 0, "event script directory", "dirname" },
                { "logfile", 0, POPT_ARG_STRING, &options.logfile, 0, "log file location", "filename" },
                { "nlist", 0, POPT_ARG_STRING, &options.nlist, 0, "node list file", "filename" },
                { "listen", 0, POPT_ARG_STRING, &options.myaddress, 0, "address to listen on", "address" },
@@ -218,6 +221,12 @@ int main(int argc, const char *argv[])
                exit(1);
        }
 
+       ret = ctdb_set_event_script_dir(ctdb, options.event_script_dir);
+       if (ret == -1) {
+               printf("Unable to setup event script directory\n");
+               exit(1);
+       }
+
        /* useful default logfile */
        if (ctdb->logfile == NULL) {
                char *name = talloc_asprintf(ctdb, "%s/log.ctdb.vnn%u", 
index f7a312d29f459a3632912e230610b14902664ce5..e103cfa803d8916913f5503e22ec95dff5c8bd7c 100644 (file)
@@ -22,6 +22,9 @@
 #include "system/wait.h"
 #include "../include/ctdb_private.h"
 #include "lib/events/events.h"
+#include "../common/rb_tree.h"
+#include <dirent.h>
+#include <ctype.h>
 
 /*
   run the event script - varargs version
@@ -34,30 +37,141 @@ static int ctdb_event_script_v(struct ctdb_context *ctdb, const char *fmt, va_li
        int ret;
        va_list ap2;
        struct stat st;
-
-       if (stat(ctdb->takeover.event_script, &st) != 0 && 
+       TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+       trbt_tree_t *tree;
+       DIR *dir;
+       struct dirent *de;
+       char *script;
+
+       /* 
+          run the main event script
+        */
+       if (stat(ctdb->takeover.main_event_script, &st) != 0 && 
            errno == ENOENT) {
-               DEBUG(0,("No event script found at '%s'\n", ctdb->takeover.event_script));
+               DEBUG(0,("No event script found at '%s'\n", ctdb->takeover.main_event_script));
+               talloc_free(tmp_ctx);
                return 0;
        }
 
        va_copy(ap2, ap);
-       options  = talloc_vasprintf(ctdb, fmt, ap2);
+       options  = talloc_vasprintf(tmp_ctx, fmt, ap2);
        va_end(ap2);
        CTDB_NO_MEMORY(ctdb, options);
 
-       cmdstr = talloc_asprintf(ctdb, "%s %s", ctdb->takeover.event_script, options);
+       cmdstr = talloc_asprintf(tmp_ctx, "%s %s", 
+                       ctdb->takeover.main_event_script, options);
        CTDB_NO_MEMORY(ctdb, 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) {
+               talloc_free(tmp_ctx);
+               return ret;
+       }
 
-       talloc_free(cmdstr);
-       talloc_free(options);
 
-       return ret;
+       
+       /*
+         the service specific event scripts 
+       */
+       if (stat(ctdb->takeover.event_script_dir, &st) != 0 && 
+           errno == ENOENT) {
+               DEBUG(0,("No event script directory found at '%s'\n", ctdb->takeover.event_script_dir));
+               talloc_free(tmp_ctx);
+               return 0;
+       }
+
+       /* 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;
+       }
+       while ((de=readdir(dir)) != NULL) {
+               int namlen;
+               int num;
+
+               namlen = strlen(de->d_name);
+
+               if (namlen < 3) {
+                       continue;
+               }
+
+               if (de->d_name[namlen-1] == '~') {
+                       /* skip files emacs left behind */
+                       continue;
+               }
+
+               if (de->d_name[2] != '.') {
+                       continue;
+               }
+
+               if ( (!isdigit(de->d_name[0])) || (!isdigit(de->d_name[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));
+               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));
+                       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);
+
+               DEBUG(1,("Executing event script %s\n",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;
+               }
+
+               talloc_free(script);
+       }
+       
+       talloc_free(tmp_ctx);
+       return 0;
 }
 
 struct ctdb_event_script_state {