add a mechanism where the ctdb daemon will run a usercontrolled script when the node...
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Tue, 31 Mar 2009 03:23:31 +0000 (14:23 +1100)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Tue, 31 Mar 2009 03:23:31 +0000 (14:23 +1100)
This would allow a sysadmin to set up ctdb to send an email/snmptrap/... when the status of the node changes.

config/ctdb.init
config/ctdb.sysconfig
include/ctdb_private.h
server/ctdb_monitor.c
server/ctdbd.c

index e263855812929fa1efb2b280ce9d05704fef6335..24a206dbbfda9dbeb4a83d7c41bf888c6728001a 100755 (executable)
@@ -64,6 +64,7 @@ CTDB_OPTIONS="$CTDB_OPTIONS --reclock=$CTDB_RECOVERY_LOCK"
 [ -z "$CTDB_EVENT_SCRIPT_DIR" ] || CTDB_OPTIONS="$CTDB_OPTIONS --event-script-dir $CTDB_EVENT_SCRIPT_DIR"
 [ -z "$CTDB_TRANSPORT" ]        || CTDB_OPTIONS="$CTDB_OPTIONS --transport $CTDB_TRANSPORT"
 [ -z "$CTDB_DEBUGLEVEL" ]       || CTDB_OPTIONS="$CTDB_OPTIONS -d $CTDB_DEBUGLEVEL"
+[ -z "$CTDB_NOTIFY_SCRIPT" ]       || CTDB_OPTIONS="$CTDB_OPTIONS --notification-script=$CTDB_NOTIFY_SCRIPT"
 [ -z "$CTDB_START_AS_DISABLED" ] || [ "$CTDB_START_AS_DISABLED" != "yes" ] || {
        CTDB_OPTIONS="$CTDB_OPTIONS --start-as-disabled"
 }
index ef3b0dc3e0397ac1f4054b2d6721d2629cbbd893..f1f367636f87ce1dc150e98f9636900df37da79f 100644 (file)
@@ -95,6 +95,9 @@
 # defaults to /etc/ctdb/nodes
 # CTDB_NODES=/etc/ctdb/nodes
 
+# a script to run when node health changes
+# CTDB_NOTIFY_SCRIPT=/etc/ctdb/notify.sh
+
 # the directory to put the local ctdb database files in
 # defaults to /var/ctdb
 # CTDB_DBDIR=/var/ctdb
index cbd97d75d51e4ea540cb30c3d1582bf0f689c9d4..cf93eed132b8ba8f67bb66806243c5b5371a0785 100644 (file)
@@ -400,6 +400,7 @@ struct ctdb_context {
        void *saved_scheduler_param;
        struct _trbt_tree_t *server_ids;        
        const char *event_script_dir;
+       const char *notification_script;
        const char *default_public_interface;
        pid_t ctdbd_pid;
        pid_t recoverd_pid;
@@ -1241,6 +1242,7 @@ int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
 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_set_notification_script(struct ctdb_context *ctdb, const char *script);
 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 21f0382d6b5d9f086219e04d7aaf3c31d9129847..46d9c632293fcecdce1116c6393098ff926b8164 100644 (file)
@@ -33,6 +33,74 @@ struct ctdb_monitor_state {
 static void ctdb_check_health(struct event_context *ev, struct timed_event *te, 
                              struct timeval t, void *private_data);
 
+/*
+  setup the notification script
+*/
+int ctdb_set_notification_script(struct ctdb_context *ctdb, const char *script)
+{
+       ctdb->notification_script = talloc_strdup(ctdb, script);
+       CTDB_NO_MEMORY(ctdb, ctdb->notification_script);
+       return 0;
+}
+
+static int ctdb_run_notification_script_child(struct ctdb_context *ctdb, const char *event)
+{
+       struct stat st;
+       int ret;
+       char *cmd;
+
+       if (stat(ctdb->notification_script, &st) != 0) {
+               DEBUG(DEBUG_ERR,("Could not stat notification script %s. Can not send notifications.\n", ctdb->notification_script));
+               return -1;
+       }
+       if (!(st.st_mode & S_IXUSR)) {
+               DEBUG(DEBUG_ERR,("Notification script %s is not executable.\n", ctdb->notification_script));
+               return -1;
+       }
+
+       cmd = talloc_asprintf(ctdb, "%s %s\n", ctdb->notification_script, event);
+       CTDB_NO_MEMORY(ctdb, cmd);
+
+       ret = system(cmd);
+       /* if the system() call was successful, translate ret into the
+          return code from the command
+       */
+       if (ret != -1) {
+               ret = WEXITSTATUS(ret);
+       }
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,("Notification script \"%s\" failed with error %d\n", cmd, ret));
+       }
+
+       return ret;
+}
+
+static void ctdb_run_notification_script(struct ctdb_context *ctdb, const char *event)
+{
+       pid_t child;
+
+       if (ctdb->notification_script == NULL) {
+               return;
+       }
+
+       child = fork();
+       if (child == (pid_t)-1) {
+               DEBUG(DEBUG_ERR,("Failed to fork() a notification child process\n"));
+               return;
+       }
+       if (child == 0) {
+               int ret;
+
+               ret = ctdb_run_notification_script_child(ctdb, event);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR,(__location__ " Notification script failed\n"));
+               }
+               _exit(0);
+       }
+
+       return;
+}
+
 /*
   called when a health monitoring event script finishes
  */
