diff --git a/test/Makefile.am b/test/Makefile.am index c8c7ace4..1b7e2022 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -53,6 +53,7 @@ TESTS += cond-start-task.sh TESTS += failing-sysv.sh TESTS += global-envs.sh TESTS += initctl-status-subset.sh +TESTS += notify.sh TESTS += pre-post-serv.sh TESTS += restart-self.sh TESTS += runlevel.sh diff --git a/test/common/serv.c b/test/common/serv.c index 4d033609..6c95ccbd 100644 --- a/test/common/serv.c +++ b/test/common/serv.c @@ -14,6 +14,10 @@ #include #define PROGNM "serv" +#define log warnx + +volatile sig_atomic_t reloading = 1; +volatile sig_atomic_t running = 1; static void verify_env(char *arg) { @@ -71,8 +75,17 @@ static void inc_restarts(void) static void sig(int signo) { - warnx("We got signal %d ...", signo); - exit(0); + log("Got signal %d ...", signo); + + switch (signo) { + case SIGHUP: + reloading = 1; + break; + + case SIGTERM: + running = 0; + break; + } } static void pidfile(char *pidfn) @@ -86,7 +99,7 @@ static void pidfile(char *pidfn) pidfn = fn; } pid = getpid(); - warnx("Creating PID file %s with %d", pidfn, pid); + log("Creating PID file %s with %d", pidfn, pid); fp = fopen(pidfn, "w"); if (!fp) @@ -106,6 +119,7 @@ static int usage(int rc) " -e K:V Verify K environment variable is V value\n" " -E K Verify K is not set in the environment\n" " -n Run in foreground\n" + " -N SOCK Send 'READY=1\\n' on $NOTIFY_SOCKET or SOCK\n" " -p Create PID file despite running in foreground\n" " -P FILE Create PID file using FILE\n" " -r SVC Call initctl to restart service SVC (self)\n" @@ -119,16 +133,20 @@ static int usage(int rc) return rc; } +#include + int main(int argc, char *argv[]) { int do_background = 1; + int notify_s6 = 0; int do_pidfile = 1; int do_restart = 0; + int do_notify = 0; char *pidfn = NULL; char cmd[80]; int c; - while ((c = getopt(argc, argv, "e:E:hnpP:r:")) != EOF) { + while ((c = getopt(argc, argv, "e:E:hnN:pP:r:")) != EOF) { switch (c) { case 'h': return usage(0); @@ -142,6 +160,10 @@ int main(int argc, char *argv[]) do_background = 0; do_pidfile--; break; + case 'N': + do_notify = atoi(optarg); + notify_s6 = 1; + break; case 'p': do_pidfile++; break; @@ -165,13 +187,36 @@ int main(int argc, char *argv[]) /* Signal handlers first *then* PID file */ signal(SIGTERM, sig); + signal(SIGHUP, sig); /* Tell world where we are, but not if bg w/o pid file */ if (do_pidfile == 1) pidfile(pidfn); - warnx("Entering while(1) loop"); - while (1) { + if (!do_notify) { + const char *sock = getenv("NOTIFY_SOCKET"); + + /* systemd style */ + if (sock) + do_notify = atoi(sock); + } + + log("Entering while(1) loop"); + while (running) { + if (reloading) { + if (do_notify > 0) { + log("Notifying Finit on socket %d, READY=1", do_notify); + if (write(do_notify, "READY=1\n", 8) == -1) + err(1, "Failed sending ready notification to Finit"); + if (notify_s6) { + log("s6 notify, closing socket %d ...", do_notify); + close(do_notify); + do_notify = 0; + } + } + reloading = 0; + } + sleep(1); if (do_restart) { inc_restarts(); @@ -181,6 +226,6 @@ int main(int argc, char *argv[]) } } - warnx("Leaving ..."); + log("Leaving ..."); return 0; } diff --git a/test/notify.sh b/test/notify.sh new file mode 100755 index 00000000..4e55e9d9 --- /dev/null +++ b/test/notify.sh @@ -0,0 +1,79 @@ +#!/bin/sh +# Verify service readiness notification + +set -eu +#set -x + +TEST_DIR=$(dirname "$0") + +test_setup() +{ + say "Test start $(date)" + texec sh -c "mkdir -p /etc/default" +} + +test_teardown() +{ + say "Test done $(date)" + say "Running test teardown." + + texec rm -f "$FINIT_CONF" +} + +test_one() +{ + type=$1 + service=$2 + + num=$(texec sh -c "find /proc/1/fd |wc -l") + say "finit: number of open file descriptors before test: $num" + + say "Add $type stanza to $FINIT_CONF" + texec sh -c "echo $service > $FINIT_CONF" + + say 'Reload Finit' + texec sh -c "initctl reload" + + sleep 1 + texec sh -c "initctl status serv" + assert_status "serv" "running" + + sleep 2 + texec sh -c "initctl cond dump" + assert_cond "service/serv/ready" + + say "Verify 'ready' is set after SIGHUP ..." + texec sh -c "initctl reload serv" + sleep 2 + assert_status "serv" "running" + assert_cond "service/serv/ready" + + texec sh -c "initctl stop serv" + sleep 1 + assert_status "serv" "stopped" + assert_nocond "service/serv/ready" + + # sleep 2 + # num=$(texec sh -c "find /proc/1/fd |wc -l") + # say "finit: number of open file descriptors after test: $num" + +} + +# shellcheck source=/dev/null +. "$TEST_DIR/tenv/lib.sh" + +texec sh -c "initctl debug" + +test_one "s6" "service log:stdout notify:s6 serv -np -N %n -- s6 readiness" +test_one "systemd" "service log:stdout notify:systemd serv -np -- systemd readiness" + +test_one "s6" "service log:stdout notify:s6 serv -np -N %n -- s6 readiness" +test_one "systemd" "service log:stdout notify:systemd serv -np -- systemd readiness" + +test_one "s6" "service log:stdout notify:s6 serv -np -N %n -- s6 readiness" +test_one "systemd" "service log:stdout notify:systemd serv -np -- systemd readiness" + +test_one "s6" "service log:stdout notify:s6 serv -np -N %n -- s6 readiness" +test_one "systemd" "service log:stdout notify:systemd serv -np -- systemd readiness" + +return 0 diff --git a/test/tenv/lib.sh b/test/tenv/lib.sh index cf21f165..8b431267 100755 --- a/test/tenv/lib.sh +++ b/test/tenv/lib.sh @@ -52,6 +52,25 @@ assert_desc() assert "Service description == $1" "$(texec initctl status "$2" | grep 'Description' | sed 's/Description : //')" = "$1" } +assert_status() +{ + service=$1 + status=$2 + assert "Service $service $status" "$(texec initctl -p status "$service" | awk '/Status/{print $3}')" = "$status" +} + +assert_cond() +{ + cond=$1 + assert "Condition $cond asserted" "$(texec initctl -v cond get "$cond")" = "on" +} + +assert_nocond() +{ + cond=$1 + assert "Condition $cond cleared" "$(texec initctl -v cond get "$cond")" = "off" +} + # shellcheck disable=SC2086 assert_pidfile() { @@ -98,6 +117,7 @@ assert() fi log "$fg_green" ✔ "$__assert_msg" + return 0 } retry()