ctdb-event: Implement event tool "script list" command
authorMartin Schwenke <martin@meltin.net>
Thu, 12 Jul 2018 03:47:51 +0000 (13:47 +1000)
committerAmitay Isaacs <amitay@samba.org>
Sat, 28 Jul 2018 15:14:11 +0000 (17:14 +0200)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13551

Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
12 files changed:
ctdb/event/event_tool.c
ctdb/tests/eventd/etc-ctdb/events/data/03.notalink.script [new file with mode: 0644]
ctdb/tests/eventd/etc-ctdb/share/events/data/02.disabled.script [new file with mode: 0755]
ctdb/tests/eventd/etc-ctdb/share/events/empty/README [new file with mode: 0644]
ctdb/tests/eventd/etc-ctdb/share/events/random/01.disabled.script [new file with mode: 0644]
ctdb/tests/eventd/etc-ctdb/share/events/random/02.enabled.script [new file with mode: 0755]
ctdb/tests/eventd/etc-ctdb/share/events/random/README.script [new file with mode: 0644]
ctdb/tests/eventd/etc-ctdb/share/events/random/a.script [new file with mode: 0755]
ctdb/tests/eventd/eventd_001.sh
ctdb/tests/eventd/eventd_002.sh
ctdb/tests/eventd/eventd_003.sh
ctdb/tests/eventd/eventd_009.sh

index 223e829c3434d997dab69d8b715d427d8ba2e2a6..4768c678b130ccba2b41c3953bbd66ee7ad1feda 100644 (file)
@@ -295,6 +295,179 @@ static int event_command_status(TALLOC_CTX *mem_ctx,
        return ret;
 }
 
