diff --git a/agent/sbd b/agent/sbd.in similarity index 97% rename from agent/sbd rename to agent/sbd.in index 5645213..4bc0245 100644 --- a/agent/sbd +++ b/agent/sbd.in @@ -1,180 +1,180 @@ #!/bin/bash # # This STONITH script drives the shared-storage stonith plugin. # # Copyright (C) 2013 Lars Marowsky-Bree # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # Main code if [ -z "$sbd_device" ]; then - if [ -f /etc/sysconfig/sbd ]; then - source /etc/sysconfig/sbd + if [ -f @CONFIGDIR@/sbd ]; then + source @CONFIGDIR@/sbd sbd_device=$SBD_DEVICE fi fi SBD_DEVS=${sbd_device%;} sbd_device=${SBD_DEVS//;/ -d } sbd_check_device() { if [ -z "$sbd_device" ]; then ha_log.sh err "No sbd device(s) found in the configuration." exit 1 fi } sbd_validate_timeout() { case "$timeout_bypass" in yes|true|1|YES|TRUE|ja|on|ON) return ;; esac crm_timeout=$[$(crm_attribute -t crm_config -G -n stonith-timeout -d 20s -q | sed -e 's/\(.*\)s/\1/' -e 's/\(.*\)m/\1*60/')] sbd_timeout=$(sbd -d $sbd_device dump | perl -ne 'if (/msgwait.*: (\d+)/) { print "$1\n"; }' | head -n 1) if [ "$sbd_timeout" -eq "0" ]; then return fi sbd_timeout_min=$[$sbd_timeout*12/10] if [ "$sbd_timeout_min" -lt 20 ]; then sbd_timeout_min=20 fi sbd_timeout_suggested=$[$sbd_timeout_min*12/10] if [ "$crm_timeout" -lt "$sbd_timeout_min" ]; then ha_log.sh err "The CIB property stonith-timeout is set too low for sbd to ever succeed" ha_log.sh err "Recommended value is $sbd_timeout_suggested, updating configuration." crm_attribute -t crm_config -n stonith-timeout -v $sbd_timeout_suggested exit 1 fi } case $1 in gethosts) sbd_check_device echo `sbd -d $sbd_device list | cut -f2 | sort | uniq` exit 0 ;; off|reset) sbd_check_device sbd_validate_timeout message=$1 case "$crashdump" in yes|true|1|YES|TRUE|ja|on|ON) message="crashdump" ;; esac sbd -d $sbd_device message $2 $message exit $? ;; status) sbd_check_device sbd_validate_timeout if ! sbd -d $sbd_device list >/dev/null 2>&1 ; then ha_log.sh err "sbd could not list nodes from $sbd_device" exit 1 fi exit 0 ;; on) exit 1 ;; getconfignames) echo "sbd_device crashdump timeout_bypass" exit 0 ;; getinfo-devid) echo "Shared storage STONITH device" exit 0 ;; getinfo-devname) echo "Shared storage STONITH device" exit 0 ;; getinfo-devdescr) cat << DESC sbd uses a shared storage device as a medium to communicate fencing requests. This allows clusters without network power switches; the downside is that access to the shared storage device becomes a Single Point of Failure. It requires sbd to be configured on all nodes. Please read http://linux-ha.org/wiki/SBD_Fencing! DESC exit 0 ;; getinfo-devurl) echo "http://linux-ha.org/wiki/SBD_Fencing" exit 0 ;; getinfo-xml) cat << SSHXML Crashdump instead of regular fence If SBD is given a fence command, this option will instead perform a kernel crash of a reboot or power-off, which on a properly configured system can lead to a crashdump for analysis. This is less safe for production environments. Please use with caution and for debugging purposes only. SBD device(s) The block device used for the SBD partition. Up to three can be specified if separated by a semicolon. (Please check the documentation if specifying two.) -If not specified, will default to the value from /etc/sysconfig/sbd. +If not specified, will default to the value from @CONFIGDIR@/sbd. Permit a seemingly too short stonith-timeout The sbd agent will try to detect a too short stonith-timeout (relative to msgwait) in the Pacemaker configuration and automatically correct it. Should that logic fail in your environment or you have legitimate need to use a shorter timeout, you can disable it via this parameter. SSHXML exit 0 ;; *) exit 1 ;; esac diff --git a/configure.ac b/configure.ac index a7e3e70..46429d1 100644 --- a/configure.ac +++ b/configure.ac @@ -1,210 +1,222 @@ dnl dnl autoconf for Agents dnl dnl License: GNU General Public License (GPL) dnl =============================================== dnl Bootstrap dnl =============================================== AC_PREREQ(2.63) dnl Suggested structure: dnl information on the package dnl checks for programs dnl checks for libraries dnl checks for header files dnl checks for types dnl checks for structures dnl checks for compiler characteristics dnl checks for library functions dnl checks for system services AC_INIT([sbd], [1.3.0], [lmb@suse.com]) AC_CANONICAL_HOST AC_CONFIG_AUX_DIR(.) AC_CONFIG_HEADERS(config.h) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([no])]) AM_INIT_AUTOMAKE AM_PROG_CC_C_O PKG_CHECK_MODULES(glib, [glib-2.0]) dnl PKG_CHECK_MODULES(libcoroipcc, [libcoroipcc]) dnl pacemaker > 1.1.8 PKG_CHECK_MODULES(pacemaker, [pacemaker, pacemaker-cib], HAVE_pacemaker=1, HAVE_pacemaker=0) dnl pacemaker <= 1.1.8 PKG_CHECK_MODULES(pcmk, [pcmk, pcmk-cib], HAVE_pcmk=1, HAVE_pcmk=0) PKG_CHECK_MODULES(libqb, [libqb]) CPPFLAGS="$CPPFLAGS -Werror" if test $HAVE_pacemaker = 0 -a $HAVE_pcmk = 0; then AC_MSG_ERROR(No package 'pacemaker' found) elif test $HAVE_pacemaker = 1; then CPPFLAGS="$CPPFLAGS $glib_CFLAGS $pacemaker_CFLAGS" fi PKG_CHECK_MODULES(libxml, [libxml-2.0]) CPPFLAGS="$CPPFLAGS $libxml_CFLAGS $libqb_CFLAGS" dnl checks for libraries AC_CHECK_LIB(aio, io_setup, , missing="yes") AC_CHECK_LIB(qb, qb_ipcs_connection_auth_set, , missing="yes") AC_CHECK_LIB(cib, cib_new, , missing="yes") AC_CHECK_LIB(crmcommon, set_crm_log_level, , missing="yes") AC_CHECK_LIB(pe_status, pe_find_node, , missing="yes") AC_CHECK_LIB(pe_rules, test_rule, , missing="yes") AC_CHECK_LIB(crmcluster, crm_peer_init, , missing="yes") AC_CHECK_LIB(uuid, uuid_unparse, , missing="yes") dnl pacemaker >= 1.1.8 AC_CHECK_HEADERS(pacemaker/crm/cluster.h) AC_CHECK_LIB(crmcommon, pcmk_strerror, , missing="yes") AC_CHECK_LIB(cib, cib_apply_patch_event, , missing="yes") if test "$missing" = "yes"; then AC_MSG_ERROR([Missing required libraries or functions.]) fi AC_PATH_PROGS(POD2MAN, pod2man, pod2man) AC_ARG_ENABLE([shared-disk], [ --enable-shared-disk Turn on functionality that requires shared disk [default=yes]]) DISK=0 if test "x${enable_shared_disk}" != xno ; then DISK=1 fi AC_DEFINE_UNQUOTED(SUPPORT_SHARED_DISK, $DISK, Turn on functionality that requires shared disk) AM_CONDITIONAL(SUPPORT_SHARED_DISK, test "$DISK" = "1") if test -e /proc/$$ then echo "/proc/{pid} is supported" AC_DEFINE_UNQUOTED(HAVE_PROC_PID, 1, Define to 1 if /proc/{pid} is supported.) fi +CONFIGDIR="" +AC_ARG_WITH(configdir, + [ --with-configdir=DIR + Directory for SBD configuration file [${CONFIGDIR}]], + [ CONFIGDIR="$withval" ] +) + dnl ********************************************************************** dnl Check for various argv[] replacing functions on various OSs dnl dnl Borrowed from Proftpd dnl Proftpd is Licenced under the terms of the GNU General Public Licence dnl and is available from http://www.proftpd.org/ dnl AC_CHECK_FUNCS(setproctitle) AC_CHECK_HEADERS(libutil.h) AC_CHECK_LIB(util, setproctitle, [AC_DEFINE(HAVE_SETPROCTITLE,1,[ ]) ac_cv_func_setproctitle="yes" ; LIBS="$LIBS -lutil"]) if test "$ac_cv_func_setproctitle" = "yes"; then pf_argv_set="PF_ARGV_NONE" fi if test "$pf_argv_set" = ""; then AC_CHECK_HEADERS(sys/pstat.h) if test "$ac_cv_header_pstat_h" = "yes"; then AC_CHECK_FUNCS(pstat) if test "$ac_cv_func_pstat" = "yes"; then pf_argv_set="PF_ARGV_PSTAT" else pf_argv_set="PF_ARGV_WRITEABLE" fi fi if test "$pf_argv_set" = ""; then AC_EGREP_HEADER([#define.*PS_STRINGS.*],sys/exec.h, have_psstrings="yes",have_psstrings="no") if test "$have_psstrings" = "yes"; then pf_argv_set="PF_ARGV_PSSTRINGS" fi fi if test "$pf_argv_set" = ""; then AC_CACHE_CHECK(whether __progname and __progname_full are available, pf_cv_var_progname, AC_TRY_LINK([extern char *__progname, *__progname_full;], [__progname = "foo"; __progname_full = "foo bar";], pf_cv_var_progname="yes", pf_cv_var_progname="no")) if test "$pf_cv_var_progname" = "yes"; then AC_DEFINE(HAVE___PROGNAME,1,[ ]) fi AC_CACHE_CHECK(which argv replacement method to use, pf_cv_argv_type, AC_EGREP_CPP(yes,[ #if defined(__GNU_HURD__) yes #endif ],pf_cv_argv_type="new", pf_cv_argv_type="writeable")) if test "$pf_cv_argv_type" = "new"; then pf_argv_set="PF_ARGV_NEW" fi if test "$pf_argv_set" = ""; then pf_argv_set="PF_ARGV_WRITEABLE" fi fi fi AC_DEFINE_UNQUOTED(PF_ARGV_TYPE, $pf_argv_set, mechanism to pretty-print ps output: setproctitle-equivalent) dnl End of tests borrowed from Proftpd AC_MSG_NOTICE(Sanitizing prefix: ${prefix}) case $prefix in NONE) prefix=/usr dnl Fix default variables - "prefix" variable if not specified if test "$localstatedir" = "\${prefix}/var"; then localstatedir="/var" fi if test "$sysconfdir" = "\${prefix}/etc"; then sysconfdir="/etc" fi ;; esac AC_MSG_NOTICE(Sanitizing exec_prefix: ${exec_prefix}) case $exec_prefix in dnl For consistency with Heartbeat, map NONE->$prefix NONE) exec_prefix=$prefix;; prefix) exec_prefix=$prefix;; esac dnl Expand autoconf variables so that we dont end up with '${prefix}' dnl in #defines and python scripts dnl NOTE: Autoconf deliberately leaves them unexpanded to allow dnl make exec_prefix=/foo install dnl No longer being able to do this seems like no great loss to me... eval prefix="`eval echo ${prefix}`" eval exec_prefix="`eval echo ${exec_prefix}`" eval bindir="`eval echo ${bindir}`" eval sbindir="`eval echo ${sbindir}`" eval libexecdir="`eval echo ${libexecdir}`" eval datadir="`eval echo ${datadir}`" eval sysconfdir="`eval echo ${sysconfdir}`" eval sharedstatedir="`eval echo ${sharedstatedir}`" eval localstatedir="`eval echo ${localstatedir}`" eval libdir="`eval echo ${libdir}`" eval includedir="`eval echo ${includedir}`" eval oldincludedir="`eval echo ${oldincludedir}`" eval infodir="`eval echo ${infodir}`" eval mandir="`eval echo ${mandir}`" +if test x"${CONFIGDIR}" = x""; then + CONFIGDIR="${sysconfdir}/sysconfig" +fi +AC_SUBST(CONFIGDIR) + dnl The Makefiles and shell scripts we output -AC_CONFIG_FILES([Makefile src/Makefile agent/Makefile man/Makefile src/sbd.service src/sbd_remote.service]) +AC_CONFIG_FILES([Makefile src/Makefile agent/Makefile man/Makefile agent/sbd src/sbd.service src/sbd_remote.service src/sbd.sh]) dnl Now process the entire list of files added by previous dnl calls to AC_CONFIG_FILES() AC_OUTPUT() diff --git a/src/sbd.service.in b/src/sbd.service.in index a7f4e7f..ef1bd16 100644 --- a/src/sbd.service.in +++ b/src/sbd.service.in @@ -1,25 +1,25 @@ [Unit] Description=Shared-storage based fencing daemon Before=pacemaker.service After=systemd-modules-load.service iscsi.service PartOf=corosync.service RefuseManualStop=true RefuseManualStart=true [Service] Type=forking PIDFile=@localstatedir@/run/sbd.pid -EnvironmentFile=-@sysconfdir@/sysconfig/sbd -ExecStart=@sbindir@/sbd $SBD_OPTS -p @localstatedir@/run/sbd.pid watch +EnvironmentFile=-@CONFIGDIR@/sbd +ExecStart=@sbindir@/sbd $SBD_OPTS -p @localstatedir@/run/sbd.pid watch ExecStop=@bindir@/kill -TERM $MAINPID # Could this benefit from exit codes for restart? # Does this need to be set to msgwait * 1.2? # TimeoutSec= # If SBD crashes, it'll very likely suicide immediately due to the # hardware watchdog. But one can always try. Restart=on-abort [Install] RequiredBy=corosync.service diff --git a/src/sbd.sh b/src/sbd.sh.in similarity index 98% rename from src/sbd.sh rename to src/sbd.sh.in index 35b0e92..386f89b 100644 --- a/src/sbd.sh +++ b/src/sbd.sh.in @@ -1,103 +1,103 @@ #!/bin/bash # # Copyright (C) 2013 Lars Marowsky-Bree # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -SBD_CONFIG=/etc/sysconfig/sbd +SBD_CONFIG=@CONFIGDIR@/sbd SBD_BIN="/usr/sbin/sbd" test -x $SBD_BIN || exit 1 test -f $SBD_CONFIG || exit 1 . $SBD_CONFIG unset LC_ALL; export LC_ALL unset LANGUAGE; export LANGUAGE : ${OCF_ROOT:=/usr/lib/ocf} : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs # Construct commandline for some common options if [ -z "$SBD_DEVICE" ]; then echo "No sbd devices defined" exit 1 fi SBD_DEVS=${SBD_DEVICE%;} SBD_DEVICE_ARGS="-d ${SBD_DEVS//;/ -d }" : ${SBD_PIDFILE:=/var/run/sbd.pid} SBD_OPTS+=" -p $SBD_PIDFILE" : ${SBD_PACEMAKER:="true"} if ocf_is_true "$SBD_PACEMAKER" ; then SBD_OPTS+=" -P" fi : ${SBD_WATCHDOG:="true"} if ! ocf_is_true "$SBD_WATCHDOG" ; then SBD_OPTS+=" -W -W" fi if [ -n "$SBD_WATCHDOG_DEV" ]; then SBD_OPTS+=" -w $SBD_WATCHDOG_DEV" fi : ${SBD_STARTMODE:="always"} case "$SBD_STARTMODE" in always) SBD_OPTS+=" -S 0" ;; clean) SBD_OPTS+=" -S 1" ;; esac : ${SBD_DELAY_START:="no"} start() { if ! pidofproc -p $SBD_PIDFILE $SBD_BIN >/dev/null 2>&1 ; then if ! $SBD_BIN $SBD_DEVICE_ARGS $SBD_OPTS watch ; then echo "SBD failed to start; aborting." exit 1 fi if ocf_is_true ${SBD_DELAY_START} ; then sleep $($SBD_BIN $SBD_DEVICE_ARGS dump | grep -m 1 msgwait | awk '{print $4}') 2>/dev/null fi else return 0 fi } stop() { if ! $SBD_BIN $SBD_DEVICE_ARGS -D $SBD_OPTS message LOCAL exit ; then echo "SBD failed to stop; aborting." exit 1 fi while pidofproc -p $SBD_PIDFILE $SBD_BIN >/dev/null 2>&1 ; do sleep 1 done } case "$1" in start|stop) $1 ;; *) echo "Usage: $0 (start|stop)" exit 1 ;; esac # TODO: # - Make openais init script call out to this script too # - How to handle the former "force-start" option? # force-start) # SBD_OPTS="$SBD_OPTS -S 0" # start # ;; diff --git a/src/sbd_remote.service.in b/src/sbd_remote.service.in index 73eaa89..e05f80e 100644 --- a/src/sbd_remote.service.in +++ b/src/sbd_remote.service.in @@ -1,24 +1,24 @@ [Unit] Description=Shared-storage based fencing daemon on pacemaker remote node After=systemd-modules-load.service iscsi.service PartOf=pacemaker_remote.service RefuseManualStop=true RefuseManualStart=true [Service] Type=forking -PIDFile=/var/run/sbd.pid -EnvironmentFile=-/etc/sysconfig/sbd -ExecStart=/usr/sbin/sbd $SBD_OPTS -p /var/run/sbd.pid watch -ExecStop=/usr/bin/kill -TERM $MAINPID +PIDFile=@localstatedir@/run/sbd.pid +EnvironmentFile=-@CONFIGDIR@/sbd +ExecStart=@sbindir@/sbd $SBD_OPTS -p @localstatedir@/run/sbd.pid watch +ExecStop=@bindir@/kill -TERM $MAINPID # Could this benefit from exit codes for restart? # Does this need to be set to msgwait * 1.2? # TimeoutSec= # If SBD crashes, it'll very likely suicide immediately due to the # hardware watchdog. But one can always try. Restart=on-abort [Install] RequiredBy=pacemaker_remote.service