Hello community, here is the log from the commit of package booth for openSUSE:Factory checked in at 2016-04-01 13:02:45 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/booth (Old) and /work/SRC/openSUSE:Factory/.booth.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "booth" Changes: -------- --- /work/SRC/openSUSE:Factory/booth/booth.changes 2016-01-22 01:09:43.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.booth.new/booth.changes 2016-04-01 13:02:49.000000000 +0200 @@ -1,0 +2,14 @@ +Wed Mar 23 16:35:54 UTC 2016 - [email protected] + +- Update to version v1.0_6_g106efdf: + + Feature: extprog: add capability to run a set of programs + + Medium: extprog: external tests timeout after renewal interval + +------------------------------------------------------------------- +Wed Mar 16 15:53:29 UTC 2016 - [email protected] + +- Update to release v1.0 + + systemd: add booth-arbitrator.service (bsc#967036) + + main: improve address matching procedure + +------------------------------------------------------------------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ booth.spec ++++++ --- /var/tmp/diff_new_pack.Mqf5sy/_old 2016-04-01 13:02:50.000000000 +0200 +++ /var/tmp/diff_new_pack.Mqf5sy/_new 2016-04-01 13:02:50.000000000 +0200 @@ -46,7 +46,7 @@ License: GPL-2.0+ Group: %{pkg_group} Version: 1.0 -Release: 0rc1 +Release: 0 Source: booth.tar.bz2 Source1: %name-rpmlintrc BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -103,6 +103,7 @@ # systemd mkdir -p %{buildroot}/%{_unitdir} cp -a conf/[email protected] %{buildroot}/%{_unitdir}/[email protected] +cp -a conf/booth-arbitrator.service %{buildroot}/%{_unitdir}/booth-arbitrator.service ln -s /usr/sbin/service %{buildroot}%{_sbindir}/rcbooth-arbitrator %else # sysV init @@ -156,6 +157,7 @@ %if %{defined _unitdir} %{_unitdir}/[email protected] +%{_unitdir}/booth-arbitrator.service %exclude %{_initddir}/booth-arbitrator %else %{_initddir}/booth-arbitrator @@ -167,22 +169,6 @@ %doc AUTHORS README COPYING %doc README.upgrade-from-v0.1 -# this should be preun, but... -%pre -# new installation? -test -x %{_sbindir}/booth || exit 0 -# stop the arbitrator if it's the previous paxos version 1.0 -if [ "`booth version | awk '{print $2}'`" = "1.0" ]; then - echo "booth v0.1 found" - if grep -qs 'ticket.*;' /etc/booth/booth.conf; then - echo "Convert the booth configuration in /etc/booth/booth.conf!" - fi - if ps -o pid,cmd -e | grep -qs "[b]oothd arbitrator"; then - rcbooth-arbitrator stop - fi -fi -exit 0 - %package test Summary: Test scripts for Booth Group: %{pkg_group} ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.Mqf5sy/_old 2016-04-01 13:02:50.000000000 +0200 +++ /var/tmp/diff_new_pack.Mqf5sy/_new 2016-04-01 13:02:50.000000000 +0200 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">git://github.com/ClusterLabs/booth.git</param> - <param name="changesrevision">9c5c19f2c9217db9bf6265e8e753ac15ba631ae0</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">106efdf386c23aa7c740f1d238ecd04fd63f5ebc</param></service></servicedata> \ No newline at end of file ++++++ booth.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/.git_info new/booth/.git_info --- old/booth/.git_info 2016-01-12 15:03:32.000000000 +0100 +++ new/booth/.git_info 2016-03-23 17:32:51.000000000 +0100 @@ -1 +1 @@ -v1.0rc1 +v1.0-6-g106efdf diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/ChangeLog new/booth/ChangeLog --- old/booth/ChangeLog 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/ChangeLog 2016-03-23 17:31:14.000000000 +0100 @@ -1,3 +1,8 @@ +* Mar Jan 16 2016 Dejan Muhamedagic <[email protected]> and others +- stable release 1.0 +- systemd: add booth-arbitrator.service (bsc#967036) +- main: improve address matching procedure + * Mon Jan 11 2016 Dejan Muhamedagic <[email protected]> and others - release candidate 1.0 rc1 - main: prevent segfault on no arguments diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/README new/booth/README --- old/booth/README 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/README 2016-03-23 17:31:14.000000000 +0100 @@ -118,14 +118,18 @@ renewals are configurable and by default set to half ticket expire time. -Before ticket renewal, the leader runs an external program if -such program is set in 'before-acquire-handler'. The external -program should ensure that the cluster managed service which is -protected by this ticket can run at this site. If that program -fails, the leader relinquishes the ticket. It announces its -intention to step down by broadcasting an unsolicited VOTE_FOR -with an empty vote. On receiving such RPC other servers start new -elections to elect a new leader. +Before ticket renewal, the leader runs one or more external +programs if such are set in 'before-acquire-handler'. This can +point either to a file or a directory. In the former case, that +file is the program, but in the latter there could be a number of +programs in the specified directory. All files which have the +executable bit set and whose names don't start with a '.' are +run sequentially. This program or programs should ensure that the +cluster managed service which is protected by this ticket can run +at this site. If any of them fails, the leader relinquishes the +ticket. It announces its intention to step down by broadcasting +an unsolicited VOTE_FOR with an empty vote. On receiving such RPC +other servers start new elections to elect a new leader. Split brain ------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/booth.spec new/booth/booth.spec --- old/booth/booth.spec 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/booth.spec 2016-03-23 17:31:14.000000000 +0100 @@ -29,7 +29,7 @@ License: GPL-2.0+ Group: %{pkg_group} Version: 1.0 -Release: rc1 +Release: 0 Source: booth.tar.bz2 Source1: %name-rpmlintrc BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -86,6 +86,7 @@ # systemd mkdir -p %{buildroot}/%{_unitdir} cp -a conf/[email protected] %{buildroot}/%{_unitdir}/[email protected] +cp -a conf/booth-arbitrator.service %{buildroot}/%{_unitdir}/booth-arbitrator.service ln -s /usr/sbin/service %{buildroot}%{_sbindir}/rcbooth-arbitrator %else # sysV init @@ -148,6 +149,7 @@ %if %{defined _unitdir} %{_unitdir}/[email protected] +%{_unitdir}/booth-arbitrator.service %exclude %{_initddir}/booth-arbitrator %else %{_initddir}/booth-arbitrator @@ -159,23 +161,6 @@ %doc AUTHORS README COPYING %doc README.upgrade-from-v0.1 -# this should be preun, but... -%pre -# new installation? -test -x %{_sbindir}/booth || exit 0 -# stop the arbitrator if it's the previous paxos version 1.0 -if [ "`booth version | awk '{print $2}'`" = "1.0" ]; then - echo "booth v0.1 found" - if grep -qs 'ticket.*;' /etc/booth/booth.conf; then - echo "Convert the booth configuration in /etc/booth/booth.conf!" - fi - if ps -o pid,cmd -e | grep -qs "[b]oothd arbitrator"; then - rcbooth-arbitrator stop - fi -fi -exit 0 - - %package test Summary: Test scripts for Booth Group: %{pkg_group} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/conf/booth-arbitrator.service new/booth/conf/booth-arbitrator.service --- old/booth/conf/booth-arbitrator.service 1970-01-01 01:00:00.000000000 +0100 +++ new/booth/conf/booth-arbitrator.service 2016-03-23 17:31:14.000000000 +0100 @@ -0,0 +1,16 @@ +# This file is part of Booth. + +[Unit] +Description=Booth - Ticket Manager for Pacemaker Clusters +Documentation=man:boothd(8) +After=network-online.target +ConditionFileNotEmpty=/etc/booth/booth.conf +Conflicts=pacemaker.service + +[Install] +WantedBy=multi-user.target + +[Service] +Type=simple +ExecStart=/usr/sbin/boothd daemon -S -c /etc/booth/booth.conf + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/conf/[email protected] new/booth/conf/[email protected] --- old/booth/conf/[email protected] 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/conf/[email protected] 2016-03-23 17:31:14.000000000 +0100 @@ -4,7 +4,8 @@ Description=Booth - Ticket Manager for Pacemaker Clusters Documentation=man:boothd(8) After=network-online.target -ConditionFileExists=/etc/booth/%i.conf +ConditionFileNotEmpty=/etc/booth/%i.conf +Conflicts=pacemaker.service [Install] Alias=boothd @@ -12,6 +13,5 @@ [Service] Type=simple -Conflicts=pacemaker.service ExecStart=/usr/sbin/boothd daemon -S -c %i diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/configure.ac new/booth/configure.ac --- old/booth/configure.ac 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/configure.ac 2016-03-23 17:31:14.000000000 +0100 @@ -4,7 +4,7 @@ # bootstrap / init AC_PREREQ([2.61]) -AC_INIT([booth], [1.0-0-rc1], [[email protected]]) +AC_INIT([booth], [1.0], [[email protected]]) AM_INIT_AUTOMAKE([-Wno-portability]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/docs/boothd.8.txt new/booth/docs/boothd.8.txt --- old/booth/docs/boothd.8.txt 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/docs/boothd.8.txt 2016-03-23 17:31:14.000000000 +0100 @@ -282,10 +282,10 @@ If the network reliability is often reduced over prolonged periods, it is advisable to try to renew more often. + -Before every renewal, if defined, the command specified in -'before-acquire-handler' is run. In that case the 'renewal-freq' -parameter is effectively also the local cluster monitoring -interval. +Before every renewal, if defined, the command or commands +specified in 'before-acquire-handler' is run. In that case the +'renewal-freq' parameter is effectively also the local cluster +monitoring interval. *'timeout'*:: After that time 'booth' will re-send packets if there was an @@ -314,9 +314,11 @@ file defines priority for conflicting requests. *'before-acquire-handler'*:: - If set, this command will be called before 'boothd' tries to - acquire or renew a ticket. On exit code other than 0, - 'boothd' relinquishes the ticket. + If set, this parameter specifies either a file containing a + program to be run or a directory where a number of programs + can reside. They are invoked before 'boothd' tries to acquire + or renew a ticket. If any of them exits with a code other + than 0, 'boothd' relinquishes the ticket. + Thus it is possible to ensure whether the services and its dependencies protected by the ticket are in good shape at this @@ -325,6 +327,10 @@ be unable to run. In that case, it is of no use to claim the ticket. + +One or more arguments may follow the program or directory +location. Typically, there is at least the name of one of +the resources which depend on this ticket. ++ See below for details about booth specific environment variables. The distributed 'service-runnable' script is an example which may be used to test whether a pacemaker resource can be started. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/script/lsb/booth-arbitrator new/booth/script/lsb/booth-arbitrator --- old/booth/script/lsb/booth-arbitrator 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/script/lsb/booth-arbitrator 2016-03-23 17:31:14.000000000 +0100 @@ -126,15 +126,9 @@ local rc=0 for cnf in ${BOOTH_CONF_FILE:-$CONF_DIR/*.conf} ; do - if [ $# != 1 ] ; then - echo "== For configuration file $cnf:" - fi cnf_base=`basename $cnf` "$@" rc=$((rc|$?)) - if [ $# != 1 ] ; then - echo "== configuration file $cnf done" - fi done return $rc } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/script/unit-test.py new/booth/script/unit-test.py --- old/booth/script/unit-test.py 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/script/unit-test.py 2016-03-23 17:31:14.000000000 +0100 @@ -220,7 +220,7 @@ ]); logging.info("started booth with PID %d, lockfile %s" % (self.booth.pid, self.lockfile)) - self.booth.expect("BOOTH site daemon is starting", timeout=2) + self.booth.expect("BOOTH site \S+ \(build \S+\) daemon is starting", timeout=2) #print self.booth.before; exit self.gdb = self.start_a_process("gdb", @@ -471,14 +471,14 @@ comment = tkt.aux.get("comment", "") logging.info("ticket change %s (%s:%d) %s" % (ktkt, fn, self.current_nr, comment)) self.set_state(tkt) + if gdb: + for (k, v) in gdb.iteritems(): + self.send_cmd(k + " " + v.replace("§", "\n")) if msg: self.current_nr = msg.aux.get("line") comment = msg.aux.get("comment", "") logging.info("sending %s (%s:%d) %s" % (kmsg, fn, self.current_nr, comment)) self.send_message(self.merge_dicts(data["message"], msg)) - if gdb: - for (k, v) in gdb.iteritems(): - self.send_cmd(k + " " + v.replace("§", "\n")) if data.has_key(kgdb) and len(gdb) == 0: self.user_debug("manual override") if out: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/src/config.c new/booth/src/config.c --- old/booth/src/config.c 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/src/config.c 2016-03-23 17:31:14.000000000 +0100 @@ -330,7 +330,7 @@ } /* make arguments for execv(2) - * tk_test.prog points to the path + * tk_test.path points to the path * tk_test.argv is argument vector (starts with the prog) * (strtok pokes holes in the configuration parameter value, i.e. * we don't need to allocate memory for arguments) @@ -340,21 +340,21 @@ char *p; int i = 0; - if (tk_test.prog) { - free(tk_test.prog); + if (tk_test.path) { + free(tk_test.path); } - if (!(tk_test.prog = strdup(val))) { + if (!(tk_test.path = strdup(val))) { log_error("out of memory"); return -1; } - p = strtok(tk_test.prog, " \t"); + p = strtok(tk_test.path, " \t"); tk_test.argv[i++] = p; do { p = strtok(NULL, " \t"); if (i >= MAX_ARGS) { log_error("too many arguments for the acquire-handler"); - free(tk_test.prog); + free(tk_test.path); return -1; } tk_test.argv[i++] = p; @@ -509,7 +509,7 @@ strcpy(booth_conf->arb_group, "nobody"); parse_weights("", defaults.weight); - defaults.clu_test.prog = NULL; + defaults.clu_test.path = NULL; defaults.clu_test.pid = 0; defaults.clu_test.status = 0; defaults.clu_test.progstate = EXTPROG_IDLE; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/src/config.h new/booth/src/config.h --- old/booth/src/config.h 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/src/config.h 2016-03-23 17:31:14.000000000 +0100 @@ -97,7 +97,8 @@ /* Program to ask whether it makes sense to * acquire the ticket */ struct clu_test { - char *prog; + char *path; + int is_dir; char *argv[MAX_ARGS]; pid_t pid; int status; /* child exit status */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/src/handler.c new/booth/src/handler.c --- old/booth/src/handler.c 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/src/handler.c 2016-03-23 17:31:14.000000000 +0100 @@ -20,6 +20,8 @@ #include <string.h> #include <errno.h> #include <arpa/inet.h> +#include <signal.h> +#include <sys/wait.h> #include <inttypes.h> #include <stdio.h> #include <assert.h> @@ -61,6 +63,173 @@ } } +static void +run_ext_prog(struct ticket_config *tk, char *prog) +{ + if (set_booth_env(tk)) { + _exit(1); + } + closefiles(); /* don't leak open files */ + tk_log_debug("running handler %s", prog); + execv(prog, tk_test.argv); + tk_log_error("%s: execv failed (%s)", prog, strerror(errno)); + _exit(1); +} + +static int +prog_filter(const struct dirent *dp) +{ + return (*dp->d_name != '.'); +} + +static pid_t curr_pid; +static int ignore_status; + +static int +test_exit_status(struct ticket_config *tk, char *prog, int status, int log_msg) +{ + int rv = -1; + + if (WIFEXITED(status)) { + rv = WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + rv = 128 + WTERMSIG(status); + } + if (rv) { + if (log_msg) { + tk_log_warn("handler \"%s\" failed: %s", + prog, interpret_rv(status)); + tk_log_warn("we are not allowed to acquire ticket"); + } + } else { + tk_log_debug("handler \"%s\" exited with success", + prog); + } + return rv; +} + +static void +reset_test_state(struct ticket_config *tk) +{ + tk_test.pid = 0; + tk_test.progstate = EXTPROG_IDLE; +} + +int tk_test_exit_status(struct ticket_config *tk) +{ + int rv; + + rv = test_exit_status(tk, tk_test.path, tk_test.status, !tk_test.is_dir); + reset_test_state(tk); + return rv; +} + +void wait_child(int sig) +{ + int i, status; + struct ticket_config *tk; + + /* use waitpid(2) and not wait(2) in order not to interfear + * with popen(2)/pclose(2) and system(2) used in pacemaker.c + */ + foreach_ticket(i, tk) { + if (tk_test.path && tk_test.pid >= 0 && + (tk_test.progstate == EXTPROG_RUNNING || + tk_test.progstate == EXTPROG_IGNORE) && + waitpid(tk_test.pid, &status, WNOHANG) == tk_test.pid) { + if (tk_test.progstate == EXTPROG_IGNORE) { + /* not interested in the outcome */ + reset_test_state(tk); + } else { + tk_test.status = status; + tk_test.progstate = EXTPROG_EXITED; + } + } + } +} + +/* the parent may want to have us stop processing scripts, say + * when the ticket gets revoked + */ +static void ignore_rest(int sig) +{ + signal(SIGTERM, SIG_IGN); + log_info("external programs handler caught TERM, ignoring status of external test programs"); + ignore_status = 1; + if (curr_pid > 0) { + (void)kill(curr_pid, SIGTERM); + } +} + +void ext_prog_timeout(struct ticket_config *tk) +{ + tk_log_warn("handler timed out"); +} + +int is_ext_prog_running(struct ticket_config *tk) +{ + if (!tk_test.path) + return 0; + return (tk_test.pid > 0 && tk_test.progstate == EXTPROG_RUNNING); +} + +void ignore_ext_test(struct ticket_config *tk) +{ + if (is_ext_prog_running(tk)) { + (void)kill(tk_test.pid, SIGTERM); + tk_test.progstate = EXTPROG_IGNORE; + } +} + +static void +process_ext_dir(struct ticket_config *tk) +{ + char prog[FILENAME_MAX+1]; + int rv, n_progs, i, status; + struct dirent **proglist, *dp; + + signal(SIGTERM, (__sighandler_t)ignore_rest); + signal(SIGCHLD, SIG_DFL); + signal(SIGUSR1, SIG_DFL); + signal(SIGINT, SIG_DFL); + tk_log_debug("running programs in directory %s", tk_test.path); + n_progs = scandir(tk_test.path, &proglist, prog_filter, alphasort); + if (n_progs == -1) { + tk_log_error("%s: scandir failed (%s)", tk_test.path, strerror(errno)); + _exit(1); + } + for (i = 0; i < n_progs; i++) { + if (ignore_status) + break; + dp = proglist[i]; + if (strlen(dp->d_name) + strlen(tk_test.path) + 1 > FILENAME_MAX) { + tk_log_error("%s: name exceeds max length (%s)", + tk_test.path, dp->d_name); + _exit(1); + } + strcpy(prog, tk_test.path); + strcat(prog, "/"); + strcat(prog, dp->d_name); + switch(curr_pid=fork()) { + case -1: + log_error("fork: %s", strerror(errno)); + _exit(1); + case 0: /* child */ + run_ext_prog(tk, prog); + default: /* parent */ + while (waitpid(curr_pid, &status, 0) != curr_pid) + ; + curr_pid = 0; + if (!ignore_status) { + rv = test_exit_status(tk, prog, status, 1); + if (rv) + _exit(rv); + } + } + } + _exit(0); +} + /* run some external program * return codes: * RUNCMD_ERR: executing program failed (or some other failure) @@ -70,22 +239,27 @@ { int rv = 0; pid_t pid; + struct stat stbuf; - if (!tk_test.prog) + if (!tk_test.path) return 0; + if (stat(tk_test.path, &stbuf)) { + tk_log_error("%s: stat failed (%s)", tk_test.path, strerror(errno)); + return RUNCMD_ERR; + } + tk_test.is_dir = (stbuf.st_mode & S_IFDIR); + switch(pid=fork()) { case -1: log_error("fork: %s", strerror(errno)); return RUNCMD_ERR; case 0: /* child */ - if (set_booth_env(tk)) { - exit(1); + if (tk_test.is_dir) { + process_ext_dir(tk); + } else { + run_ext_prog(tk, tk_test.path); } - closefiles(); /* don't leak open files */ - execv(tk_test.prog, tk_test.argv); - tk_log_error("%s: execv failed (%s)", tk_test.prog, strerror(errno)); - exit(1); default: /* parent */ tk_test.pid = pid; tk_test.progstate = EXTPROG_RUNNING; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/src/handler.h new/booth/src/handler.h --- old/booth/src/handler.h 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/src/handler.h 2016-03-23 17:31:14.000000000 +0100 @@ -25,6 +25,11 @@ }; int run_handler(struct ticket_config *tk); +int tk_test_exit_status(struct ticket_config *tk); +void ignore_ext_test(struct ticket_config *tk); +int is_ext_prog_running(struct ticket_config *tk); +void ext_prog_timeout(struct ticket_config *tk); +void wait_child(int sig); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/src/main.c new/booth/src/main.c --- old/booth/src/main.c 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/src/main.c 2016-03-23 17:31:14.000000000 +0100 @@ -58,8 +58,9 @@ #include "ticket.h" #include "request.h" #include "attr.h" +#include "handler.h" -#define RELEASE_VERSION "0.2.0" +#define RELEASE_VERSION "1.0" #define RELEASE_STR RELEASE_VERSION " (build " BOOTH_BUILD_VERSION ")" #define CLIENT_NALLOC 32 @@ -1396,31 +1397,6 @@ exit(0); } -static void wait_child(int sig) -{ - int i, status; - struct ticket_config *tk; - - /* use waitpid(2) and not wait(2) in order not to interfear - * with popen(2)/pclose(2) and system(2) used in pacemaker.c - */ - foreach_ticket(i, tk) { - if (tk_test.prog && tk_test.pid >= 0 && - (tk_test.progstate == EXTPROG_RUNNING || - tk_test.progstate == EXTPROG_IGNORE) && - waitpid(tk_test.pid, &status, WNOHANG) == tk_test.pid) { - if (tk_test.progstate == EXTPROG_IGNORE) { - /* not interested in the outcome */ - tk_test.pid = 0; - tk_test.progstate = EXTPROG_IDLE; - } else { - tk_test.status = status; - tk_test.progstate = EXTPROG_EXITED; - } - } - } -} - static int do_server(int type) { int rv = -1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/src/ticket.c new/booth/src/ticket.c --- old/booth/src/ticket.c 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/src/ticket.c 2016-03-23 17:31:14.000000000 +0100 @@ -190,59 +190,6 @@ } } -/* Ask an external program whether getting the ticket - * makes sense. -* Eg. if the services have a failcount of INFINITY, -* we can't serve here anyway. */ -static int run_external_prog(struct ticket_config *tk, - int start_election) -{ - int rv; - - rv = run_handler(tk); - switch (rv) { - case RUNCMD_ERR: - tk_log_warn("couldn't run external test, not allowed to acquire ticket"); - ext_prog_failed(tk, start_election); - break; - case 0: - /* immediately returned with success */ - break; - case RUNCMD_MORE: - tk_log_debug("forked %s", tk_test.prog); - break; - default: - break; - } - - return rv; -} - -static int test_exit_status(struct ticket_config *tk, - int start_election) -{ - int rv = -1, status; - - status = tk_test.status; - if (WIFEXITED(status)) { - rv = WEXITSTATUS(status); - } else if (WIFSIGNALED(status)) { - rv = 128 + WTERMSIG(status); - } - if (rv) { - tk_log_warn("handler \"%s\" failed: %s", - tk_test.prog, interpret_rv(status)); - tk_log_warn("we are not allowed to acquire ticket"); - ext_prog_failed(tk, start_election); - } else { - tk_log_debug("handler \"%s\" exited with success", - tk_test.prog); - } - tk_test.pid = 0; - tk_test.progstate = EXTPROG_IDLE; - return rv; -} - #define attr_found(geo_ap, ap) \ ((geo_ap) && !strcmp((geo_ap)->val, (ap)->attr_val)) @@ -292,19 +239,26 @@ { int rv = 0; - if (!tk_test.prog) + if (!tk_test.path) return 0; switch(tk_test.progstate) { case EXTPROG_IDLE: - rv = run_external_prog(tk, start_election); + rv = run_handler(tk); + if (rv == RUNCMD_ERR) { + tk_log_warn("couldn't run external test, not allowed to acquire ticket"); + ext_prog_failed(tk, start_election); + } break; case EXTPROG_RUNNING: /* should never get here, but just in case */ rv = RUNCMD_MORE; break; case EXTPROG_EXITED: - rv = test_exit_status(tk, start_election); + rv = tk_test_exit_status(tk); + if (rv) { + ext_prog_failed(tk, start_election); + } break; case EXTPROG_IGNORE: /* nothing to do here */ @@ -376,15 +330,6 @@ } } -static void ignore_extprog(struct ticket_config *tk) -{ - if (tk_test.prog && tk_test.pid >= 0 && - tk_test.progstate == EXTPROG_RUNNING) { - tk_test.progstate = EXTPROG_IGNORE; - (void)kill(tk_test.pid, SIGTERM); - } -} - static void start_revoke_ticket(struct ticket_config *tk) { tk_log_info("revoking ticket"); @@ -392,7 +337,6 @@ save_committed_tkt(tk); reset_ticket(tk); set_leader(tk, no_leader); - ignore_extprog(tk); ticket_write(tk); ticket_broadcast(tk, OP_REVOKE, OP_ACK, RLT_SUCCESS, OR_ADMIN); } @@ -497,6 +441,7 @@ void reset_ticket(struct ticket_config *tk) { + ignore_ext_test(tk); disown_ticket(tk); no_resends(tk); set_state(tk, ST_INIT); @@ -943,8 +888,13 @@ if (tk->leader != local) { tk_log_warn("lost at %s", site_string(tk->leader)); } else { - tk_log_warn("lost majority (revoking locally)"); - reason = tk->election_reason ? tk->election_reason : OR_REACQUIRE; + if (is_ext_prog_running(tk)) { + ext_prog_timeout(tk); + reason = OR_LOCAL_FAIL; + } else { + tk_log_warn("lost majority (revoking locally)"); + reason = tk->election_reason ? tk->election_reason : OR_REACQUIRE; + } } tk->lost_leader = tk->leader; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/src/transport.c new/booth/src/transport.c --- old/booth/src/transport.c 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/src/transport.c 2016-03-23 17:31:14.000000000 +0100 @@ -102,12 +102,12 @@ if (matched == node->addrlen) { - /* Full match. */ + /* Exact match. */ +exact_match: *address_bits_matched = matched * 8; -found: *me = node; did_match = EXACT_MATCH; - continue; + break; } if (!fuzzy_allowed) @@ -120,14 +120,14 @@ if (matched * 8 < *address_bits_matched) continue; if (!bits_left) - goto found; + goto exact_match; node_bits = n_a[bytes]; ip_bits = ipaddr[bytes]; if (((node_bits ^ ip_bits) & mask) == 0) { /* _At_least_ prefixlen bits matched. */ - *address_bits_matched = prefixlen; if (did_match < EXACT_MATCH) { + *address_bits_matched = prefixlen; *me = node; did_match = FUZZY_MATCH; } @@ -769,7 +769,7 @@ * packet */ char buffer[MAX_MSG_LEN]; /* Used for unit tests */ - void *msg; + struct boothc_ticket_msg *msg; sa_len = sizeof(sa); @@ -781,7 +781,7 @@ if (rv == -1) return; - deliver_fn(msg, rv); + deliver_fn((void*)msg, rv); } static int booth_udp_init(void *f) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/unit-tests/020_ext-verifier.txt new/booth/unit-tests/020_ext-verifier.txt --- old/booth/unit-tests/020_ext-verifier.txt 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/unit-tests/020_ext-verifier.txt 2016-03-23 17:31:14.000000000 +0100 @@ -13,10 +13,11 @@ term_duration 3000 # but shall start renewal now term_expires time(0) + 1000 - ext_verifier "test `set|grep ^BOOTH|wc -l` -ge 5" - hb_sent_at time(0) - 10 + req_sent_at time(0) - 10 +gdb0: + call parse_extprog("test `set|grep ^BOOTH|wc -l` -ge 5", booth_conf->ticket+0) outgoing0: header.cmd OP_HEARTBEAT @@ -25,7 +26,7 @@ ticket1: ext_verifier 'test "$BOOTH_TICKET" == "tick1"' # cause re-query of the verifier - hb_sent_at time(0) - 10 + req_sent_at time(0) - 10 # #gdb1: @@ -40,7 +41,7 @@ ticket2: ext_verifier 'test "$BOOTH_TICKET" == "tick2FOO"' # cause re-query of the verifier - hb_sent_at time(0) - 10 + req_sent_at time(0) - 10 # We just tell the others we don't have it anymore. outgoing2: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/booth/unit-tests/_defaults.txt new/booth/unit-tests/_defaults.txt --- old/booth/unit-tests/_defaults.txt 2016-01-12 11:50:01.000000000 +0100 +++ new/booth/unit-tests/_defaults.txt 2016-03-23 17:31:14.000000000 +0100 @@ -15,14 +15,15 @@ # defaults for all tests state ST_INIT - next_cron 0 + next_cron.tv_sec 0 + # time(0)+1 # local is site[0] per convention leader booth_conf->site+1 #owner booth_conf->site+1 #expires time(0)+1 - term_expires time(0)+1 + term_expires.tv_sec time(0)+1 #last_ack_ballot 242 leader 0 @@ -51,5 +52,4 @@ ticket.leader -1 ticket.term 0 ticket.term_valid_for 0 - ticket.leader_commit -1