+#define EVENT_SCRIPT_DISABLED      ' '
+#define EVENT_SCRIPT_ENABLED       '*'
+
+static int event_command_script_list(TALLOC_CTX *mem_ctx,
+                                    int argc,
+                                    const char **argv,
+                                    void *private_data)
+{
+       struct event_tool_context *ctx = talloc_get_type_abort(
+               private_data, struct event_tool_context);
+       char *subdir = NULL;
+       char *data_dir = NULL;
+       char *etc_dir = NULL;
+       struct event_script_list *data_list = NULL;
+       struct event_script_list *etc_list = NULL;
+       unsigned int i, j, matched;
+       int ret = 0;
+
+       if (argc != 1) {
+               cmdline_usage(ctx->cmdline, "script list");
+               return 1;
+       }
+
+       subdir = talloc_asprintf(mem_ctx, "events/%s", argv[0]);
+       if (subdir == NULL) {
+               ret = ENOMEM;
+       }
+
+       data_dir = path_datadir_append(mem_ctx, subdir);
+       if (data_dir == NULL) {
+               return ENOMEM;
+       }
+
+       etc_dir = path_etcdir_append(mem_ctx, subdir);
+       if (etc_dir == NULL) {
+               return ENOMEM;
+       }
+
+       /*
+        * Ignore error on ENOENT for cut down (e.g. fixed/embedded)
+        * installs that don't use symlinks but just populate etc_dir
+        * directly
+        */
+       ret = event_script_get_list(mem_ctx, data_dir, &data_list);
+       if (ret != 0 && ret != ENOENT) {
+               D_ERR("Command script list finished with result=%d\n", ret);
+               goto done;
+       }
+
+       ret = event_script_get_list(mem_ctx, etc_dir, &etc_list);
+       if (ret != 0) {
+               D_ERR("Command script list finished with result=%d\n", ret);
+               goto done;
+       }
+
+       D_NOTICE("Command script list finished with result=%d\n", ret);
+
+       if (data_list == NULL) {
+               goto list_enabled_only;
+       }
+
+       /*
+        * First list scripts provided by CTDB.  Flag those that are
+        * enabled via a symlink and arrange for them to be excluded
+        * from the subsequent list of local scripts.
+        *
+        * Both lists are sorted, so walk the list of enabled scripts
+        * only once in this pass.
+        */
+       j = 0;
+       matched = 0;
+       for (i = 0; i < data_list->num_scripts; i++) {
+               struct event_script *d = data_list->script[i];
+               char flag = EVENT_SCRIPT_DISABLED;
+               char buf[PATH_MAX];
+               ssize_t len;
+
+               /* Check to see if this script is enabled */
+               while (j < etc_list->num_scripts) {
+                       struct event_script *e = etc_list->script[j];
+
+                       ret = strcmp(e->name, d->name);
+
+                       if (ret > 0) {
+                               /*
+                                * Enabled name is greater, so needs
+                                * to be considered later: done
+                                */
+                               break;
+                       }
+
+                       if (ret < 0) {
+                               /* Enabled name is less: next */
+                               j++;
+                               continue;
+                       }
+
+                       len = readlink(e->path, buf, sizeof(buf));
+                       if (len == -1 || len >= sizeof(buf)) {
+                               /*
+                                * Not a link?  Disappeared?  Invalid
+                                * link target?  Something else?
+                                *
+                                * Doesn't match provided script: next, done
+                                */
+                               j++;
+                               break;
+                       }
+
+                       /* readlink() does not NUL-terminate */
+                       buf[len] = '\0';
+
+                       ret = strcmp(buf, d->path);
+                       if (ret != 0) {
+                               /* Enabled link doesn't match: next, done */
+                               j++;
+                               break;
+                       }
+
+                       /*
+                        * Enabled script's symlink matches our
+                        * script: flag our script as enabled
+                        *
+                        * Also clear the enabled script so it can be
+                        * trivially skipped in the next pass
+                        */
+                       flag = EVENT_SCRIPT_ENABLED;
+                       TALLOC_FREE(etc_list->script[j]);
+                       j++;
+                       matched++;
+                       break;
+               }
+
+               printf("%c %s\n", flag, d->name);
+       }
+
+       /* Print blank line if both provided and local lists are being printed */
+       if (data_list->num_scripts > 0 && matched != etc_list->num_scripts) {
+               printf("\n");
+       }
+
+list_enabled_only:
+
+       /* Now print details of local scripts, after a blank line */
+       for (j = 0; j < etc_list->num_scripts; j++) {
+               struct event_script *e = etc_list->script[j];
+               char flag = EVENT_SCRIPT_DISABLED;
+
+               if (e == NULL) {
+                       /* Matched in previous pass: next */
+                       continue;
+               }
+
+               /* Script is local: if executable then flag as enabled */
+               if (e->enabled) {
+                       flag = EVENT_SCRIPT_ENABLED;
+               }
+
+               printf("%c %s\n", flag, e->name);
+       }
+
+       ret = 0;
+
+done:
+       talloc_free(subdir);
+       talloc_free(data_dir);
+       talloc_free(etc_dir);
+       talloc_free(data_list);
+       talloc_free(etc_list);
+
+       return ret;
+}
+
 static int event_command_script(TALLOC_CTX *mem_ctx,
                                struct event_tool_context *ctx,
                                const char *component,
@@ -463,6 +636,8 @@ struct cmdline_command event_commands[] = {
                "Run an event", "<timeout> <component> <event> <args>" },
        { "status", event_command_status,
                "Get status of an event", "<component> <event>" },
+       { "script list", event_command_script_list,
+               "List event scripts", "<component>" },
        { "script enable", event_command_script_enable,
                "Enable an event script", "<component> <script>" },
        { "script disable", event_command_script_disable,
diff --git a/ctdb/tests/eventd/etc-ctdb/events/data/03.notalink.script b/ctdb/tests/eventd/etc-ctdb/events/data/03.notalink.script
new file mode 100644 (file)
index 0000000..039e4d0
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+exit 0
diff --git a/ctdb/tests/eventd/etc-ctdb/share/events/data/02.disabled.script b/ctdb/tests/eventd/etc-ctdb/share/events/data/02.disabled.script
new file mode 100755 (executable)
index 0000000..9c56f5b
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+case "$1" in
+"failure") exit 1 ;;
+*) exit 0 ;;
+esac
diff --git a/ctdb/tests/eventd/etc-ctdb/share/events/empty/README b/ctdb/tests/eventd/etc-ctdb/share/events/empty/README
new file mode 100644 (file)
index 0000000..a5614a9
--- /dev/null
@@ -0,0 +1 @@
+empty event scripts directory
diff --git a/ctdb/tests/eventd/etc-ctdb/share/events/random/01.disabled.script b/ctdb/tests/eventd/etc-ctdb/share/events/random/01.disabled.script
new file mode 100644 (file)
index 0000000..c52d3c2
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exit 0
diff --git a/ctdb/tests/eventd/etc-ctdb/share/events/random/02.enabled.script b/ctdb/tests/eventd/etc-ctdb/share/events/random/02.enabled.script
new file mode 100755 (executable)
index 0000000..f25e724
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+case "$1" in
+"monitor") exit 0 ;;
+"failure") exit 1 ;;
+"timeout") sleep 99 ;;
+"verbose") echo "Running event $1" ; exit 0 ;;
+"verbosefailure") echo "args: $*"; exit 1 ;;
+"verbosetimeout") echo "Sleeping for 99 seconds"; sleep 99 ;;
+"verbosetimeout2") echo "Sleeping for 99 seconds"; sleep 99 ;;
+*) exit 0 ;;
+esac
diff --git a/ctdb/tests/eventd/etc-ctdb/share/events/random/README.script b/ctdb/tests/eventd/etc-ctdb/share/events/random/README.script
new file mode 100644 (file)
index 0000000..9086add
--- /dev/null
@@ -0,0 +1 @@
+Random collection of files and event scripts
diff --git a/ctdb/tests/eventd/etc-ctdb/share/events/random/a.script b/ctdb/tests/eventd/etc-ctdb/share/events/random/a.script
new file mode 100755 (executable)
index 0000000..2bb8d86
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exit 1
index 3f4e8e46857a1c1a18180cf623e512073daedf7f..7d4ee9e4e919339d66dee60da931dcefc2e26429 100755 (executable)
@@ -20,3 +20,8 @@ required_error ENOENT <<EOF
 Script 01.test does not exist in foobar
 EOF
 simple_test script enable foobar 01.test
