# 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
;;
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
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;
};
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,
*/
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;
}
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;
.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",
};
{ "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" },
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",
#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
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 {