@@ -55,10 +123,13 @@ static void ctdb_health_callback(struct ctdb_context *ctdb, int status, void *p)
                        node->flags |= NODE_FLAGS_DISABLED;
                }
 
+               ctdb_run_notification_script(ctdb, "unhealthy");
        } else if (status == 0 && (node->flags & NODE_FLAGS_UNHEALTHY)) {
                DEBUG(DEBUG_NOTICE,("monitor event OK - node re-enabled\n"));
                node->flags &= ~NODE_FLAGS_UNHEALTHY;
                ctdb->monitor->next_interval = 1;
+
+               ctdb_run_notification_script(ctdb, "healthy");
        }
 
        next_interval = ctdb->monitor->next_interval;
index 5670b9387d63779c46a027c8eaead0cec7fca3eb..de6c39fbca7331fb3d3ceef30b092f70a94f63ab 100644 (file)
@@ -33,6 +33,7 @@ static struct {
        const char *myaddress;
        const char *public_address_list;
        const char *event_script_dir;
+       const char *notification_script;
        const char *logfile;
        const char *recovery_lock_file;
        const char *db_dir;
@@ -119,6 +120,7 @@ int main(int argc, const char *argv[])
                { "logfile", 0, POPT_ARG_STRING, &options.logfile, 0, "log file location", "filename" },
                { "nlist", 0, POPT_ARG_STRING, &options.nlist, 0, "node list file", "filename" },
                { "node-ip", 0, POPT_ARG_STRING, &options.node_ip, 0, "node ip", "ip-address"},
+               { "notification-script", 0, POPT_ARG_STRING, &options.notification_script, 0, "notification script", "filename" },
                { "listen", 0, POPT_ARG_STRING, &options.myaddress, 0, "address to listen on", "address" },
                { "transport", 0, POPT_ARG_STRING, &options.transport, 0, "protocol transport", NULL },
                { "dbdir", 0, POPT_ARG_STRING, &options.db_dir, 0, "directory for the tdb files", NULL },
@@ -302,6 +304,14 @@ int main(int argc, const char *argv[])
                exit(1);
        }
 
+       if (options.notification_script != NULL) {
+               ret = ctdb_set_notification_script(ctdb, options.notification_script);
+               if (ret == -1) {
+                       DEBUG(DEBUG_ALERT,("Unable to setup notification script\n"));
+                       exit(1);
+               }
+       }
+
        ctdb->do_setsched = !options.no_setsched;
 
        ctdb->do_checkpublicip = !options.no_publicipcheck;