+
+required_error ENOENT <<EOF
+Command script list finished with result=$(errcode ENOENT)
+EOF
+simple_test script list foobar
index ba75b1c0e55f8b3cfe2cfd0a7a306fdb17111e6a..f964adf35aa56eec1d1dfd9eb124e678cbdbfb39 100755 (executable)
@@ -17,3 +17,5 @@ simple_test run 10 empty monitor
 ok_null
 simple_test status empty monitor
 
+ok_null
+simple_test script list empty
index 772caef583c9c7e388052ddec23e1414bebcc31e..86250573c8fcd47cdf41b4c69223611d7dca2a03 100755 (executable)
@@ -34,3 +34,12 @@ ok <<EOF
 02.enabled           OK         DURATION DATETIME
 EOF
 simple_test status random monitor
+
+ok <<EOF
+  01.disabled
+  02.enabled
+
+  01.disabled
+* 02.enabled
+EOF
+simple_test script list random
index cc6c1b5279e28b4dcc90b0fc0fb6f0195b1f3e96..1e3d86e28ed28e438c0326d161d5bf96846ebb67 100755 (executable)
@@ -6,6 +6,18 @@ define_test "eventscript directory with links"
 
 setup_eventd
 
+ok <<EOF
+  01.dummy
+  02.disabled
+
+  03.notalink
+EOF
+simple_test script list data
+
+# Should be a no-op
+ok_null
+simple_test script disable data 03.notalink
+
 ok_null
 simple_test run 10 data failure
 
@@ -17,6 +29,14 @@ Event failure in data failed
 EOF
 simple_test run 10 data failure
 
+ok <<EOF
+* 01.dummy
+  02.disabled
+
+  03.notalink
+EOF
+simple_test script list data
+
 required_result 1 <<EOF
 01.dummy             ERROR      DURATION DATETIME
   OUTPUT: 
@@ -28,11 +48,107 @@ simple_test run 10 data monitor
 
 ok <<EOF
 01.dummy             OK         DURATION DATETIME
+03.notalink          DISABLED  
 EOF
 simple_test status data monitor
 
+ok_null
+simple_test script enable data 03.notalink
+
+ok <<EOF
+* 01.dummy
+  02.disabled
+
+* 03.notalink
+EOF
+simple_test script list data
+
+# Local/3rd-party link, not enabled
+touch "${CTDB_BASE}/foo"
+chmod 644 "${CTDB_BASE}/foo"
+ln -s "${CTDB_BASE}/foo" "${CTDB_BASE}/events/data/04.locallink.script"
+
+ok <<EOF
+* 01.dummy
+  02.disabled
+
+* 03.notalink
+  04.locallink
+EOF
+simple_test script list data
+
+ok_null
+simple_test script enable data 04.locallink
+
+required_result 1 ""
+unit_test test -x "${CTDB_BASE}/foo"
+
+ok_null
+simple_test script disable data 04.locallink
+
+ok_null
+unit_test test -f "${CTDB_BASE}/foo"
+
+ok <<EOF
+* 01.dummy
+  02.disabled
+
+* 03.notalink
+EOF
+simple_test script list data
+
+# Local/3rd-party link, enabled
+chmod +x "${CTDB_BASE}/foo"
+ln -s "${CTDB_BASE}/foo" "${CTDB_BASE}/events/data/04.locallink.script"
+
+ok <<EOF
+* 01.dummy
+  02.disabled
+
+* 03.notalink
+* 04.locallink
+EOF
+simple_test script list data
+
 ok_null
 simple_test script disable data 01.dummy
 
+ok_null
+simple_test script disable data 04.locallink
+
+ok_null
+unit_test test -f "${CTDB_BASE}/foo"
+
+ok <<EOF
+  01.dummy
+  02.disabled
+
+* 03.notalink
+EOF
+simple_test script list data
+
 ok_null
 simple_test run 10 data failure
+
+# Local/3rd-party link, dangling
+ln -s "${CTDB_BASE}/doesnotexist" "${CTDB_BASE}/events/data/04.locallink.script"
+
+ok <<EOF
+  01.dummy
+  02.disabled
+
+* 03.notalink
+  04.locallink
+EOF
+simple_test script list data
+
+ok_null
+simple_test script disable data 04.locallink
+
+ok <<EOF
+  01.dummy
+  02.disabled
+
+* 03.notalink
+EOF
+simple_test script list data