diff --git a/Makefile.am b/Makefile.am index 573438f5b..67de93da1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,194 +1,196 @@ # # Copyright (C) 2008 Andrew Beekhof # Copyright (C) 2011 Fabio M. Di Nitto # # 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 program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure DRF/config-h.in \ missing install-sh autoscan.log configure.scan \ DRF/stamp-h.in libtool.m4 ltdl.m4 libltdl.tar \ compile config.guess config.sub depcomp ACLOCAL_AMFLAGS = -I m4 SPEC = $(PACKAGE_NAME).spec TARFILES = $(PACKAGE_NAME)-$(VERSION).tar.bz2 \ $(PACKAGE_NAME)-$(VERSION).tar.gz SUBDIRS = if BUILD_RGMANAGER SUBDIRS += rgmanager RGMANAGER = without else RGMANAGER = with endif if BUILD_LINUX_HA SUBDIRS += include heartbeat tools ldirectord doc systemd LINUX_HA = without else LINUX_HA = with endif if WITH_COMPAT_HABINDIR COMPAT_HABINDIR = without else COMPAT_HABINDIR = with endif pkgconfigdir = $(datadir)/pkgconfig pkgconfig_DATA = $(PACKAGE_NAME).pc EXTRA_DIST = autogen.sh .version ci make/release.mk \ make/git-version-gen make/gitlog-to-changelog \ AUTHORS COPYING COPYING.GPLv3 COPYING.LGPL ChangeLog \ $(pkgconfig_DATA).in $(SPEC).in install-exec-local: if BUILD_LINUX_HA $(INSTALL) -d -m 1755 $(DESTDIR)$(HA_RSCTMPDIR) $(LN_S) -f ../../lib/heartbeat/ocf-binaries $(DESTDIR)${OCF_RA_DIR_PREFIX}/heartbeat/.ocf-binaries $(LN_S) -f ../../lib/heartbeat/ocf-directories $(DESTDIR)${OCF_RA_DIR_PREFIX}/heartbeat/.ocf-directories $(LN_S) -f ../../lib/heartbeat/ocf-returncodes $(DESTDIR)${OCF_RA_DIR_PREFIX}/heartbeat/.ocf-returncodes $(LN_S) -f ../../lib/heartbeat/ocf-shellfuncs $(DESTDIR)${OCF_RA_DIR_PREFIX}/heartbeat/.ocf-shellfuncs endif if BUILD_RGMANAGER if BUILD_LINUX_HA $(LN_S) -n -f ${CLUSTERDATA} $(DESTDIR)${OCF_RA_DIR_PREFIX}/redhat endif $(INSTALL) -d $(DESTDIR)/$(LOGDIR) endif dist-clean-local: rm -f autoconf automake autoheader $(TARFILES) uninstall-local: rmdir $(DESTDIR)/$(LOGDIR) || :; if BUILD_LINUX_HA rm -f $(DESTDIR)${OCF_RA_DIR_PREFIX}/heartbeat/.ocf-binaries rm -f $(DESTDIR)${OCF_RA_DIR_PREFIX}/heartbeat/.ocf-directories rm -f $(DESTDIR)${OCF_RA_DIR_PREFIX}/heartbeat/.ocf-returncodes rm -f $(DESTDIR)${OCF_RA_DIR_PREFIX}/heartbeat/.ocf-shellfuncs if BUILD_RGMANAGER rm -f $(DESTDIR)${OCF_RA_DIR_PREFIX}/redhat endif endif BUILT_SOURCES = .version .version: echo $(VERSION) > $@-t && mv $@-t $@ dist-hook: gen-ChangeLog $(SPEC) echo $(VERSION) > $(distdir)/.tarball-version rm -f $(distdir)/$(SPEC) && \ cp $(top_srcdir)/$(SPEC) $(distdir)/$(SPEC) gen_start_date = 2000-01-01 .PHONY: gen-ChangeLog gen-ChangeLog: if test -d .git; then \ LC_ALL=C $(top_srcdir)/make/gitlog-to-changelog \ --since=$(gen_start_date) > $(distdir)/cl-t; \ rm -f $(distdir)/ChangeLog.devel; \ mv $(distdir)/cl-t $(distdir)/ChangeLog.devel; \ fi ## make rpm/srpm section. $(SPEC): $(SPEC).in rm -f $@-t $@ date="$(shell LC_ALL=C date "+%a %b %d %Y")" && \ specver="1" && \ rcver="" && \ dirty="" && \ alphatag="" && \ numcomm="" && \ ver="$(VERSION)" && \ if echo $$ver | grep -q -- "-dirty$$"; then \ dirty="dirty" && \ echo VERSION IS DIRTY && \ ver=`echo $$ver | sed -e "s/-dirty$$//"`; \ fi && \ echo $$ver && \ if echo $$ver | grep -q -- "-"; then \ alphatag=`echo $$ver | sed -e "s/.*-//"` && \ echo VERSION HAS ALPHATAG && \ ver=`echo $$ver | sed -e "s/-.*//"`; \ fi && \ echo $$ver && \ if [ -n "$$alphatag" ]; then \ echo VERSION HAS NUMCOMMITS && \ numcomm=`echo $$ver | sed -e 's/.*\.//'` && \ ver=`echo $$ver | sed -e 's/.'$$numcomm'$$//'`; \ fi && \ if echo $$ver | grep -q "\.[[:digit:]]rc[[:digit:]]"; then \ rpmver=`echo $$ver | sed -e "s/rc[[:digit:]].*//g"` && \ rcver=`echo $$ver | sed -e "s/.*\(rc[[:digit:]]\).*/\1/g"` && \ specver="0"; \ else \ rpmver=$$ver; \ fi && \ echo $$rpmver $$rcver && \ sed \ -e "s#@version@#$$rpmver#g" \ -e "s#@alphatag@#$$alphatag#g" \ -e "s#@numcomm@#$$numcomm#g" \ -e "s#@dirty@#$$dirty#g" \ -e "s#@date@#$$date#g" \ -e "s#@specver@#$$specver#g" \ -e "s#@rcver@#$$rcver#g" \ -e "s#@rgmanager@#$(RGMANAGER)#g" \ -e "s#@linux-ha@#$(LINUX_HA)#g" \ -e "s#@compat-habindir@#$(COMPAT_HABINDIR)#g" \ $< > $@-t; \ if [ -z "$$dirty" ]; then sed -i -e "s#%glo.*dirty.*##g" $@-t; fi; \ if [ -z "$$alphatag" ]; then sed -i -e "s#%glo.*alphatag.*##g" $@-t; fi; \ if [ -z "$$numcomm" ]; then sed -i -e "s#%glo.*numcomm.*##g" $@-t; fi; \ if [ -z "$$rcver" ]; then sed -i -e "s#%glo.*rcver.*##g" $@-t; fi chmod a-w $@-t mv $@-t $@ $(TARFILES): $(MAKE) dist RPMBUILDOPTS = --define "_sourcedir $(abs_builddir)" \ --define "_specdir $(abs_builddir)" \ --define "_builddir $(abs_builddir)" \ --define "_srcrpmdir $(abs_builddir)" \ --define "_rpmdir $(abs_builddir)" srpm: clean $(MAKE) $(SPEC) $(TARFILES) rpmbuild $(RPMBUILDOPTS) --nodeps -bs $(SPEC) rpm: clean $(MAKE) $(SPEC) $(TARFILES) rpmbuild $(RPMBUILDOPTS) -ba $(SPEC) check-local: +if CI_CHECKS $(top_srcdir)/ci/build.sh check +endif spellcheck: make/spellcheck-ignore if BUILD_LINUX_HA $(MAKE) -C heartbeat $@ endif if BUILD_RGMANAGER : not implemented for RGManager-compat agents endif clean-generic: rm -rf $(SPEC) $(TARFILES) $(PACKAGE_NAME)-$(VERSION) *.rpm diff --git a/configure.ac b/configure.ac index 058c0f1da..c69aac22c 100644 --- a/configure.ac +++ b/configure.ac @@ -1,1074 +1,1076 @@ 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([resource-agents], m4_esyscmd([make/git-version-gen .tarball-version]), [developers@clusterlabs.org]) AC_USE_SYSTEM_EXTENSIONS CRM_DTD_VERSION="1.0" AC_CONFIG_AUX_DIR(.) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_HOST dnl Where #defines go (e.g. `AC_CHECK_HEADERS' below) dnl dnl Internal header: include/config.h dnl - Contains ALL defines dnl - include/config.h.in is generated automatically by autoheader dnl - NOT to be included in any header files except lha_internal.h dnl (which is also not to be included in any other header files) dnl dnl External header: include/agent_config.h dnl - Contains a subset of defines checked here dnl - Manually edit include/agent_config.h.in to have configure include new defines dnl - Should not include HAVE_* defines dnl - Safe to include anywhere AM_CONFIG_HEADER(include/config.h include/agent_config.h) ALL_LINGUAS="en fr" AC_ARG_WITH(version, [ --with-version=version Override package version (if you're a packager needing to pretend) ], [ PACKAGE_VERSION="$withval" ]) AC_ARG_WITH(pkg-name, [ --with-pkg-name=name Override package name (if you're a packager needing to pretend) ], [ PACKAGE_NAME="$withval" ]) dnl dnl AM_INIT_AUTOMAKE([1.11.1 foreign dist-bzip2 dist-xz]) dnl AM_INIT_AUTOMAKE([1.10.1 foreign dist-bzip2]) AC_DEFINE_UNQUOTED(AGENTS_VERSION, "$PACKAGE_VERSION", Current agents version) CC_IN_CONFIGURE=yes export CC_IN_CONFIGURE LDD=ldd dnl ======================================================================== dnl Compiler characteristics dnl ======================================================================== # check stolen from gnulib/m4/gnu-make.m4 if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then AC_MSG_ERROR([you don't seem to have GNU make; it is required]) fi AC_PROG_CC dnl Can force other with environment variable "CC". AM_PROG_CC_C_O AC_PROG_CC_STDC AC_PROG_AWK AC_PROG_LN_S AC_PROG_INSTALL AC_PROG_MAKE_SET AC_C_STRINGIZE AC_C_INLINE AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UID_T AC_TYPE_UINT16_T AC_TYPE_UINT8_T AC_TYPE_UINT32_T AC_CHECK_SIZEOF(char) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) AC_STRUCT_TIMEZONE dnl =============================================== dnl Helpers dnl =============================================== cc_supports_flag() { local CPPFLAGS="$@" AC_MSG_CHECKING(whether $CC supports "$@") AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])], [RC=0; AC_MSG_RESULT([yes])], [RC=1; AC_MSG_RESULT([no])]) return $RC } extract_header_define() { AC_MSG_CHECKING(for $2 in $1) Cfile=$srcdir/extract_define.$2.${$} printf "#include \n" > ${Cfile}.c printf "#include <%s>\n" $1 >> ${Cfile}.c printf "int main(int argc, char **argv) { printf(\"%%s\", %s); return 0; }\n" $2 >> ${Cfile}.c $CC $CFLAGS ${Cfile}.c -o ${Cfile} value=`${Cfile}` AC_MSG_RESULT($value) printf $value rm -f ${Cfile}.c ${Cfile} } 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 # ordering is important, PKG_PROG_PKG_CONFIG is to be invoked before any other PKG_* related stuff PKG_PROG_PKG_CONFIG(0.18) # PKG_CHECK_MODULES will fail if systemd is not found by default, so make sure # we set the proper vars and deal with it PKG_CHECK_MODULES([systemd], [systemd], [HAS_SYSTEMD=yes], [HAS_SYSTEMD=no]) if test "x$HAS_SYSTEMD" == "xyes"; then PKG_CHECK_VAR([SYSTEMD_UNIT_DIR], [systemd], [systemdsystemunitdir]) if test "x$SYSTEMD_UNIT_DIR" == "x"; then AC_MSG_ERROR([Unable to detect systemd unit dir automatically]) fi PKG_CHECK_VAR([SYSTEMD_TMPFILES_DIR], [systemd], [tmpfilesdir]) if test "x$SYSTEMD_TMPFILES_DIR" == "x"; then AC_MSG_ERROR([Unable to detect systemd tmpfiles directory automatically]) fi # sanitize systed vars when using non standard prefix if test "$prefix" != "/usr"; then SYSTEMD_UNIT_DIR="$prefix/$SYSTEMD_UNIT_DIR" AC_SUBST([SYSTEMD_UNIT_DIR]) SYSTEMD_TMPFILES_DIR="$prefix/$SYSTEMD_TMPFILES_DIR" AC_SUBST([SYSTEMD_TMPFILES_DIR]) fi fi AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$HAS_SYSTEMD" == xyes ]) dnl =============================================== dnl Configure Options dnl =============================================== dnl Some systems, like Solaris require a custom package name AC_ARG_WITH(pkgname, [ --with-pkgname=name name for pkg (typically for Solaris) ], [ PKGNAME="$withval" ], [ PKGNAME="LXHAhb" ], ) AC_SUBST(PKGNAME) AC_ARG_ENABLE([ansi], [ --enable-ansi force GCC to compile to ANSI/ANSI standard for older compilers. [default=yes]]) AC_ARG_ENABLE([fatal-warnings], [ --enable-fatal-warnings very pedantic and fatal warnings for gcc [default=yes]]) INITDIR="" AC_ARG_WITH(initdir, [ --with-initdir=DIR directory for init (rc) scripts [${INITDIR}]], [ INITDIR="$withval" ]) OCF_ROOT_DIR="${prefix}/lib/ocf" AC_ARG_WITH(ocf-root, [ --with-ocf-root=DIR directory for OCF scripts [${OCF_ROOT_DIR}]], [ OCF_ROOT_DIR="$withval" ]) HA_RSCTMPDIR=${localstatedir}/run/resource-agents AC_ARG_WITH(rsctmpdir, [ --with-rsctmpdir=DIR directory for resource agents state files [${HA_RSCTMPDIR}]], [ HA_RSCTMPDIR="$withval" ]) AC_ARG_ENABLE([libnet], [ --enable-libnet Use libnet for ARP based funcationality, [default=try]], [enable_libnet="$enableval"], [enable_libnet=try]) BUILD_RGMANAGER=0 BUILD_LINUX_HA=0 RASSET=linux-ha AC_ARG_WITH(ras-set, [ --with-ras-set=SET build/install only linux-ha, rgmanager or all resource-agents [default: linux-ha]], [ RASSET="$withval" ]) if test x$RASSET = xyes || test x$RASSET = xall ; then BUILD_RGMANAGER=1 BUILD_LINUX_HA=1 fi if test x$RASSET = xlinux-ha; then BUILD_LINUX_HA=1 fi if test x$RASSET = xrgmanager; then BUILD_RGMANAGER=1 fi if test $BUILD_LINUX_HA -eq 0 && test $BUILD_RGMANAGER -eq 0; then AC_MSG_ERROR([Are you really sure you want this package?]) exit 1 fi AM_CONDITIONAL(BUILD_LINUX_HA, test $BUILD_LINUX_HA -eq 1) AM_CONDITIONAL(BUILD_RGMANAGER, test $BUILD_RGMANAGER -eq 1) AC_ARG_WITH(compat-habindir, [ --with-compat-habindir use HA_BIN directory with compatibility for the Heartbeat stack [${libexecdir}]], [], [with_compat_habindir=no]) AM_CONDITIONAL(WITH_COMPAT_HABINDIR, test "x$with_compat_habindir" != "xno") dnl =============================================== dnl General Processing dnl =============================================== echo Our Host OS: $host_os/$host 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 AC_MSG_NOTICE(Sanitizing INITDIR: ${INITDIR}) case $INITDIR in prefix) INITDIR=$prefix;; "") AC_MSG_CHECKING(which init (rc) directory to use) for initdir in /etc/init.d /etc/rc.d/init.d /sbin/init.d \ /usr/local/etc/rc.d /etc/rc.d do if test -d $initdir then INITDIR=$initdir break fi done if test -z $INITDIR then INITDIR=${sysconfdir}/init.d fi AC_MSG_RESULT($INITDIR);; esac AC_SUBST(INITDIR) if test "${prefix}" = "/usr"; then INITDIRPREFIX="$INITDIR" else INITDIRPREFIX="${prefix}/$INITDIR" fi AC_SUBST(INITDIRPREFIX) AC_MSG_NOTICE(Sanitizing libdir: ${libdir}) case $libdir in dnl For consistency with Heartbeat, map NONE->$prefix *prefix*|NONE) AC_MSG_CHECKING(which lib directory to use) for aDir in lib64 lib do trydir="${exec_prefix}/${aDir}" if test -d ${trydir} then libdir=${trydir} break fi done AC_MSG_RESULT($libdir); ;; esac if test "x$with_compat_habindir" != "xno" ; then libexecdir=${libdir} fi 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}`" dnl docdir is a recent addition to autotools eval docdir="`eval echo ${docdir}`" if test "x$docdir" = "x"; then docdir="`eval echo ${datadir}/doc`" fi AC_SUBST(docdir) dnl Home-grown variables eval INITDIR="${INITDIR}" for j in prefix exec_prefix bindir sbindir libexecdir datadir sysconfdir \ sharedstatedir localstatedir libdir includedir oldincludedir infodir \ mandir INITDIR docdir do dirname=`eval echo '${'${j}'}'` if test ! -d "$dirname" then AC_MSG_WARN([$j directory ($dirname) does not exist!]) fi done dnl This OS-based decision-making is poor autotools practice; dnl feature-based mechanisms are strongly preferred. dnl dnl So keep this section to a bare minimum; regard as a "necessary evil". REBOOT_OPTIONS="-f" POWEROFF_OPTIONS="-f" case "$host_os" in *bsd*) LIBS="-L/usr/local/lib" CPPFLAGS="$CPPFLAGS -I/usr/local/include" ;; *solaris*) REBOOT_OPTIONS="-n" POWEROFF_OPTIONS="-n" LDFLAGS+=" -lssp -lssp_nonshared" ;; *linux*) AC_DEFINE_UNQUOTED(ON_LINUX, 1, Compiling for Linux platform) POWEROFF_OPTIONS="-nf" REBOOT_OPTIONS="-nf" ;; darwin*) AC_DEFINE_UNQUOTED(ON_DARWIN, 1, Compiling for Darwin platform) LIBS="$LIBS -L${prefix}/lib" CFLAGS="$CFLAGS -I${prefix}/include" ;; esac AC_DEFINE_UNQUOTED(HA_LOG_FACILITY, LOG_DAEMON, Default logging facility) AC_MSG_NOTICE(Host CPU: $host_cpu) case "$host_cpu" in ppc64|powerpc64) case $CFLAGS in *powerpc64*) ;; *) if test "$GCC" = yes; then CFLAGS="$CFLAGS -m64" fi ;; esac esac AC_MSG_CHECKING(which format is needed to print uint64_t) case "$host_cpu" in s390x)U64T="%lu";; *64*) U64T="%lu";; *) U64T="%llu";; esac AC_MSG_RESULT($U64T) AC_DEFINE_UNQUOTED(U64T, "$U64T", Correct printf format for logging uint64_t) dnl Variables needed for substitution AC_CHECK_HEADERS(heartbeat/glue_config.h) if test "$ac_cv_header_heartbeat_glue_config_h" != "yes"; then enable_libnet=no fi AC_DEFINE_UNQUOTED(OCF_ROOT_DIR,"$OCF_ROOT_DIR", OCF root directory - specified by the OCF standard) AC_SUBST(OCF_ROOT_DIR) GLUE_STATE_DIR=${localstatedir}/run AC_DEFINE_UNQUOTED(GLUE_STATE_DIR,"$GLUE_STATE_DIR", Where to keep state files and sockets) AC_SUBST(GLUE_STATE_DIR) AC_DEFINE_UNQUOTED(HA_VARRUNDIR,"$GLUE_STATE_DIR", Where Heartbeat keeps state files and sockets - old name) HA_VARRUNDIR="$GLUE_STATE_DIR" AC_SUBST(HA_VARRUNDIR) # Expand $prefix eval HA_RSCTMPDIR="`eval echo ${HA_RSCTMPDIR}`" AC_DEFINE_UNQUOTED(HA_RSCTMPDIR,"$HA_RSCTMPDIR", Where Resource agents keep state files) AC_SUBST(HA_RSCTMPDIR) dnl Eventually move out of the heartbeat dir tree and create symlinks when needed HA_VARLIBHBDIR=${localstatedir}/lib/heartbeat AC_DEFINE_UNQUOTED(HA_VARLIBHBDIR,"$HA_VARLIBHBDIR", Whatever this used to mean) AC_SUBST(HA_VARLIBHBDIR) OCF_RA_DIR="${OCF_ROOT_DIR}/resource.d" AC_DEFINE_UNQUOTED(OCF_RA_DIR,"$OCF_RA_DIR", Location for OCF RAs) AC_SUBST(OCF_RA_DIR) OCF_RA_DIR_PREFIX="$OCF_RA_DIR" AC_SUBST(OCF_RA_DIR_PREFIX) OCF_LIB_DIR="${OCF_ROOT_DIR}/lib" AC_DEFINE_UNQUOTED(OCF_LIB_DIR,"$OCF_LIB_DIR", Location for shared code for OCF RAs) AC_SUBST(OCF_LIB_DIR) OCF_LIB_DIR_PREFIX="$OCF_LIB_DIR" AC_SUBST(OCF_LIB_DIR_PREFIX) dnl =============================================== dnl rgmanager ras bits dnl =============================================== LOGDIR=${localstatedir}/log/cluster CLUSTERDATA=${datadir}/cluster AC_SUBST([LOGDIR]) AC_SUBST([CLUSTERDATA]) dnl =============================================== dnl Program Paths dnl =============================================== PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin" export PATH AC_CHECK_PROGS(MAKE, gmake make) +AC_CHECK_PROGS(SHELLCHECK, shellcheck) +AM_CONDITIONAL(CI_CHECKS, test "x$SHELLCHECK" != "x" ) AC_PATH_PROGS(BASH_SHELL, bash) if test x"${BASH_SHELL}" = x""; then AC_MSG_ERROR(You need bash installed in order to build ${PACKAGE}) fi AC_PATH_PROGS(XSLTPROC, xsltproc) AM_CONDITIONAL(BUILD_DOC, test "x$XSLTPROC" != "x" ) if test "x$XSLTPROC" = "x"; then AC_MSG_WARN([xsltproc not installed, unable to (re-)build manual pages]) fi AC_SUBST(XSLTPROC) AC_PATH_PROGS(XMLCATALOG, xmlcatalog) AC_PATH_PROGS(SSH, ssh, /usr/bin/ssh) AC_PATH_PROGS(SCP, scp, /usr/bin/scp) AC_PATH_PROGS(TAR, tar) AC_PATH_PROGS(MD5, md5) AC_PATH_PROGS(TEST, test) AC_PATH_PROGS(PING, ping, /bin/ping) AC_PATH_PROGS(IFCONFIG, ifconfig, /sbin/ifconfig) AC_PATH_PROGS(MAILCMD, mailx mail, mail) AC_PATH_PROGS(EGREP, egrep) AC_PATH_PROGS(RM, rm) AC_SUBST(BASH_SHELL) AC_SUBST(MAILCMD) AC_SUBST(EGREP) AC_SUBST(SHELL) AC_SUBST(PING) AC_SUBST(RM) AC_SUBST(TEST) dnl Ensure PYTHON is an absolute path AC_PATH_PROG([PYTHON], [$PYTHON]) AM_PATH_PYTHON if test -z "$PYTHON"; then echo "*** Essential program python not found" 1>&2 fi AC_PYTHON_MODULE(googleapiclient) AC_PYTHON_MODULE(json) AC_PYTHON_MODULE(pyroute2) AS_VERSION_COMPARE([$PYTHON_VERSION], [2.7], [BUILD_OCF_PY=0], [BUILD_OCF_PY=1], [BUILD_OCF_PY=1]) BUILD_AZURE_EVENTS=1 if test -z "$PYTHON" || test $BUILD_OCF_PY -eq 0; then BUILD_AZURE_EVENTS=0 AC_MSG_WARN("Not building azure-events") fi AM_CONDITIONAL(BUILD_AZURE_EVENTS, test $BUILD_AZURE_EVENTS -eq 1) BUILD_GCP_PD_MOVE=1 if test -z "$PYTHON" || test "x${HAVE_PYMOD_GOOGLEAPICLIENT}" != xyes || test $BUILD_OCF_PY -eq 0; then BUILD_GCP_PD_MOVE=0 AC_MSG_WARN("Not building gcp-pd-move") fi AM_CONDITIONAL(BUILD_GCP_PD_MOVE, test $BUILD_GCP_PD_MOVE -eq 1) BUILD_GCP_VPC_MOVE_ROUTE=1 if test -z "$PYTHON" || test "x${HAVE_PYMOD_GOOGLEAPICLIENT}" != xyes || \ test "x${HAVE_PYMOD_PYROUTE2}" != xyes || test $BUILD_OCF_PY -eq 0; then BUILD_GCP_VPC_MOVE_ROUTE=0 AC_MSG_WARN("Not building gcp-vpc-move-route") fi AM_CONDITIONAL(BUILD_GCP_VPC_MOVE_ROUTE, test $BUILD_GCP_VPC_MOVE_ROUTE -eq 1) BUILD_GCP_VPC_MOVE_VIP=1 if test -z "$PYTHON" || test "x${HAVE_PYMOD_GOOGLEAPICLIENT}" != xyes || test $BUILD_OCF_PY -eq 0; then BUILD_GCP_VPC_MOVE_VIP=0 AC_MSG_WARN("Not building gcp-vpc-move-vip") fi AM_CONDITIONAL(BUILD_GCP_VPC_MOVE_VIP, test $BUILD_GCP_VPC_MOVE_VIP -eq 1) AC_PATH_PROGS(ROUTE, route) AC_DEFINE_UNQUOTED(ROUTE, "$ROUTE", path to route command) AC_MSG_CHECKING(ifconfig option to list interfaces) for IFCONFIG_A_OPT in "-A" "-a" "" do $IFCONFIG $IFCONFIG_A_OPT > /dev/null 2>&1 if test "$?" = 0 then AC_DEFINE_UNQUOTED(IFCONFIG_A_OPT, "$IFCONFIG_A_OPT", option for ifconfig command) AC_MSG_RESULT($IFCONFIG_A_OPT) break fi done AC_SUBST(IFCONFIG_A_OPT) if test x"${MAKE}" = x""; then AC_MSG_ERROR(You need (g)make installed in order to build ${PACKAGE}) fi STYLESHEET_PREFIX="" if test x"${XSLTPROC}" != x""; then AC_MSG_CHECKING(docbook to manpage transform) # first try to figure out correct template using xmlcatalog query, # resort to extensive (semi-deterministic) file search if that fails DOCBOOK_XSL_URI='http://docbook.sourceforge.net/release/xsl/current' DOCBOOK_XSL_PATH='manpages/docbook.xsl' STYLESHEET_PREFIX=$(${XMLCATALOG} "" ${DOCBOOK_XSL_URI} \ | sed -n 's|^file://||p;q') if test x"${STYLESHEET_PREFIX}" = x""; then DIRS=$(find "${datadir}" -name $(basename $(dirname ${DOCBOOK_XSL_PATH})) \ -type d | LC_ALL=C sort) if test x"${DIRS}" = x""; then # when datadir is not standard OS path, we cannot find docbook.xsl # use standard OS path as backup DIRS=$(find "/usr/share" "/usr/local/share" -name $(basename $(dirname ${DOCBOOK_XSL_PATH})) \ -type d | LC_ALL=C sort) fi XSLT=$(basename ${DOCBOOK_XSL_PATH}) for d in ${DIRS}; do if test -f "${d}/${XSLT}"; then STYLESHEET_PREFIX=$(echo "${d}" | sed 's/\/manpages//') break fi done fi if test x"${STYLESHEET_PREFIX}" = x""; then AC_MSG_ERROR(You need docbook-style-xsl installed in order to build ${PACKAGE}) fi fi AC_MSG_RESULT($STYLESHEET_PREFIX) AC_SUBST(STYLESHEET_PREFIX) dnl =============================================== dnl Libraries dnl =============================================== AC_CHECK_LIB(socket, socket) AC_CHECK_LIB(gnugetopt, getopt_long) dnl if available if test "x${enable_thread_safe}" = "xyes"; then GPKGNAME="gthread-2.0" else GPKGNAME="glib-2.0" fi PKG_CHECK_MODULES([GLIB], [$GPKGNAME]) CPPFLAGS="$CPPFLAGS $GLIB_CFLAGS" LIBS="$LIBS $GLIB_LIBS" dnl ======================================================================== dnl Headers dnl ======================================================================== AC_HEADER_STDC AC_CHECK_HEADERS(sys/socket.h) AC_CHECK_HEADERS(sys/sockio.h) AC_CHECK_HEADERS([arpa/inet.h]) AC_CHECK_HEADERS([fcntl.h]) AC_CHECK_HEADERS([limits.h]) AC_CHECK_HEADERS([malloc.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([sys/file.h]) AC_CHECK_HEADERS([sys/ioctl.h]) AC_CHECK_HEADERS([sys/param.h]) AC_CHECK_HEADERS([sys/time.h]) AC_CHECK_HEADERS([syslog.h]) dnl ======================================================================== dnl Functions dnl ======================================================================== AC_FUNC_FORK AC_FUNC_STRNLEN AC_CHECK_FUNCS([alarm gettimeofday inet_ntoa memset mkdir socket uname]) AC_CHECK_FUNCS([strcasecmp strchr strdup strerror strrchr strspn strstr strtol strtoul]) AC_PATH_PROGS(REBOOT, reboot, /sbin/reboot) AC_SUBST(REBOOT) AC_SUBST(REBOOT_OPTIONS) AC_DEFINE_UNQUOTED(REBOOT, "$REBOOT", path to the reboot command) AC_DEFINE_UNQUOTED(REBOOT_OPTIONS, "$REBOOT_OPTIONS", reboot options) AC_PATH_PROGS(POWEROFF_CMD, poweroff, /sbin/poweroff) AC_SUBST(POWEROFF_CMD) AC_SUBST(POWEROFF_OPTIONS) AC_DEFINE_UNQUOTED(POWEROFF_CMD, "$POWEROFF_CMD", path to the poweroff command) AC_DEFINE_UNQUOTED(POWEROFF_OPTIONS, "$POWEROFF_OPTIONS", poweroff options) AC_PATH_PROGS(POD2MAN, pod2man) AM_CONDITIONAL(BUILD_POD_DOC, test "x$POD2MAN" != "x" ) if test "x$POD2MAN" = "x"; then AC_MSG_WARN([pod2man not installed, unable to (re-)build ldirector manual page]) fi AC_SUBST(POD2MAN) dnl ======================================================================== dnl Functions dnl ======================================================================== AC_CHECK_FUNCS(getopt, AC_DEFINE(HAVE_DECL_GETOPT, 1, [Have getopt function])) dnl ======================================================================== dnl sfex dnl ======================================================================== build_sfex=no case $host_os in *Linux*|*linux*) if test "$ac_cv_header_heartbeat_glue_config_h" = "yes"; then build_sfex=yes fi ;; esac AM_CONDITIONAL(BUILD_SFEX, test "$build_sfex" = "yes" ) dnl ======================================================================== dnl tickle (needs port to BSD platforms) dnl ======================================================================== AC_CHECK_MEMBERS([struct iphdr.saddr],,,[[#include ]]) AM_CONDITIONAL(BUILD_TICKLE, test "$ac_cv_member_struct_iphdr_saddr" = "yes" ) dnl ======================================================================== dnl libnet dnl ======================================================================== libnet="" libnet_version="none" LIBNETLIBS="" LIBNETDEFINES="" AC_MSG_CHECKING(if libnet is required) libnet_fatal=$enable_libnet case $enable_libnet in no) ;; yes|libnet10|libnet11|10|11) libnet_fatal=yes;; try) case $host_os in *Linux*|*linux*) libnet_fatal=no;; *) libnet_fatal=yes;; dnl legacy behavior esac ;; *) libnet_fatal=yes; enable_libnet=try;; esac AC_MSG_RESULT($libnet_fatal) if test "x$enable_libnet" != "xno"; then AC_PATH_PROGS(LIBNETCONFIG, libnet-config) AC_CHECK_LIB(nsl, t_open) dnl -lnsl AC_CHECK_LIB(socket, socket) dnl -lsocket AC_CHECK_LIB(net, libnet_get_hwaddr, LIBNETLIBS=" -lnet", []) fi AC_MSG_CHECKING(for libnet) if test "x$LIBNETLIBS" != "x" -o "x$enable_libnet" = "xlibnet11"; then LIBNETDEFINES="" if test "$ac_cv_lib_nsl_t_open" = yes; then LIBNETLIBS="-lnsl $LIBNETLIBS" fi if test "$ac_cv_lib_socket_socket" = yes; then LIBNETLIBS="-lsocket $LIBNETLIBS" fi libnet=net libnet_version="libnet1.1" fi if test "x$enable_libnet" = "xtry" -o "x$enable_libnet" = "xlibnet10"; then if test "x$LIBNETLIBS" = x -a "x${LIBNETCONFIG}" != "x" ; then LIBNETDEFINES="`$LIBNETCONFIG --defines` `$LIBNETCONFIG --cflags`"; LIBNETLIBS="`$LIBNETCONFIG --libs`"; libnet_version="libnet1.0 (old)" case $LIBNETLIBS in *-l*) libnet=`echo $LIBNETLIBS | sed 's%.*-l%%'`;; *) libnet_version=none;; esac CPPFLAGS="$CPPFLAGS $LIBNETDEFINES" AC_CHECK_HEADERS(libnet.h) if test "$ac_cv_header_libnet_h" = no; then libnet_version=none fi fi fi AC_MSG_RESULT(found $libnet_version) if test "$libnet_version" = none; then LIBNETLIBS="" LIBNETDEFINES="" if test $libnet_fatal = yes; then AC_MSG_ERROR(libnet not found) fi else AC_CHECK_LIB($libnet,libnet_init, [new_libnet=yes; AC_DEFINE(HAVE_LIBNET_1_1_API, 1, Libnet 1.1 API)], [new_libnet=no; AC_DEFINE(HAVE_LIBNET_1_0_API, 1, Libnet 1.0 API)],$LIBNETLIBS) AC_SUBST(LIBNETLIBS) fi if test "$new_libnet" = yes; then AC_MSG_CHECKING(for libnet API 1.1.4: ) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fgnu89-inline -Wall -Werror" AC_COMPILE_IFELSE([ AC_LANG_SOURCE(#include int main(){libnet_t *l=NULL; libnet_pblock_record_ip_offset(l, l->total_size); return(0); })], [AC_MSG_RESULT(no)], [AC_DEFINE(HAVE_LIBNET_1_1_4_API, 1, Libnet 1.1.4 API) AC_MSG_RESULT(yes)]) CFLAGS="$save_CFLAGS" fi sendarp_linux=0 case $host_os in *Linux*|*linux*) sendarp_linux=1;; esac redhat_based=0 AC_CHECK_FILE(/etc/redhat-release, [redhat_based=1]) AC_SUBST(LIBNETLIBS) AC_SUBST(LIBNETDEFINES) AM_CONDITIONAL(SENDARP_LINUX, test $sendarp_linux = 1 ) AM_CONDITIONAL(USE_LIBNET, test "x$libnet_version" != "xnone" ) AM_CONDITIONAL(NFSCONVERT, test $redhat_based = 1 ) dnl ************************************************************************ dnl * Check for netinet/icmp6.h to enable the IPv6addr resource agent AC_CHECK_HEADERS(netinet/icmp6.h,[],[],[#include ]) AM_CONDITIONAL(USE_IPV6ADDR_AGENT, test "$ac_cv_header_netinet_icmp6_h" = yes && test "$ac_cv_header_heartbeat_glue_config_h" = yes) AM_CONDITIONAL(IPV6ADDR_COMPATIBLE, test "$ac_cv_header_netinet_icmp6_h" = yes) dnl ======================================================================== dnl Compiler flags dnl ======================================================================== dnl Make sure that CFLAGS is not exported. If the user did dnl not have CFLAGS in their environment then this should have dnl no effect. However if CFLAGS was exported from the user's dnl environment, then the new CFLAGS will also be exported dnl to sub processes. CC_ERRORS="" CC_EXTRAS="" if export -p | fgrep " CFLAGS=" > /dev/null; then SAVED_CFLAGS="$CFLAGS" unset CFLAGS CFLAGS="$SAVED_CFLAGS" unset SAVED_CFLAGS fi if test "$GCC" != yes; then CFLAGS="$CFLAGS -g" enable_fatal_warnings=no else CFLAGS="$CFLAGS -ggdb3" # We had to eliminate -Wnested-externs because of libtool changes # Also remove -Waggregate-return because we use one libnet # call which returns a struct EXTRA_FLAGS="-fgnu89-inline -fstack-protector-all -Wall -Wbad-function-cast -Wcast-qual -Wdeclaration-after-statement -Wendif-labels -Wfloat-equal -Wformat=2 -Wformat-security -Wformat-nonliteral -Winline -Wmissing-prototypes -Wmissing-declarations -Wmissing-format-attribute -Wnested-externs -Wno-long-long -Wno-strict-aliasing -Wpointer-arith -Wstrict-prototypes -Wunsigned-char -Wwrite-strings" # Additional warnings it might be nice to enable one day # -Wshadow # -Wunreachable-code for j in $EXTRA_FLAGS do if cc_supports_flag $j then CC_EXTRAS="$CC_EXTRAS $j" fi done dnl In lib/ais/Makefile.am there's a gcc option available as of v4.x GCC_MAJOR=`gcc -v 2>&1 | awk 'END{print $3}' | sed 's/[.].*//'` AM_CONDITIONAL(GCC_4, test "${GCC_MAJOR}" = 4) dnl System specific options case "$host_os" in *linux*|*bsd*) if test "${enable_fatal_warnings}" = "unknown"; then enable_fatal_warnings=yes fi ;; esac if test "x${enable_fatal_warnings}" != xno && cc_supports_flag -Werror ; then enable_fatal_warnings=yes else enable_fatal_warnings=no fi if test "x${enable_ansi}" != xno && cc_supports_flag -std=iso9899:199409 ; then AC_MSG_NOTICE(Enabling ANSI Compatibility) CC_EXTRAS="$CC_EXTRAS -ansi -D_GNU_SOURCE -DANSI_ONLY" fi AC_MSG_NOTICE(Activated additional gcc flags: ${CC_EXTRAS}) fi CFLAGS="$CFLAGS $CC_EXTRAS" NON_FATAL_CFLAGS="$CFLAGS" AC_SUBST(NON_FATAL_CFLAGS) dnl dnl We reset CFLAGS to include our warnings *after* all function dnl checking goes on, so that our warning flags don't keep the dnl AC_*FUNCS() calls above from working. In particular, -Werror will dnl *always* cause us troubles if we set it before here. dnl dnl if test "x${enable_fatal_warnings}" = xyes ; then AC_MSG_NOTICE(Enabling Fatal Warnings) CFLAGS="$CFLAGS -Werror" fi AC_SUBST(CFLAGS) dnl This is useful for use in Makefiles that need to remove one specific flag CFLAGS_COPY="$CFLAGS" AC_SUBST(CFLAGS_COPY) AC_SUBST(LOCALE) AC_SUBST(CC) AC_SUBST(MAKE) dnl The Makefiles and shell scripts we output AC_CONFIG_FILES(Makefile \ resource-agents.pc \ include/Makefile \ heartbeat/Makefile \ heartbeat/ocf-binaries \ heartbeat/ocf-directories \ heartbeat/ocf-shellfuncs \ heartbeat/shellfuncs \ systemd/Makefile \ systemd/resource-agents.conf \ tools/Makefile \ tools/nfsconvert \ tools/ocf-tester \ tools/ocft/Makefile \ tools/ocft/ocft \ tools/ocft/caselib \ tools/ocft/README \ tools/ocft/README.zh_CN \ ldirectord/Makefile \ ldirectord/ldirectord \ ldirectord/init.d/Makefile \ ldirectord/init.d/ldirectord \ ldirectord/init.d/ldirectord.debian \ ldirectord/init.d/ldirectord.debian.default \ ldirectord/systemd/Makefile \ ldirectord/systemd/ldirectord.service \ ldirectord/logrotate.d/Makefile \ ldirectord/OCF/Makefile \ ldirectord/OCF/ldirectord \ doc/Makefile \ doc/man/Makefile \ rgmanager/Makefile \ rgmanager/src/Makefile \ rgmanager/src/resources/Makefile \ rgmanager/src/resources/ocf-shellfuncs \ rgmanager/src/resources/svclib_nfslock \ rgmanager/src/resources/lvm_by_lv.sh \ rgmanager/src/resources/lvm_by_vg.sh \ rgmanager/src/resources/utils/Makefile \ rgmanager/src/resources/utils/fs-lib.sh \ rgmanager/src/resources/utils/messages.sh \ rgmanager/src/resources/utils/config-utils.sh \ rgmanager/src/resources/utils/member_util.sh \ rgmanager/src/resources/utils/ra-skelet.sh \ ) dnl Files we output that need to be executable AC_CONFIG_FILES([heartbeat/azure-events], [chmod +x heartbeat/azure-events]) AC_CONFIG_FILES([heartbeat/AoEtarget], [chmod +x heartbeat/AoEtarget]) AC_CONFIG_FILES([heartbeat/ManageRAID], [chmod +x heartbeat/ManageRAID]) AC_CONFIG_FILES([heartbeat/ManageVE], [chmod +x heartbeat/ManageVE]) AC_CONFIG_FILES([heartbeat/Squid], [chmod +x heartbeat/Squid]) AC_CONFIG_FILES([heartbeat/SysInfo], [chmod +x heartbeat/SysInfo]) AC_CONFIG_FILES([heartbeat/aws-vpc-route53], [chmod +x heartbeat/aws-vpc-route53]) AC_CONFIG_FILES([heartbeat/clvm], [chmod +x heartbeat/clvm]) AC_CONFIG_FILES([heartbeat/conntrackd], [chmod +x heartbeat/conntrackd]) AC_CONFIG_FILES([heartbeat/dnsupdate], [chmod +x heartbeat/dnsupdate]) AC_CONFIG_FILES([heartbeat/dummypy], [chmod +x heartbeat/dummypy]) AC_CONFIG_FILES([heartbeat/eDir88], [chmod +x heartbeat/eDir88]) AC_CONFIG_FILES([heartbeat/fio], [chmod +x heartbeat/fio]) AC_CONFIG_FILES([heartbeat/galera], [chmod +x heartbeat/galera]) AC_CONFIG_FILES([heartbeat/gcp-pd-move], [chmod +x heartbeat/gcp-pd-move]) AC_CONFIG_FILES([heartbeat/gcp-vpc-move-ip], [chmod +x heartbeat/gcp-vpc-move-ip]) AC_CONFIG_FILES([heartbeat/gcp-vpc-move-vip], [chmod +x heartbeat/gcp-vpc-move-vip]) AC_CONFIG_FILES([heartbeat/gcp-vpc-move-route], [chmod +x heartbeat/gcp-vpc-move-route]) AC_CONFIG_FILES([heartbeat/iSCSILogicalUnit], [chmod +x heartbeat/iSCSILogicalUnit]) AC_CONFIG_FILES([heartbeat/iSCSITarget], [chmod +x heartbeat/iSCSITarget]) AC_CONFIG_FILES([heartbeat/jira], [chmod +x heartbeat/jira]) AC_CONFIG_FILES([heartbeat/kamailio], [chmod +x heartbeat/kamailio]) AC_CONFIG_FILES([heartbeat/lxc], [chmod +x heartbeat/lxc]) AC_CONFIG_FILES([heartbeat/lxd-info], [chmod +x heartbeat/lxd-info]) AC_CONFIG_FILES([heartbeat/machine-info], [chmod +x heartbeat/machine-info]) AC_CONFIG_FILES([heartbeat/mariadb], [chmod +x heartbeat/mariadb]) AC_CONFIG_FILES([heartbeat/mpathpersist], [chmod +x heartbeat/mpathpersist]) AC_CONFIG_FILES([heartbeat/nfsnotify], [chmod +x heartbeat/nfsnotify]) AC_CONFIG_FILES([heartbeat/openstack-info], [chmod +x heartbeat/openstack-info]) AC_CONFIG_FILES([heartbeat/rabbitmq-cluster], [chmod +x heartbeat/rabbitmq-cluster]) AC_CONFIG_FILES([heartbeat/redis], [chmod +x heartbeat/redis]) AC_CONFIG_FILES([heartbeat/rsyslog], [chmod +x heartbeat/rsyslog]) AC_CONFIG_FILES([heartbeat/smb-share], [chmod +x heartbeat/smb-share]) AC_CONFIG_FILES([heartbeat/sg_persist], [chmod +x heartbeat/sg_persist]) AC_CONFIG_FILES([heartbeat/slapd], [chmod +x heartbeat/slapd]) AC_CONFIG_FILES([heartbeat/storage-mon], [chmod +x heartbeat/storage-mon]) AC_CONFIG_FILES([heartbeat/sybaseASE], [chmod +x heartbeat/sybaseASE]) AC_CONFIG_FILES([heartbeat/syslog-ng], [chmod +x heartbeat/syslog-ng]) AC_CONFIG_FILES([heartbeat/vsftpd], [chmod +x heartbeat/vsftpd]) AC_CONFIG_FILES([heartbeat/CTDB], [chmod +x heartbeat/CTDB]) AC_CONFIG_FILES([rgmanager/src/resources/ASEHAagent.sh], [chmod +x rgmanager/src/resources/ASEHAagent.sh]) AC_CONFIG_FILES([rgmanager/src/resources/apache.sh], [chmod +x rgmanager/src/resources/apache.sh]) AC_CONFIG_FILES([rgmanager/src/resources/bind-mount.sh], [chmod +x rgmanager/src/resources/bind-mount.sh]) AC_CONFIG_FILES([rgmanager/src/resources/clusterfs.sh], [chmod +x rgmanager/src/resources/clusterfs.sh]) AC_CONFIG_FILES([rgmanager/src/resources/db2.sh], [chmod +x rgmanager/src/resources/db2.sh]) AC_CONFIG_FILES([rgmanager/src/resources/drbd.sh], [chmod +x rgmanager/src/resources/drbd.sh]) AC_CONFIG_FILES([rgmanager/src/resources/fs.sh], [chmod +x rgmanager/src/resources/fs.sh]) AC_CONFIG_FILES([rgmanager/src/resources/ip.sh], [chmod +x rgmanager/src/resources/ip.sh]) AC_CONFIG_FILES([rgmanager/src/resources/lvm.sh], [chmod +x rgmanager/src/resources/lvm.sh]) AC_CONFIG_FILES([rgmanager/src/resources/mysql.sh], [chmod +x rgmanager/src/resources/mysql.sh]) AC_CONFIG_FILES([rgmanager/src/resources/named.sh], [chmod +x rgmanager/src/resources/named.sh]) AC_CONFIG_FILES([rgmanager/src/resources/netfs.sh], [chmod +x rgmanager/src/resources/netfs.sh]) AC_CONFIG_FILES([rgmanager/src/resources/nfsclient.sh], [chmod +x rgmanager/src/resources/nfsclient.sh]) AC_CONFIG_FILES([rgmanager/src/resources/nfsexport.sh], [chmod +x rgmanager/src/resources/nfsexport.sh]) AC_CONFIG_FILES([rgmanager/src/resources/nfsserver.sh], [chmod +x rgmanager/src/resources/nfsserver.sh]) AC_CONFIG_FILES([rgmanager/src/resources/openldap.sh], [chmod +x rgmanager/src/resources/openldap.sh]) AC_CONFIG_FILES([rgmanager/src/resources/oracledb.sh], [chmod +x rgmanager/src/resources/oracledb.sh]) AC_CONFIG_FILES([rgmanager/src/resources/oradg.sh], [chmod +x rgmanager/src/resources/oradg.sh]) AC_CONFIG_FILES([rgmanager/src/resources/orainstance.sh], [chmod +x rgmanager/src/resources/orainstance.sh]) AC_CONFIG_FILES([rgmanager/src/resources/oralistener.sh], [chmod +x rgmanager/src/resources/oralistener.sh]) AC_CONFIG_FILES([rgmanager/src/resources/postgres-8.sh], [chmod +x rgmanager/src/resources/postgres-8.sh]) AC_CONFIG_FILES([rgmanager/src/resources/samba.sh], [chmod +x rgmanager/src/resources/samba.sh]) AC_CONFIG_FILES([rgmanager/src/resources/script.sh], [chmod +x rgmanager/src/resources/script.sh]) AC_CONFIG_FILES([rgmanager/src/resources/service.sh], [chmod +x rgmanager/src/resources/service.sh]) AC_CONFIG_FILES([rgmanager/src/resources/smb.sh], [chmod +x rgmanager/src/resources/smb.sh]) AC_CONFIG_FILES([rgmanager/src/resources/tomcat-5.sh], [chmod +x rgmanager/src/resources/tomcat-5.sh]) AC_CONFIG_FILES([rgmanager/src/resources/tomcat-6.sh], [chmod +x rgmanager/src/resources/tomcat-6.sh]) AC_CONFIG_FILES([rgmanager/src/resources/vm.sh], [chmod +x rgmanager/src/resources/vm.sh]) dnl Now process the entire list of files added by previous dnl calls to AC_CONFIG_FILES() AC_OUTPUT() dnl ***************** dnl Configure summary dnl ***************** AC_MSG_RESULT([]) AC_MSG_RESULT([$PACKAGE configuration:]) AC_MSG_RESULT([ Version = ${VERSION}]) AC_MSG_RESULT([ Build Version = $Format:%H$]) AC_MSG_RESULT([]) AC_MSG_RESULT([ Prefix = ${prefix}]) AC_MSG_RESULT([ Executables = ${sbindir}]) AC_MSG_RESULT([ Man pages = ${mandir}]) AC_MSG_RESULT([ Libraries = ${libdir}]) AC_MSG_RESULT([ Header files = ${includedir}]) AC_MSG_RESULT([ Arch-independent files = ${datadir}]) AC_MSG_RESULT([ Documentation = ${docdir}]) AC_MSG_RESULT([ State information = ${localstatedir}]) AC_MSG_RESULT([ System configuration = ${sysconfdir}]) AC_MSG_RESULT([ HA_BIN directory prefix = ${libexecdir}]) AC_MSG_RESULT([ RA state files = ${HA_RSCTMPDIR}]) AC_MSG_RESULT([ AIS Plugins = ${LCRSODIR}]) AC_MSG_RESULT([]) AC_MSG_RESULT([ CPPFLAGS = ${CPPFLAGS}]) AC_MSG_RESULT([ CFLAGS = ${CFLAGS}]) AC_MSG_RESULT([ Libraries = ${LIBS}]) AC_MSG_RESULT([ Stack Libraries = ${CLUSTERLIBS}]) diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am index 039486fe4..e90894cb9 100644 --- a/doc/man/Makefile.am +++ b/doc/man/Makefile.am @@ -1,255 +1,256 @@ # # doc: Linux-HA resource agents # # Copyright (C) 2009 Florian Haas # # 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 program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = $(doc_DATA) $(REFENTRY_STYLESHEET) \ mkappendix.sh ralist.sh CLEANFILES = $(man_MANS) $(xmlfiles) metadata-*.xml STYLESHEET_PREFIX ?= http://docbook.sourceforge.net/release/xsl/current MANPAGES_STYLESHEET ?= $(STYLESHEET_PREFIX)/manpages/docbook.xsl HTML_STYLESHEET ?= $(STYLESHEET_PREFIX)/xhtml/docbook.xsl FO_STYLESHEET ?= $(STYLESHEET_PREFIX)/fo/docbook.xsl REFENTRY_STYLESHEET ?= ra2refentry.xsl XSLTPROC_OPTIONS ?= --xinclude XSLTPROC_MANPAGES_OPTIONS ?= $(XSLTPROC_OPTIONS) XSLTPROC_HTML_OPTIONS ?= $(XSLTPROC_OPTIONS) XSLTPROC_FO_OPTIONS ?= $(XSLTPROC_OPTIONS) radir = $(abs_top_builddir)/heartbeat # required for out-of-tree build symlinkstargets = \ ocf-distro ocf.py ocf-rarun ocf-returncodes \ findif.sh apache-conf.sh http-mon.sh mysql-common.sh \ nfsserver-redhat.sh ora-common.sh preptree: for i in $(symlinkstargets); do \ if [ ! -f $(radir)/$$i ]; then \ rm -rf $(radir)/$$i; \ ln -sf $(abs_top_srcdir)/heartbeat/$$i $(radir)/$$i; \ fi; \ done $(radir)/%: $(abs_top_srcdir)/heartbeat/% if [ ! -f $@ ]; then \ ln -sf $< $@; \ fi # OCF_ROOT=. is necessary due to a sanity check in ocf-shellfuncs # (which tests whether $OCF_ROOT points to a directory metadata-%.xml: $(radir)/% preptree OCF_ROOT=. OCF_FUNCTIONS_DIR=$(radir) $< meta-data > $@ metadata-IPv6addr.xml: $(radir)/IPv6addr OCF_ROOT=. OCF_FUNCTIONS_DIR=$(radir) $< meta-data > $@ clean-local: find $(radir) -type l -exec rm -rf {} \; # Please note: we can't name the man pages # ocf:heartbeat:. Believe me, I've tried. It looks like it # works, but then it doesn't. While make can deal correctly with # colons in target names (when properly escaped), it royally messes up # when it is deals with _dependencies_ that contain colons. See Bug # 12126 on savannah.gnu.org. But, maybe it gets fixed soon, it was # first reported in 1995 and added to Savannah in in 2005... if BUILD_DOC man_MANS = ocf_heartbeat_AoEtarget.7 \ ocf_heartbeat_AudibleAlarm.7 \ ocf_heartbeat_ClusterMon.7 \ ocf_heartbeat_CTDB.7 \ ocf_heartbeat_Delay.7 \ ocf_heartbeat_Dummy.7 \ ocf_heartbeat_EvmsSCC.7 \ ocf_heartbeat_Evmsd.7 \ ocf_heartbeat_Filesystem.7 \ ocf_heartbeat_ICP.7 \ ocf_heartbeat_IPaddr.7 \ ocf_heartbeat_IPaddr2.7 \ ocf_heartbeat_IPsrcaddr.7 \ ocf_heartbeat_LVM.7 \ ocf_heartbeat_LVM-activate.7 \ ocf_heartbeat_LinuxSCSI.7 \ ocf_heartbeat_MailTo.7 \ ocf_heartbeat_ManageRAID.7 \ ocf_heartbeat_ManageVE.7 \ ocf_heartbeat_NodeUtilization.7 \ ocf_heartbeat_Pure-FTPd.7 \ ocf_heartbeat_Raid1.7 \ ocf_heartbeat_Route.7 \ ocf_heartbeat_SAPDatabase.7 \ ocf_heartbeat_SAPInstance.7 \ ocf_heartbeat_SendArp.7 \ ocf_heartbeat_ServeRAID.7 \ ocf_heartbeat_SphinxSearchDaemon.7 \ ocf_heartbeat_Squid.7 \ ocf_heartbeat_Stateful.7 \ ocf_heartbeat_SysInfo.7 \ ocf_heartbeat_VIPArip.7 \ ocf_heartbeat_VirtualDomain.7 \ ocf_heartbeat_WAS.7 \ ocf_heartbeat_WAS6.7 \ ocf_heartbeat_WinPopup.7 \ ocf_heartbeat_Xen.7 \ ocf_heartbeat_Xinetd.7 \ ocf_heartbeat_ZFS.7 \ ocf_heartbeat_aliyun-vpc-move-ip.7 \ ocf_heartbeat_anything.7 \ ocf_heartbeat_apache.7 \ ocf_heartbeat_asterisk.7 \ ocf_heartbeat_aws-vpc-move-ip.7 \ ocf_heartbeat_aws-vpc-route53.7 \ ocf_heartbeat_awseip.7 \ ocf_heartbeat_awsvip.7 \ ocf_heartbeat_azure-lb.7 \ ocf_heartbeat_clvm.7 \ ocf_heartbeat_conntrackd.7 \ ocf_heartbeat_crypt.7 \ ocf_heartbeat_db2.7 \ ocf_heartbeat_dhcpd.7 \ ocf_heartbeat_docker.7 \ ocf_heartbeat_docker-compose.7 \ ocf_heartbeat_dovecot.7 \ ocf_heartbeat_dnsupdate.7 \ ocf_heartbeat_dummypy.7 \ ocf_heartbeat_eDir88.7 \ ocf_heartbeat_ethmonitor.7 \ ocf_heartbeat_exportfs.7 \ ocf_heartbeat_fio.7 \ ocf_heartbeat_galera.7 \ ocf_heartbeat_garbd.7 \ ocf_heartbeat_gcp-ilb.7 \ ocf_heartbeat_gcp-vpc-move-ip.7 \ ocf_heartbeat_iSCSILogicalUnit.7 \ ocf_heartbeat_iSCSITarget.7 \ ocf_heartbeat_iface-bridge.7 \ ocf_heartbeat_iface-vlan.7 \ ocf_heartbeat_ipsec.7 \ ocf_heartbeat_ids.7 \ ocf_heartbeat_iscsi.7 \ ocf_heartbeat_jboss.7 \ ocf_heartbeat_jira.7 \ ocf_heartbeat_kamailio.7 \ ocf_heartbeat_lvmlockd.7 \ ocf_heartbeat_lxc.7 \ ocf_heartbeat_lxd-info.7 \ ocf_heartbeat_machine-info.7 \ ocf_heartbeat_mariadb.7 \ ocf_heartbeat_mdraid.7 \ ocf_heartbeat_minio.7 \ ocf_heartbeat_mpathpersist.7 \ ocf_heartbeat_mysql.7 \ ocf_heartbeat_mysql-proxy.7 \ ocf_heartbeat_nagios.7 \ ocf_heartbeat_named.7 \ ocf_heartbeat_nfsnotify.7 \ ocf_heartbeat_nfsserver.7 \ ocf_heartbeat_nginx.7 \ ocf_heartbeat_nvmet-subsystem.7 \ ocf_heartbeat_nvmet-namespace.7 \ ocf_heartbeat_nvmet-port.7 \ ocf_heartbeat_openstack-info.7 \ ocf_heartbeat_openstack-cinder-volume.7 \ ocf_heartbeat_openstack-floating-ip.7 \ ocf_heartbeat_openstack-virtual-ip.7 \ ocf_heartbeat_oraasm.7 \ ocf_heartbeat_oracle.7 \ ocf_heartbeat_oralsnr.7 \ ocf_heartbeat_ovsmonitor.7 \ ocf_heartbeat_pgagent.7 \ ocf_heartbeat_pgsql.7 \ ocf_heartbeat_pingd.7 \ ocf_heartbeat_podman.7 \ ocf_heartbeat_portblock.7 \ ocf_heartbeat_postfix.7 \ ocf_heartbeat_pound.7 \ ocf_heartbeat_proftpd.7 \ ocf_heartbeat_rabbitmq-cluster.7 \ + ocf_heartbeat_rabbitmq-server-ha.7 \ ocf_heartbeat_redis.7 \ ocf_heartbeat_rkt.7 \ ocf_heartbeat_rsyncd.7 \ ocf_heartbeat_rsyslog.7 \ ocf_heartbeat_scsi2reservation.7 \ ocf_heartbeat_sfex.7 \ ocf_heartbeat_slapd.7 \ ocf_heartbeat_smb-share.7 \ ocf_heartbeat_sybaseASE.7 \ ocf_heartbeat_sg_persist.7 \ ocf_heartbeat_storage-mon.7 \ ocf_heartbeat_symlink.7 \ ocf_heartbeat_syslog-ng.7 \ ocf_heartbeat_tomcat.7 \ ocf_heartbeat_varnish.7 \ ocf_heartbeat_vdo-vol.7 \ ocf_heartbeat_vmware.7 \ ocf_heartbeat_vsftpd.7 \ ocf_heartbeat_zabbixserver.7 if USE_IPV6ADDR_AGENT man_MANS += ocf_heartbeat_IPv6addr.7 endif if BUILD_AZURE_EVENTS man_MANS += ocf_heartbeat_azure-events.7 endif if BUILD_GCP_PD_MOVE man_MANS += ocf_heartbeat_gcp-pd-move.7 endif if BUILD_GCP_VPC_MOVE_ROUTE man_MANS += ocf_heartbeat_gcp-vpc-move-route.7 endif if BUILD_GCP_VPC_MOVE_VIP man_MANS += ocf_heartbeat_gcp-vpc-move-vip.7 endif xmlfiles = $(man_MANS:.7=.xml) %.1 %.5 %.7 %.8: %.xml $(XSLTPROC) \ $(XSLTPROC_MANPAGES_OPTIONS) \ $(MANPAGES_STYLESHEET) $< ocf_heartbeat_%.xml: metadata-%.xml $(srcdir)/$(REFENTRY_STYLESHEET) $(XSLTPROC) --novalid \ --stringparam package $(PACKAGE_NAME) \ --stringparam version $(VERSION) \ --output $@ \ $(srcdir)/$(REFENTRY_STYLESHEET) $< ocf_resource_agents.xml: $(xmlfiles) mkappendix.sh ./mkappendix.sh $(xmlfiles) > $@ %.html: %.xml $(XSLTPROC) \ $(XSLTPROC_HTML_OPTIONS) \ --output $@ \ $(HTML_STYLESHEET) $< xml: ocf_resource_agents.xml endif diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am index ec40c9fc0..8e0f2122c 100644 --- a/heartbeat/Makefile.am +++ b/heartbeat/Makefile.am @@ -1,240 +1,241 @@ # Makefile.am for OCF RAs # # Author: Sun Jing Dong # Copyright (C) 2004 IBM # # 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 program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = $(ocf_SCRIPTS) $(ocfcommon_DATA) \ $(common_DATA) $(hb_DATA) $(dtd_DATA) \ README README.galera AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/linux-ha halibdir = $(libexecdir)/heartbeat ocfdir = $(OCF_RA_DIR_PREFIX)/heartbeat dtddir = $(datadir)/$(PACKAGE_NAME) dtd_DATA = ra-api-1.dtd metadata.rng ocf_PROGRAMS = if USE_IPV6ADDR_AGENT ocf_PROGRAMS += IPv6addr endif halib_PROGRAMS = if IPV6ADDR_COMPATIBLE halib_PROGRAMS += send_ua endif IPv6addr_SOURCES = IPv6addr.c IPv6addr_utils.c IPv6addr_LDADD = -lplumb $(LIBNETLIBS) send_ua_SOURCES = send_ua.c IPv6addr_utils.c send_ua_LDADD = $(LIBNETLIBS) ocf_SCRIPTS = AoEtarget \ AudibleAlarm \ ClusterMon \ CTDB \ Delay \ Dummy \ EvmsSCC \ Evmsd \ Filesystem \ ICP \ IPaddr \ IPaddr2 \ IPsrcaddr \ LVM \ LinuxSCSI \ lvmlockd \ LVM-activate \ MailTo \ ManageRAID \ ManageVE \ NodeUtilization \ Pure-FTPd \ Raid1 \ Route \ SAPDatabase \ SAPInstance \ SendArp \ ServeRAID \ SphinxSearchDaemon \ Squid \ Stateful \ SysInfo \ VIPArip \ VirtualDomain \ WAS \ WAS6 \ WinPopup \ Xen \ Xinetd \ ZFS \ aliyun-vpc-move-ip \ anything \ apache \ asterisk \ aws-vpc-move-ip \ aws-vpc-route53 \ awseip \ awsvip \ azure-lb \ clvm \ conntrackd \ crypt \ db2 \ dhcpd \ dnsupdate \ dummypy \ docker \ docker-compose \ dovecot \ eDir88 \ ethmonitor \ exportfs \ fio \ galera \ garbd \ gcp-ilb \ gcp-vpc-move-ip \ iSCSILogicalUnit \ iSCSITarget \ ids \ iface-bridge \ iface-vlan \ ipsec \ iscsi \ jboss \ jira \ kamailio \ lxc \ lxd-info \ machine-info \ mariadb \ mdraid \ minio \ mysql \ mysql-proxy \ nagios \ named \ nfsnotify \ nfsserver \ nginx \ nvmet-subsystem \ nvmet-namespace \ nvmet-port \ openstack-cinder-volume \ openstack-floating-ip \ openstack-info \ openstack-virtual-ip \ oraasm \ oracle \ oralsnr \ ovsmonitor \ pgagent \ pgsql \ pingd \ podman \ portblock \ postfix \ pound \ proftpd \ rabbitmq-cluster \ + rabbitmq-server-ha \ redis \ rkt \ rsyncd \ rsyslog \ scsi2reservation \ sfex \ sg_persist \ mpathpersist \ slapd \ smb-share \ storage-mon \ sybaseASE \ symlink \ syslog-ng \ tomcat \ varnish \ vdo-vol \ vmware \ vsftpd \ zabbixserver if BUILD_AZURE_EVENTS ocf_SCRIPTS += azure-events endif if BUILD_GCP_PD_MOVE ocf_SCRIPTS += gcp-pd-move endif if BUILD_GCP_VPC_MOVE_ROUTE ocf_SCRIPTS += gcp-vpc-move-route endif if BUILD_GCP_VPC_MOVE_VIP ocf_SCRIPTS += gcp-vpc-move-vip endif ocfcommondir = $(OCF_LIB_DIR_PREFIX)/heartbeat ocfcommon_DATA = ocf-shellfuncs \ ocf-binaries \ ocf-directories \ ocf-returncodes \ ocf-rarun \ ocf-distro \ apache-conf.sh \ http-mon.sh \ sapdb-nosha.sh \ sapdb.sh \ lvm-clvm.sh \ lvm-plain.sh \ lvm-tag.sh \ ora-common.sh \ mysql-common.sh \ nfsserver-redhat.sh \ findif.sh \ ocf.py # Legacy locations hbdir = $(sysconfdir)/ha.d hb_DATA = shellfuncs check: $(ocf_SCRIPTS:=.check) %.check: % OCF_ROOT=$(abs_srcdir) OCF_FUNCTIONS_DIR=$(abs_srcdir) ./$< meta-data | xmllint --path $(abs_srcdir) --noout --relaxng $(abs_srcdir)/metadata.rng - do_spellcheck = printf '[%s]\n' "$(agent)"; \ OCF_ROOT=$(abs_srcdir) OCF_FUNCTIONS_DIR=$(abs_srcdir) \ ./$(agent) meta-data 2>/dev/null \ | xsltproc $(top_srcdir)/make/extract_text.xsl - \ | aspell pipe list -d en_US --ignore-case \ --home-dir=$(top_srcdir)/make -p spellcheck-ignore \ | sed -n 's|^&\([^:]*\):.*|\1|p'; spellcheck: @$(foreach agent,$(ocf_SCRIPTS), $(do_spellcheck)) clean-local: rm -rf __pycache__ *.pyc diff --git a/heartbeat/Squid.in b/heartbeat/Squid.in index 12e248936..e574ad045 100644 --- a/heartbeat/Squid.in +++ b/heartbeat/Squid.in @@ -1,472 +1,472 @@ #!@BASH_SHELL@ # # Description: Manages a Squid Server provided by NTT OSSC as an # OCF High-Availability resource under Heartbeat/LinuxHA control # # 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 program 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. # # Copyright (c) 2008 NIPPON TELEGRAPH AND TELEPHONE CORPORATION # ####################################################################### # OCF parameters: # OCF_RESKEY_squid_exe : Executable file # OCF_RESKEY_squid_conf : Configuration file # OCF_RESKEY_squid_opts : Start options # OCF_RESKEY_squid_pidfile: Process id file # OCF_RESKEY_squid_port : Port number # OCF_RESKEY_debug_mode : Debug mode # OCF_RESKEY_debug_log : Debug log file # OCF_RESKEY_squid_stop_timeout: # Number of seconds to await to confirm a # normal stop method # # OCF_RESKEY_squid_exe, OCF_RESKEY_squid_conf, OCF_RESKEY_squid_pidfile # and OCF_RESKEY_squid_port must be specified. Each of the rests # has its default value or refers OCF_RESKEY_squid_conf to make # its value when no explicit value is given. ############################################################################### : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs # Parameter defaults OCF_RESKEY_squid_exe_default="" OCF_RESKEY_squid_conf_default="" OCF_RESKEY_squid_opts_default="" OCF_RESKEY_squid_pidfile_default="" OCF_RESKEY_squid_port_default="" OCF_RESKEY_squid_stop_timeout_default="10" OCF_RESKEY_debug_mode_default="" OCF_RESKEY_debug_log_default="" : ${OCF_RESKEY_squid_exe=${OCF_RESKEY_squid_exe_default}} : ${OCF_RESKEY_squid_conf=${OCF_RESKEY_squid_conf_default}} : ${OCF_RESKEY_squid_pidfile=${OCF_RESKEY_squid_pidfile_default}} : ${OCF_RESKEY_squid_port=${OCF_RESKEY_squid_port_default}} : ${OCF_RESKEY_squid_stop_timeout=${OCF_RESKEY_squid_stop_timeout_default}} : ${OCF_RESKEY_debug_mode=${OCF_RESKEY_debug_mode_default}} : ${OCF_RESKEY_debug_log=${OCF_RESKEY_debug_log_default}} usage() { cat <<-! usage: $0 action action: start : start a new squid instance stop : stop the running squid instance status : return the status of squid, run or down monitor : return TRUE if the squid appears to be working. meta-data : show meta data message validate-all: validate the instance parameters ! return $OCF_ERR_ARGS } metadata_squid() { cat < 1.0 The resource agent of Squid. This manages a Squid instance as an HA resource. Manages a Squid proxy server instance This is a required parameter. This parameter specifies squid's executable file. Executable file This is a required parameter. This parameter specifies a configuration file for a squid instance managed by this RA. Configuration file This is a optional parameter. This parameter specifies the start options. Start options Deprecated - do not use anymore deprecated - do not use anymore This is a required parameter. This parameter specifies a port number for a squid instance managed by this RA. If multiple ports are used, you must specify only one of them. Port number On stop, a squid shutdown is invoked first. If the resource doesn't stop within this timeout, we resort to stopping processes by sending signals and finally KILLing them. how long to wait for squid shutdown to stop the instance before resorting to kill This is an optional parameter. This RA runs in debug mode when this parameter includes 'x' or 'v'. If 'x' is included, both of STDOUT and STDERR redirect to the logfile specified by "debug_log", and then the builtin shell option 'x' is turned on. It is similar about 'v'. Debug mode This is an optional parameter. This parameter specifies a destination file for debug logs and works only if this RA run in debug mode. Refer to "debug_mode" about debug mode. If no value is given but is required, it's constructed according to the following rules: "/var/log/" as a directory part, the basename of the configuration file given by "syslog_ng_conf" as a basename part, ".log" as a suffix. A destination of the debug log END return $OCF_SUCCESS } get_pids() { SQUID_PIDS=( ) # Seek by pattern SQUID_PIDS[0]=$(pgrep -f "$PROCESS_PATTERN") # Seek by child process if [[ -n "${SQUID_PIDS[0]}" ]]; then SQUID_PIDS[1]=$(pgrep -P ${SQUID_PIDS[0]}) fi if [[ -n "${SQUID_PIDS[1]}" ]]; then typeset exe exe=$(ls -l "/proc/${SQUID_PIDS[1]}/exe") if [[ $? = 0 ]]; then exe=${exe##*-> } if ! [[ "$exe" = $SQUID_EXE ]]; then SQUID_PIDS[1]="" fi else SQUID_PIDS[1]="" fi fi # Seek by port if have_binary netstat; then SQUID_PIDS[2]=$( netstat -apn | awk '/tcp.*:'$SQUID_PORT' .*LISTEN/ && $7~/^[1-9]/ { sub("\\/.*", "", $7); print $7; exit}') else SQUID_PIDS[2]=$( ss -apn | awk '/tcp.*LISTEN.*:'$SQUID_PORT'/ { sub(".*pid=", "", $7); sub(",fd=.*", "", $7); print $7 }') fi } are_all_pids_found() { if [[ -n "${SQUID_PIDS[0]}" ]] && [[ -n "${SQUID_PIDS[1]}" ]] && [[ -n "${SQUID_PIDS[2]}" ]] then return 0 else return 1 fi } are_pids_sane() { if [[ "${SQUID_PIDS[1]}" = "${SQUID_PIDS[2]}" ]]; then return $OCF_SUCCESS else ocf_exit_reason "$SQUID_NAME:Pid unmatch" return $OCF_ERR_GENERIC fi } is_squid_dead() { if [[ -z "${SQUID_PIDS[0]}" ]] && [[ -z "${SQUID_PIDS[2]}" ]] then return 0 else return 1 fi } monitor_squid() { typeset trialcount=0 while true; do get_pids if are_all_pids_found; then are_pids_sane return $OCF_SUCCESS fi if is_squid_dead; then return $OCF_NOT_RUNNING fi ocf_log info "$SQUID_NAME:Inconsistent processes:" \ "${SQUID_PIDS[0]},${SQUID_PIDS[1]},${SQUID_PIDS[2]}" (( trialcount = trialcount + 1 )) if (( trialcount > SQUID_CONFIRM_TRIALCOUNT )); then ocf_exit_reason "$SQUID_NAME:Inconsistency of processes remains unsolved" return $OCF_ERR_GENERIC fi sleep 1 done } start_squid() { typeset status monitor_squid status=$? if [[ $status != $OCF_NOT_RUNNING ]]; then return $status fi set -- "$SQUID_OPTS" ocf_run $SQUID_EXE -f "$SQUID_CONF" "$@" status=$? if [[ $status != $OCF_SUCCESS ]]; then return $OCF_ERR_GENERIC fi while true; do get_pids if are_all_pids_found && are_pids_sane; then return $OCF_SUCCESS fi ocf_log info "$SQUID_NAME:Waiting for squid to be invoked" sleep 1 done return $OCF_ERR_GENERIC } stop_squid() { typeset lapse_sec if ocf_run $SQUID_EXE -f $SQUID_CONF -k shutdown; then lapse_sec=0 while true; do get_pids if is_squid_dead; then return $OCF_SUCCESS fi (( lapse_sec = lapse_sec + 1 )) if (( lapse_sec > SQUID_STOP_TIMEOUT )); then break fi sleep 1 ocf_log info "$SQUID_NAME:$FUNCNAME:$LINENO: " \ "stop NORM $lapse_sec/$SQUID_STOP_TIMEOUT" done fi while true; do get_pids ocf_log info "$SQUID_NAME:$FUNCNAME:$LINENO: " \ "try to stop by SIGKILL:${SQUID_PIDS[0]} ${SQUID_PIDS[2]}" kill -KILL ${SQUID_PIDS[0]} ${SQUID_PIDS[2]} sleep 1 if is_squid_dead; then return $OCF_SUCCESS fi done return $OCF_ERR_GENERIC } status_squid() { return $OCF_SUCCESS } validate_all_squid() { ocf_log info "validate_all_squid[$SQUID_NAME]" return $OCF_SUCCESS } -: === Debug ${0##*/} $1 === +: "=== Debug ${0##*/} $1 ===" if [[ "$1" = "meta-data" ]]; then metadata_squid exit $? fi SQUID_CONF="${OCF_RESKEY_squid_conf}" if [[ -z "$SQUID_CONF" ]]; then ocf_exit_reason "SQUID_CONF is not defined" exit $OCF_ERR_CONFIGURED fi SQUID_NAME="${SQUID_CONF##*/}" SQUID_NAME="${SQUID_NAME%.*}" DEBUG_LOG="${OCF_RESKEY_debug_log-/var/log/squid_${SQUID_NAME}_debug}.log" DEBUG_MODE="" case $OCF_RESKEY_debug_mode in *x*) DEBUG_MODE="${DEBUG_MODE}x";; esac case $OCF_RESKEY_debug_mode in *v*) DEBUG_MODE="${DEBUG_MODE}v";; esac if [ -n "$DEBUG_MODE" ]; then PS4='\d \t \h '"${1-unknown} " export PS4 exec 1>>$DEBUG_LOG 2>&1 set -$DEBUG_MODE fi SQUID_EXE="${OCF_RESKEY_squid_exe}" if [[ -z "$SQUID_EXE" ]]; then ocf_exit_reason "SQUID_EXE is not defined" exit $OCF_ERR_CONFIGURED fi if [[ ! -x "$SQUID_EXE" ]]; then ocf_exit_reason "$SQUID_EXE is not found" exit $OCF_ERR_CONFIGURED fi SQUID_PORT="${OCF_RESKEY_squid_port}" if [[ -z "$SQUID_PORT" ]]; then ocf_exit_reason "SQUID_PORT is not defined" exit $OCF_ERR_CONFIGURED fi SQUID_OPTS="${OCF_RESKEY_squid_opts}" SQUID_PIDS=( ) SQUID_CONFIRM_TRIALCOUNT="${OCF_RESKEY_squid_confirm_trialcount-3}" SQUID_STOP_TIMEOUT="${OCF_RESKEY_squid_stop_timeout-10}" SQUID_SUSPEND_TRIALCOUNT="${OCF_RESKEY_squid_suspend_trialcount-10}" PROCESS_PATTERN="$SQUID_EXE -f $SQUID_CONF" COMMAND=$1 case "$COMMAND" in start) ocf_log debug "[$SQUID_NAME] Enter squid start" start_squid func_status=$? ocf_log debug "[$SQUID_NAME] Leave squid start $func_status" exit $func_status ;; stop) ocf_log debug "[$SQUID_NAME] Enter squid stop" stop_squid func_status=$? ocf_log debug "[$SQUID_NAME] Leave squid stop $func_status" exit $func_status ;; status) status_squid exit $? ;; monitor) #ocf_log debug "[$SQUID_NAME] Enter squid monitor" monitor_squid func_status=$? #ocf_log debug "[$SQUID_NAME] Leave squid monitor $func_status" exit $func_status ;; validate-all) validate_all_squid exit $? ;; *) usage ;; esac # vim: set sw=4 ts=4 : diff --git a/heartbeat/gcp-ilb b/heartbeat/gcp-ilb index 28484b241..48dc3ac4e 100755 --- a/heartbeat/gcp-ilb +++ b/heartbeat/gcp-ilb @@ -1,343 +1,343 @@ #!/bin/sh # --------------------------------------------------------------------- # # Copyright 2021 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Authors: Fatima Silveira, Lucia Subatin # --------------------------------------------------------------------- # Description: Wrapper to respond to probe requests from health # check agents in Google Cloud Platform. Nothing is specific to Google # Cloud. # --------------------------------------------------------------------- # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs # Defaults OCF_RESKEY_cat_default="socat" OCF_RESKEY_port_default="60000" OCF_RESKEY_log_enable_default="false" OCF_RESKEY_log_cmd_default="gcloud" OCF_RESKEY_log_params_default="logging write GCPILB" OCF_RESKEY_log_end_params_default="" if type "socat" > /dev/null 2>&1; then OCF_RESKEY_cat_default="socat" else OCF_RESKEY_cat_default="nc" fi; : ${OCF_RESKEY_cat=${OCF_RESKEY_cat_default}} : ${OCF_RESKEY_port=${OCF_RESKEY_port_default}} : ${OCF_RESKEY_log_enable=${OCF_RESKEY_log_enable_default}} : ${OCF_RESKEY_log_cmd=${OCF_RESKEY_log_cmd_default}} : ${OCF_RESKEY_log_params=${OCF_RESKEY_log_params_default}} : ${OCF_RESKEY_log_end_params=${OCF_RESKEY_log_end_params_default}} process="$OCF_RESOURCE_INSTANCE" pidfile="/var/run/$OCF_RESOURCE_INSTANCE.pid" #Validate command for logging -if $OCF_RESKEY_log_enable = "true"; then +if [ $OCF_RESKEY_log_enable = "true" ]; then if type $OCF_RESKEY_log_cmd > /dev/null 2>&1; then logging_cmd="$OCF_RESKEY_log_cmd $OCF_RESKEY_log_params" ocf_log debug "Logging command is: \'$logging_cmd\' " else - $OCF_RESKEY_log_enable = "false" + OCF_RESKEY_log_enable="false" ocf_log err "\'$logging_cmd\' is invalid. External logging disabled." fi; fi ####################################################################### ilb_metadata() { cat < 1.0 Resource Agent that wraps /usr/bin/nc or /usr/bin/socat to reply to health checks in Google Cloud. See https://cloud.google.com/load-balancing/docs/health-checks for more information. Replies to health checks from Google Cloud Listening port for health-check probes. Default: ${OCF_RESKEY_port_default} Listening port (def ${OCF_RESKEY_port_default}) Location of netcat (default: /usr/bin/nc ) or socat (default: /usr/bin/socat ). If present, is used /usr/bin/socat. The recommended binary is socat, present in the following minimum versions if the package resource-agents: - SLES 12 SP4/SP5: resource-agents-4.3.018.a7fb5035-3.30.1. - SLES 15/15 SP1: resource-agents-4.3.0184.6ee15eb2-4.13.1. Path to nc / socat Logging with an external application is enabled (accepts "true" or "false"). The defaults are configured to call "gcloud logging" (see: https://cloud.google.com/sdk/gcloud/reference/logging). Log enabled External logging command. The defaults are configured to call "gcloud logging" (see: https://cloud.google.com/sdk/gcloud/reference/logging). This parameter should only have the binary that can be validated (e.g., gcloud). The rest of the command is formed with the additional parameters and the message being logged as follows: - log_cmd + log_params + "The message being logged" + log_end_params Using the gcloud command for Stackdriver logging, the parameters would be: - log_cmd = gcloud - log_params = logging write GCPILB - "This is a message being sent by the app" - log_end_params = (nothing in this case, this is reserved for use with other tools) Which would result in this valid command (where GCPILB is the name of the log): gcloud logging write GCPILB "This is a message being sent by the app" NOTE: Only the binary is validated for existence and no further checks are performed. The assumption is that only administrators with root access can configure this tool. External log command Additional input for the logging application. See explanation for log_cmd Additional input 1 Additional input for the logging application. Placed after the message being logged. Additional input 1 END exit 0 } ####################################################################### log() { lvl=$1 msg=$2 ocf_log $lvl "$0 - $process - $pid: $msg" if ocf_is_true "${OCF_RESKEY_log_enable}" ; then ( ${OCF_RESKEY_log_cmd} ${OCF_RESKEY_log_params} "L $lvl: $msg" ${OCF_RESKEY_log_end_params} ) fi } getpid() { if ! [ -f "$pidfile" ] ; then return fi cat $pidfile } ilb_usage() { cat < $pidfile return $OCF_SUCCESS else log err "\'$cmd\' could not be started" return $OCF_ERR_GENERIC fi } ilb_stop() { if ! ilb_monitor; then rm -f $pidfile return $OCF_SUCCESS fi if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then # Allow 2/3 of the action timeout for the orderly shutdown # (The origin unit is ms, hence the conversion) stop_timeout=$((OCF_RESKEY_CRM_meta_timeout/1500)) else stop_timeout=10 fi pid=`getpid` kill $pid i=0 while [ $i -lt $stop_timeout ]; do if ! ilb_monitor; then rm -f $pidfile return $OCF_SUCCESS fi sleep 1 i=$((i+1)) done log warn "Stop with SIGTERM failed/timed out, now sending SIGKILL." i=0 while [ $i -lt $stop_timeout ]; do kill -s 9 $pid if ! ilb_monitor; then log warn "SIGKILL did the job." rm -f $pidfile return $OCF_SUCCESS fi log info "The job still hasn't stopped yet. Re-trying SIGKILL..." sleep 2 i=$((i+2)) done log err "The cat has more than 9 lives and could not be terminated." return $OCF_ERR_GENERIC } ilb_validate() { check_binary "$OCF_RESKEY_cat" check_binary "$OCF_RESKEY_log_cmd" if ! ocf_is_decimal "$OCF_RESKEY_port"; then ocf_exit_reason "$OCF_RESKEY_port is not a valid port" exit $OCF_ERR_CONFIGURED fi return $OCF_SUCCESS } ############################################################################### # # MAIN # ############################################################################### case $__OCF_ACTION in meta-data) ilb_metadata exit $OCF_SUCCESS ;; usage|help) ilb_usage exit $OCF_SUCCESS ;; esac if ! ocf_is_root; then log err "You must be root for $__OCF_ACTION operation." exit $OCF_ERR_PERM fi case $__OCF_ACTION in start) ilb_validate ilb_start ;; stop) ilb_stop ;; monitor) ilb_monitor ;; validate-all) ilb_validate ;; *) ilb_usage exit $OCF_ERR_UNIMPLEMENTED ;; esac rc=$? log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION returned $rc" exit $rc diff --git a/heartbeat/nvmet-subsystem b/heartbeat/nvmet-subsystem index e004ec142..a1d0cd293 100755 --- a/heartbeat/nvmet-subsystem +++ b/heartbeat/nvmet-subsystem @@ -1,188 +1,188 @@ #!/bin/sh # # # NVMe-oF (rdma, tcp, fc) OCF RA. Exports and manages NVMe targets. # # (c) 2021 LINBIT HA-Solutions GmbH, written by Philipp Reisner # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Further, this software is distributed without any warranty that it is # free of the rightful claim of any third person regarding infringement # or the like. Any license provided herein, whether implied or # otherwise, applies only to this software file. Patent licenses, if # any, provided herein do not apply to combinations of this program with # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # ####################################################################### # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs OCF_RESKEY_allowed_initiators_default="" : ${OCF_RESKEY_allowed_initiators=${OCF_RESKEY_allowed_initiators_default}} OCF_RESKEY_serial_default="" : ${OCF_RESKEY_serial=${OCF_RESKEY_serial_default}} ####################################################################### meta_data() { cat < 1.0 Manages NVMe-oF subsystems. An NVMe-oF subsystem is part of an NVMe-oF target. A subsystem must be created first, before namespace(s) and port(s). NVMe-oF target export agent The NVMe Qualified Name (NQN) is used to identify the remote NVMe storage target. It is similar to an iSCSI Qualified Name (IQN). While it is a free-form string, you should follow the convention: nqn.2014-08.com.vendor:nvme:nvm-subsystem-sn-12345 NVMe Qualified Name Allowed initiators. A space-separated list of initiators allowed to connect to this target. Initiators are identified by their NQN. If the list is empty, any initiator will be allowed to connect. List of NVMe initiators allowed to connect to this target The serial of the subsystem. Set it to a random 16 character hex value. Use hexdump -n 8 -e '4/4 "%08x" 1 "\n"' /dev/urandom List of NVMe initiators allowed to connect to this target END } ####################################################################### nvmet_subsystem_usage() { cat < ${subsys}/attr_serial if [ -z "${OCF_RESKEY_allowed_initiators}" ]; then echo 1 > ${subsys}/attr_allow_any_host else local hosts_dir=/sys/kernel/config/nvmet/hosts echo 0 > ${subsys}/attr_allow_any_host - for hostnqn in "${OCF_RESKEY_allowed_initiators}"; do + for hostnqn in ${OCF_RESKEY_allowed_initiators}; do mkdir -p ${hosts_dir}/${hostnqn} ln -s ${hosts_dir}/${hostnqn} ${subsys}/allowed_hosts done fi nvmet_subsystem_monitor } nvmet_subsystem_stop() { nvmet_subsystem_monitor if [ $? -eq $OCF_NOT_RUNNING ]; then return $OCF_SUCCESS fi rmdir /sys/kernel/config/nvmet/subsystems/${OCF_RESKEY_nqn} return $OCF_SUCCESS } nvmet_subsystem_monitor() { [ -d /sys/kernel/config/nvmet/subsystems/${OCF_RESKEY_nqn} ] || return $OCF_NOT_RUNNING return $OCF_SUCCESS } nvmet_subsystem_validate() { if [ ! -d /sys/kernel/config/nvmet ]; then ocf_log err "/sys/kernel/config/nvmet does not exist -- Load the nvmet.ko linux kernel module." exit $OCF_ERR_INSTALLED fi return $OCF_SUCCESS } case $1 in meta-data) meta_data exit $OCF_SUCCESS ;; usage|help) nvmet_subsystem_usage exit $OCF_SUCCESS ;; esac # Everything except usage and meta-data must pass the validate test nvmet_subsystem_validate case $__OCF_ACTION in start) nvmet_subsystem_start;; stop) nvmet_subsystem_stop;; monitor|status) nvmet_subsystem_monitor;; reload) ocf_log info "Reloading..." nvmet_subsystem_start ;; validate-all) ;; *) nvmet_subsystem_usage exit $OCF_ERR_UNIMPLEMENTED ;; esac rc=$? ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" exit $rc diff --git a/heartbeat/rabbitmq-server-ha.ocf b/heartbeat/rabbitmq-server-ha similarity index 99% rename from heartbeat/rabbitmq-server-ha.ocf rename to heartbeat/rabbitmq-server-ha index 2425e0fed..1e08802bd 100755 --- a/heartbeat/rabbitmq-server-ha.ocf +++ b/heartbeat/rabbitmq-server-ha @@ -1,2437 +1,2437 @@ #!/bin/sh # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # See usage() function below for more details ... # # Note that the script uses an external file to setup RabbitMQ policies # so make sure to create it from an example shipped with the package. # ####################################################################### # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ####################################################################### # Fill in some defaults if no values are specified PATH=/sbin:/usr/sbin:/bin:/usr/bin OCF_RESKEY_binary_default="/usr/sbin/rabbitmq-server" OCF_RESKEY_ctl_default="/usr/sbin/rabbitmqctl" OCF_RESKEY_debug_default=false OCF_RESKEY_username_default="rabbitmq" OCF_RESKEY_groupname_default="rabbitmq" OCF_RESKEY_admin_user_default="guest" OCF_RESKEY_admin_password_default="guest" OCF_RESKEY_definitions_dump_file_default="/etc/rabbitmq/definitions" OCF_RESKEY_pid_file_default="/var/run/rabbitmq/pid" OCF_RESKEY_log_dir_default="/var/log/rabbitmq" OCF_RESKEY_mnesia_base_default="/var/lib/rabbitmq/mnesia" OCF_RESKEY_mnesia_schema_base_default="/var/lib/rabbitmq" OCF_RESKEY_host_ip_default="127.0.0.1" OCF_RESKEY_node_port_default=5672 OCF_RESKEY_default_vhost_default="/" OCF_RESKEY_erlang_cookie_default=false OCF_RESKEY_erlang_cookie_file_default="/var/lib/rabbitmq/.erlang.cookie" OCF_RESKEY_use_fqdn_default=false OCF_RESKEY_fqdn_prefix_default="" OCF_RESKEY_max_rabbitmqctl_timeouts_default=3 OCF_RESKEY_policy_file_default="/usr/local/sbin/set_rabbitmq_policy" OCF_RESKEY_rmq_feature_health_check_default=true OCF_RESKEY_rmq_feature_local_list_queues_default=true OCF_RESKEY_limit_nofile_default=65535 OCF_RESKEY_avoid_using_iptables_default=false OCF_RESKEY_allowed_cluster_nodes_default="" : ${HA_LOGTAG="lrmd"} : ${HA_LOGFACILITY="daemon"} : ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} : ${OCF_RESKEY_ctl=${OCF_RESKEY_ctl_default}} : ${OCF_RESKEY_debug=${OCF_RESKEY_debug_default}} : ${OCF_RESKEY_username=${OCF_RESKEY_username_default}} : ${OCF_RESKEY_groupname=${OCF_RESKEY_groupname_default}} : ${OCF_RESKEY_admin_user=${OCF_RESKEY_admin_user_default}} : ${OCF_RESKEY_admin_password=${OCF_RESKEY_admin_password_default}} : ${OCF_RESKEY_definitions_dump_file=${OCF_RESKEY_definitions_dump_file_default}} : ${OCF_RESKEY_log_dir=${OCF_RESKEY_log_dir_default}} : ${OCF_RESKEY_mnesia_base=${OCF_RESKEY_mnesia_base_default}} : ${OCF_RESKEY_mnesia_schema_base=${OCF_RESKEY_mnesia_schema_base_default}} : ${OCF_RESKEY_pid_file=${OCF_RESKEY_pid_file_default}} : ${OCF_RESKEY_node_port=${OCF_RESKEY_node_port_default}} : ${OCF_RESKEY_default_vhost=${OCF_RESKEY_default_vhost_default}} : ${OCF_RESKEY_erlang_cookie=${OCF_RESKEY_erlang_cookie_default}} : ${OCF_RESKEY_erlang_cookie_file=${OCF_RESKEY_erlang_cookie_file_default}} : ${OCF_RESKEY_use_fqdn=${OCF_RESKEY_use_fqdn_default}} : ${OCF_RESKEY_fqdn_prefix=${OCF_RESKEY_fqdn_prefix_default}} : ${OCF_RESKEY_max_rabbitmqctl_timeouts=${OCF_RESKEY_max_rabbitmqctl_timeouts_default}} : ${OCF_RESKEY_policy_file=${OCF_RESKEY_policy_file_default}} : ${OCF_RESKEY_rmq_feature_health_check=${OCF_RESKEY_rmq_feature_health_check_default}} : ${OCF_RESKEY_rmq_feature_local_list_queues=${OCF_RESKEY_rmq_feature_local_list_queues_default}} : ${OCF_RESKEY_limit_nofile=${OCF_RESKEY_limit_nofile_default}} : ${OCF_RESKEY_avoid_using_iptables=${OCF_RESKEY_avoid_using_iptables_default}} : ${OCF_RESKEY_allowed_cluster_nodes=${OCF_RESKEY_allowed_cluster_nodes_default}} ####################################################################### OCF_RESKEY_CRM_meta_timeout_default=30000 : ${OCF_RESKEY_CRM_meta_timeout=${OCF_RESKEY_CRM_meta_timeout_default}} OCF_RESKEY_start_time_default=$((OCF_RESKEY_CRM_meta_timeout / 6000 + 2)) : ${OCF_RESKEY_start_time=${OCF_RESKEY_start_time_default}} OCF_RESKEY_stop_time_default=${OCF_RESKEY_start_time_default} : ${OCF_RESKEY_stop_time=${OCF_RESKEY_start_time_default}} OCF_RESKEY_command_timeout_default="" : ${OCF_RESKEY_command_timeout=${OCF_RESKEY_command_timeout_default}} TIMEOUT_ARG=$((OCF_RESKEY_CRM_meta_timeout / 6000 + 30)) COMMAND_TIMEOUT="/usr/bin/timeout ${OCF_RESKEY_command_timeout} ${TIMEOUT_ARG}" RESOURCE_NAME=`echo $OCF_RESOURCE_INSTANCE | cut -d ":" -f 1` ####################################################################### usage() { cat < - + 1.0 Resource agent for RabbitMQ promotes a Master, then cluster nodes can join it Resource agent for RabbitMQ HA cluster RabbitMQ binary RabbitMQ binary rabbitctl binary rabbitctl binary binary RabbitMQ PID file RabbitMQ PID file RabbitMQ log directory RabbitMQ log directory RabbitMQ user name RabbitMQ user name RabbitMQ group name RabbitMQ group name RabbitMQ default admin user for API RabbitMQ admin user RabbitMQ default admin user password for API RabbitMQ admin password RabbitMQ default definitions dump file RabbitMQ definitions dump file Timeout command arguments for issued commands termination (value is auto evaluated) Arguments for timeout wrapping command Timeout for start rabbitmq server Timeout for start rabbitmq server Timeout for stopping rabbitmq server Timeout for stopping rabbitmq server The debug flag for agent (${OCF_RESKEY_binary}) instance. In the /tmp/ directory will be created rmq-* files for log some operations and ENV values inside OCF-script. AMQP server (${OCF_RESKEY_binary}) debug flag Base directory for storing Mnesia files Base directory for storing Mnesia files Parent directory for Mnesia schema directory Parent directory for Mnesia schema directory ${OCF_RESKEY_binary} should listen on this IP address ${OCF_RESKEY_binary} should listen on this IP address ${OCF_RESKEY_binary} should listen on this port ${OCF_RESKEY_binary} should listen on this port Default virtual host used for monitoring if a node is fully synchronized with the rest of the cluster. In normal operation, the resource agent will wait for queues from this virtual host on this node to be synchronized elsewhere before stopping RabbitMQ. This also means queues in other virtual hosts may not be fully synchronized on stop operations. Default virtual host used for waiting for synchronization Erlang cookie for clustering. If specified, will be updated at the mnesia reset Erlang cookie Erlang cookie file path where the cookie will be put, if requested Erlang cookie file Either to use FQDN or a shortname for the rabbitmq node Use FQDN Optional FQDN prefix for RabbitMQ nodes in cluster. FQDN prefix can be specified to host multiple RabbitMQ instances on a node or in case of RabbitMQ running in dedicated network/interface. FQDN prefix If during monitor call rabbitmqctl times out, the timeout is ignored unless it is Nth timeout in a row. Here N is the value of the current parameter. If too many timeouts happen in a raw, the monitor call will return with error. Fail only if that many rabbitmqctl timeouts in a row occurred A path to the shell script to setup RabbitMQ policies A policy file path Since rabbit 3.6.4 list_queues/list_channels-based monitoring should be replaced with "node_health_check" command, as it creates no network load at all. Use node_health_check for monitoring For rabbit version that implements --local flag for list_queues, this can greatly reduce network overhead in cases when node is stopped/demoted. Use --local option for list_queues Soft and hard limit for NOFILE NOFILE limit When set to true the iptables calls to block client access become noops. This is useful when we run inside containers. Disable iptables use entirely When set to anything other than the empty string it must container the list of cluster node names, separated by spaces, where the rabbitmq resource is allowed to run. Tis is needed when rabbitmq is running on a subset of nodes part of a larger cluster. The default ("") is to assume that all nodes part of the cluster will run the rabbitmq resource. List of cluster nodes where rabbitmq is allowed to run $EXTENDED_OCF_PARAMS - - - - - - - - - - + + + + + + + + + + END } MIN_MASTER_SCORE=100 BEST_MASTER_SCORE=1000 ####################################################################### # Functions invoked by resource manager actions #TODO(bogdando) move proc_kill, proc_stop to shared OCF functions # to be shipped with HA cluster packages ########################################################### # Attempts to kill a process with retries and checks procfs # to make sure the process is stopped. # # Globals: # LL # Arguments: # $1 - pid of the process to try and kill # $2 - service name used for logging and match-based kill, if the pid is "none" # $3 - signal to use, defaults to SIGTERM # $4 - number of retries, defaults to 5 # $5 - time to sleep between retries, defaults to 2 # Returns: # 0 - if successful # 1 - if process is still running according to procfs # 2 - if invalid parameters passed in ########################################################### proc_kill() { local pid="${1}" local service_name="${2}" local signal="${3:-SIGTERM}" local count="${4:-5}" local process_sleep="${5:-2}" local LH="${LL} proc_kill():" local pgrp="$(ps -o pgid= ${pid} 2>/dev/null | tr -d '[[:space:]]')" if [ "${pid}" ] && [ "${pgrp}" = "1" ] ; then ocf_log err "${LH} shall not kill by the bad pid 1 (init)!" return 2 fi if [ "${pid}" = "none" ]; then local matched matched="$(pgrep -fla ${service_name})" if [ -z "${matched}" ] ; then ocf_log info "${LH} cannot find any processes matching the ${service_name}, considering target process to be already dead" return 0 fi ocf_log debug "${LH} no pid provided, will try the ${service_name}, matched list: ${matched}" while [ $count -gt 0 ]; do if [ -z "${matched}" ]; then break else matched="$(pgrep -fla ${service_name})" ocf_log debug "${LH} Stopping ${service_name} with ${signal}..." ocf_run pkill -f -"${signal}" "${service_name}" fi sleep $process_sleep count=$(( count-1 )) done pgrep -f "${service_name}" > /dev/null if [ $? -ne 0 ] ; then ocf_log debug "${LH} Stopped ${service_name} with ${signal}" return 0 else ocf_log warn "${LH} Failed to stop ${service_name} with ${signal}" return 1 fi else # pid is not none while [ $count -gt 0 ]; do if [ ! -d "/proc/${pid}" ]; then break else ocf_log debug "${LH} Stopping ${service_name} with ${signal}..." ocf_run pkill -"${signal}" -g "${pgrp}" fi sleep $process_sleep count=$(( count-1 )) done # Check if the process ended after the last sleep if [ ! -d "/proc/${pid}" ] ; then ocf_log debug "${LH} Stopped ${service_name} with ${signal}" return 0 fi ocf_log warn "${LH} Failed to stop ${service_name} with ${signal}" return 1 fi } ########################################################### # Attempts to kill a process with the given pid or pid file # using proc_kill and will retry with sigkill if sigterm is # unsuccessful. # # Globals: # OCF_ERR_GENERIC # OCF_SUCCESS # LL # Arguments: # $1 - pidfile or pid or 'none', if stopping by the name matching # $2 - service name used for logging or for the failback stopping method # $3 - stop process timeout (in sec), used to determine how many times we try # SIGTERM and an upper limit on how long this function should try and # stop the process. Defaults to 15. # Returns: # OCF_SUCCESS - if successful # OCF_ERR_GENERIC - if process is still running according to procfs ########################################################### proc_stop() { local pid_param="${1}" local service_name="${2}" local timeout="${3:-15}" local LH="${LL} proc_stop():" local i local pid local pidfile if [ "${pid_param}" = "none" ] ; then pid="none" else # check if provide just a number echo "${pid_param}" | egrep -q '^[0-9]+$' if [ $? -eq 0 ]; then pid="${pid_param}" elif [ -e "${pid_param}" ]; then # check if passed in a pid file pidfile="${pid_param}" pid=$(cat "${pidfile}" 2>/dev/null | tr -s " " "\n" | sort -u) else ocf_log warn "${LH} pid param ${pid_param} is not a file or a number, try match by ${service_name}" pid="none" fi fi # number of times to try a SIGTEM is (timeout - 5 seconds) / 2 seconds local stop_count=$(( ($timeout-5)/2 )) # make sure we stop at least once if [ $stop_count -le 0 ]; then stop_count=1 fi if [ -z "${pid}" ] ; then ocf_log warn "${LH} unable to get PID from ${pidfile}, try match by ${service_name}" pid="none" fi if [ -n "${pid}" ]; then for i in ${pid} ; do [ "${i}" ] || break ocf_log info "${LH} Stopping ${service_name} by PID ${i}" proc_kill "${i}" "${service_name}" SIGTERM $stop_count if [ $? -ne 0 ]; then # SIGTERM failed, send a single SIGKILL proc_kill "${i}" "${service_name}" SIGKILL 1 2 if [ $? -ne 0 ]; then ocf_log err "${LH} ERROR: could not stop ${service_name}" return "${OCF_ERR_GENERIC}" fi fi done fi # Remove the pid file here which will remove empty pid files as well if [ -n "${pidfile}" ]; then rm -f "${pidfile}" fi ocf_log info "${LH} Stopped ${service_name}" return "${OCF_SUCCESS}" } # Invokes the given command as a rabbitmq user and wrapped in the # timeout command. su_rabbit_cmd() { local timeout if [ "$1" = "-t" ]; then timeout="/usr/bin/timeout ${OCF_RESKEY_command_timeout} $2" shift 2 else timeout=$COMMAND_TIMEOUT fi local cmd="${1:-status}" local LH="${LL} su_rabbit_cmd():" local rc=1 local user=$OCF_RESKEY_username local mail=/var/spool/mail/rabbitmq local pwd=/var/lib/rabbitmq local home=/var/lib/rabbitmq ocf_log debug "${LH} invoking a command: ${cmd}" su $user -s /bin/sh -c "USER=${user} MAIL=${mail} PWD=${pwd} HOME=${home} LOGNAME=${user} \ ${timeout} ${cmd}" rc=$? ocf_log info "${LH} the invoked command exited ${rc}: ${cmd}" return $rc } now() { date -u +%s } set_limits() { local current_limit=$(su $OCF_RESKEY_username -s /bin/sh -c "ulimit -n") if [ ! -z $OCF_RESKEY_limit_nofile ] && [ $OCF_RESKEY_limit_nofile -gt $current_limit ] ; then ulimit -n $OCF_RESKEY_limit_nofile fi } master_score() { local LH="${LL} master_score():" local score=$1 if [ -z $score ] ; then score=0 fi ocf_log info "${LH} Updating master score attribute with ${score}" ocf_run crm_master -N $THIS_PCMK_NODE -l reboot -v $score || return $OCF_ERR_GENERIC return $OCF_SUCCESS } # Return either FQDN or shortname, depends on the OCF_RESKEY_use_fqdn. get_hostname() { local os=$(uname -s) if [ "${OCF_RESKEY_use_fqdn}" = 'false' ] ; then if [ "$os" = "SunOS" ]; then echo "$(hostname | sed 's@\..*@@')" else echo "$(hostname -s)" fi else if [ "$os" = "SunOS" ]; then echo "$(hostname)" else echo "$(hostname -f)" fi fi } # Strip the FQDN to the shortname, if OCF_RESKEY_use_fqdn was set; # Prepend prefix to the hostname process_fqdn() { if [ "${OCF_RESKEY_use_fqdn}" = 'false' ] ; then echo "${OCF_RESKEY_fqdn_prefix}$1" | awk -F. '{print $1}' else echo "${OCF_RESKEY_fqdn_prefix}$1" fi } # Return OCF_SUCCESS, if current host is in the list of given hosts. # Otherwise, return 10 my_host() { local hostlist="$1" local hostname local hn local rc=10 local LH="${LL} my_host():" hostname=$(process_fqdn $(get_hostname)) ocf_log debug "${LH} hostlist is: $hostlist" for host in $hostlist ; do hn=$(process_fqdn "${host}") ocf_log debug "${LH} comparing '$hostname' with '$hn'" if [ "${hostname}" = "${hn}" ] ; then rc=$OCF_SUCCESS break fi done return $rc } get_integer_node_attr() { local value value=$(crm_attribute -N $1 -l reboot --name "$2" --query 2>/dev/null | awk '{ split($3, vals, "="); if (vals[2] != "(null)") print vals[2] }') if [ $? -ne 0 ] || [ -z "$value" ] ; then value=0 fi echo $value } get_node_start_time() { get_integer_node_attr $1 'rabbit-start-time' } get_node_master_score() { get_integer_node_attr $1 "master-${RESOURCE_NAME}" } # Return either rabbit node name as FQDN or shortname, depends on the OCF_RESKEY_use_fqdn. rabbit_node_name() { echo "rabbit@$(process_fqdn $(ocf_attribute_target $1))" } rmq_setup_env() { local H local dir H="$(get_hostname)" export RABBITMQ_NODENAME=$(rabbit_node_name $H) if [ "$OCF_RESKEY_node_port" != "$OCF_RESKEY_node_port_default" ]; then export RABBITMQ_NODE_PORT=$OCF_RESKEY_node_port fi export RABBITMQ_PID_FILE=$OCF_RESKEY_pid_file MNESIA_FILES="${OCF_RESKEY_mnesia_base}/$(rabbit_node_name $H)" export RABBITMQ_SERVER_START_ARGS="${RABBITMQ_SERVER_START_ARGS} -mnesia dir \"${MNESIA_FILES}\" -sname $(rabbit_node_name $H)" RMQ_START_TIME="${MNESIA_FILES}/ocf_server_start_time.txt" MASTER_FLAG_FILE="${MNESIA_FILES}/ocf_master_for_${OCF_RESOURCE_INSTANCE}" THIS_PCMK_NODE=$(ocf_attribute_target) TOTALVMEM=`free -mt | awk '/Total:/ {print $2}'` # check and make PID file dir local PID_DIR=$( dirname $OCF_RESKEY_pid_file ) if [ ! -d ${PID_DIR} ] ; then mkdir -p ${PID_DIR} chown -R ${OCF_RESKEY_username}:${OCF_RESKEY_groupname} ${PID_DIR} chmod 755 ${PID_DIR} fi # Regardless of whether we just created the directory or it # already existed, check whether it is writable by the configured # user for dir in ${PID_DIR} "${OCF_RESKEY_mnesia_base}" "${OCF_RESKEY_log_dir}"; do if test -e ${dir}; then local files files=$(su -s /bin/sh - $OCF_RESKEY_username -c "find ${dir} ! -writable") if [ "${files}" ]; then ocf_log warn "Directory ${dir} is not writable by ${OCF_RESKEY_username}, chowning." chown -R ${OCF_RESKEY_username}:${OCF_RESKEY_groupname} "${dir}" fi fi done export LL="${OCF_RESOURCE_INSTANCE}[$$]:" update_cookie } # Return a RabbitMQ node to its virgin state. # For reset and force_reset to succeed the RabbitMQ application must have been stopped. # If the app cannot be stopped, beam will be killed and mnesia files will be removed. reset_mnesia() { local LH="${LL} reset_mnesia():" local make_amnesia=false local rc=$OCF_ERR_GENERIC # check status of a beam process get_status rc=$? if [ $rc -eq 0 ] ; then # beam is running # check status of rabbit app and stop it, if it is running get_status rabbit rc=$? if [ $rc -eq 0 ] ; then # rabbit app is running, have to stop it ocf_log info "${LH} Stopping RMQ-app prior to reset the mnesia." stop_rmq_server_app rc=$? if [ $rc -ne 0 ] ; then ocf_log warn "${LH} RMQ-app can't be stopped." make_amnesia=true fi fi if ! $make_amnesia ; then # rabbit app is not running, reset mnesia ocf_log info "${LH} Execute reset with timeout: ${TIMEOUT_ARG}" su_rabbit_cmd "${OCF_RESKEY_ctl} reset" rc=$? if [ $rc -ne 0 ] ; then ocf_log info "${LH} Execute force_reset with timeout: ${TIMEOUT_ARG}" su_rabbit_cmd "${OCF_RESKEY_ctl} force_reset" rc=$? if [ $rc -ne 0 ] ; then ocf_log warn "${LH} Mnesia couldn't cleaned, even by force-reset command." make_amnesia=true fi fi fi else # there is no beam running make_amnesia=true ocf_log warn "${LH} There is no Beam process running." fi # remove mnesia files, if required if $make_amnesia ; then kill_rmq_and_remove_pid ocf_run rm -rf "${MNESIA_FILES}" mnesia_schema_location="${OCF_RESKEY_mnesia_schema_base}/Mnesia.$(rabbit_node_name $(get_hostname))" ocf_run rm -rf "$mnesia_schema_location" ocf_log warn "${LH} Mnesia files appear corrupted and have been removed from ${MNESIA_FILES} and $mnesia_schema_location" fi # always return OCF SUCCESS return $OCF_SUCCESS } block_client_access() { # When OCF_RESKEY_avoid_using_iptables is true iptables calls are noops if [ "${OCF_RESKEY_avoid_using_iptables}" = 'true' ] ; then return $OCF_SUCCESS fi # do not add temporary RMQ blocking rule, if it is already exist # otherwise, try to add a blocking rule with max of 5 retries local tries=5 until $(iptables -nvL --wait | grep -q 'temporary RMQ block') || [ $tries -eq 0 ]; do tries=$((tries-1)) iptables --wait -I INPUT -p tcp -m tcp --dport ${OCF_RESKEY_node_port} -m state --state NEW,RELATED,ESTABLISHED \ -m comment --comment 'temporary RMQ block' -j REJECT --reject-with tcp-reset sleep 1 done if [ $tries -eq 0 ]; then return $OCF_ERR_GENERIC else return $OCF_SUCCESS fi } unblock_client_access() { local lhtext="none" if [ -z $1 ] ; then lhtext=$1 fi # When OCF_RESKEY_avoid_using_iptables is true iptables calls are noops if [ "${OCF_RESKEY_avoid_using_iptables}" = 'true' ] ; then return fi # remove all temporary RMQ blocking rules, if there are more than one exist for i in $(iptables -nvL --wait --line-numbers | awk '/temporary RMQ block/ {print $1}'); do iptables --wait -D INPUT -p tcp -m tcp --dport ${OCF_RESKEY_node_port} -m state --state NEW,RELATED,ESTABLISHED \ -m comment --comment 'temporary RMQ block' -j REJECT --reject-with tcp-reset done ocf_log info "${lhtext} unblocked access to RMQ port" } get_nodes__base(){ local infotype='' local rc=$OCF_ERR_GENERIC local c_status if [ "$1" = 'nodes' ] then infotype='db_nodes' elif [ "$1" = 'running' ] then infotype='running_db_nodes' fi c_status=`${OCF_RESKEY_ctl} eval "mnesia:system_info(${infotype})." 2>/dev/null` rc=$? if [ $rc -ne 0 ] ; then echo '' return $OCF_ERR_GENERIC fi # translate line like '{running_nodes,['rabbit@node-1','rabbit@node-2','rabbit@node-3']},' to node_list echo $(echo "${c_status}" | awk -F, '{ for (i=1;i<=NF;i++) { if ($i ~ /@/) { gsub(/[\[\]}{]/,"",$i); print $i; } }}' | tr -d "\'") return $OCF_SUCCESS } get_nodes() { echo $(get_nodes__base nodes) return $? } get_running_nodes() { echo $(get_nodes__base running) return $? } # Get alive cluster nodes in visible partition, but the specified one get_alive_pacemaker_nodes_but() { if [ -z "$1" ]; then tmp_pcmk_node_list=`crm_node -l -p | sed -e '/(null)/d'` else tmp_pcmk_node_list=`crm_node -l -p | sed -e "s/${1}//g" | sed -e '/(null)/d'` fi # If OCF_RESKEY_allowed_cluster_nodes is set then we only want the intersection # of the cluster node output and the allowed_cluster_nodes list if [ -z "${OCF_RESKEY_allowed_cluster_nodes}" ]; then pcmk_node_list=$tmp_pcmk_node_list else pcmk_node_list=`for i in $tmp_pcmk_node_list ${OCF_RESKEY_allowed_cluster_nodes}; do echo $i; done | sort | uniq -d` fi echo $pcmk_node_list } # Get current master. If a parameter is provided, # do not check node with that name get_master_name_but() { local node for node in $(get_alive_pacemaker_nodes_but "$@") do ocf_log info "${LH} looking if $node is master" if is_master $node; then ocf_log info "${LH} master is $node" echo $node break fi done } # Evals some erlang code on current node erl_eval() { local fmt="${1:?}" shift $COMMAND_TIMEOUT ${OCF_RESKEY_ctl} eval "$(printf "$fmt" "$@")" 2>/dev/null } # Returns 0 if we are clustered with provideded node is_clustered_with() { local LH="${LH}: is_clustered_with: " local node_name local rc node_name=$(rabbit_node_name $1) local seen_as_running seen_as_running=$(erl_eval "lists:member('%s', rabbit_mnesia:cluster_nodes(running))." "$node_name") rc=$? if [ "$rc" -ne 0 ]; then ocf_log err "${LH} Failed to check whether '$node_name' is considered running by us" # We had a transient local error; that doesn't mean the remote node is # not part of the cluster, so ignore this elif [ "$seen_as_running" != true ]; then ocf_log info "${LH} Node $node_name is not running, considering it not clustered with us" return 1 fi local seen_as_partitioned seen_as_partitioned=$(erl_eval "lists:member('%s', rabbit_node_monitor:partitions())." "$node_name") rc=$? if [ "$rc" -ne 0 ]; then ocf_log err "${LH} Failed to check whether '$node_name' is partitioned with us" # We had a transient local error; that doesn't mean the remote node is # partitioned with us, so ignore this elif [ "$seen_as_partitioned" != false ]; then ocf_log info "${LH} Node $node_name is partitioned from us" return 1 fi return $? } check_need_join_to() { local join_to local node local running_nodes local rc=$OCF_ERR_GENERIC rc=0 join_to=$(rabbit_node_name $1) running_nodes=$(get_running_nodes) for node in $running_nodes ; do if [ "${join_to}" = "${node}" ] ; then rc=1 break fi done return $rc } # Update erlang cookie, if it has been specified update_cookie() { local cookie_file_content if [ "${OCF_RESKEY_erlang_cookie}" != 'false' ] ; then if [ -f "${OCF_RESKEY_erlang_cookie_file}" ]; then # First line of cookie file without newline cookie_file_content=$(head -n1 "${OCF_RESKEY_erlang_cookie_file}" | perl -pe chomp) fi # As there is a brief period of time when the file is empty # (shell redirection has already opened and truncated file, # and echo hasn't finished its job), we are doing this write # only when cookie has changed. if [ "${OCF_RESKEY_erlang_cookie}" != "${cookie_file_content}" ]; then echo "${OCF_RESKEY_erlang_cookie}" > "${OCF_RESKEY_erlang_cookie_file}" fi # And this are idempotent operations, so we don't have to # check any preconditions for running them. chown ${OCF_RESKEY_username}:${OCF_RESKEY_groupname} "${OCF_RESKEY_erlang_cookie_file}" chmod 600 "${OCF_RESKEY_erlang_cookie_file}" fi return $OCF_SUCCESS } # Stop rmq beam process by pid and by rabbit node name match. Returns SUCCESS/ERROR kill_rmq_and_remove_pid() { local LH="${LL} kill_rmq_and_remove_pid():" # Stop the rabbitmq-server by its pidfile, use the name matching as a fallback, # and ignore the exit code proc_stop "${OCF_RESKEY_pid_file}" "beam.*${RABBITMQ_NODENAME}" "${OCF_RESKEY_stop_time}" # Ensure the beam.smp stopped by the rabbit node name matching as well proc_stop none "beam.*${RABBITMQ_NODENAME}" "${OCF_RESKEY_stop_time}" if [ $? -eq 0 ] ; then return $OCF_SUCCESS else return $OCF_ERR_GENERIC fi } trim_var(){ local string="$*" echo ${string%% } } action_validate() { # todo(sv): validate some incoming parameters OCF_RESKEY_CRM_meta_notify_post=$(trim_var $OCF_RESKEY_CRM_meta_notify_post) OCF_RESKEY_CRM_meta_notify_pre=$(trim_var $OCF_RESKEY_CRM_meta_notify_pre) OCF_RESKEY_CRM_meta_notify_start=$(trim_var $OCF_RESKEY_CRM_meta_notify_start) OCF_RESKEY_CRM_meta_notify_stop=$(trim_var $OCF_RESKEY_CRM_meta_notify_stop) OCF_RESKEY_CRM_meta_notify_start_resource=$(trim_var $OCF_RESKEY_CRM_meta_notify_start_resource) OCF_RESKEY_CRM_meta_notify_stop_resource=$(trim_var $OCF_RESKEY_CRM_meta_notify_stop_resource) OCF_RESKEY_CRM_meta_notify_active_resource=$(trim_var $OCF_RESKEY_CRM_meta_notify_active_resource) OCF_RESKEY_CRM_meta_notify_inactive_resource=$(trim_var $OCF_RESKEY_CRM_meta_notify_inactive_resource) OCF_RESKEY_CRM_meta_notify_start_uname=$(trim_var $OCF_RESKEY_CRM_meta_notify_start_uname) OCF_RESKEY_CRM_meta_notify_stop_uname=$(trim_var $OCF_RESKEY_CRM_meta_notify_stop_uname) OCF_RESKEY_CRM_meta_notify_active_uname=$(trim_var $OCF_RESKEY_CRM_meta_notify_active_uname) OCF_RESKEY_CRM_meta_notify_master_resource=$(trim_var $OCF_RESKEY_CRM_meta_notify_master_resource) OCF_RESKEY_CRM_meta_notify_master_uname=$(trim_var $OCF_RESKEY_CRM_meta_notify_master_uname) OCF_RESKEY_CRM_meta_notify_demote_resource=$(trim_var $OCF_RESKEY_CRM_meta_notify_demote_resource) OCF_RESKEY_CRM_meta_notify_demote_uname=$(trim_var $OCF_RESKEY_CRM_meta_notify_demote_uname) OCF_RESKEY_CRM_meta_notify_slave_resource=$(trim_var $OCF_RESKEY_CRM_meta_notify_slave_resource) OCF_RESKEY_CRM_meta_notify_slave_uname=$(trim_var $OCF_RESKEY_CRM_meta_notify_slave_uname) OCF_RESKEY_CRM_meta_notify_promote_resource=$(trim_var $OCF_RESKEY_CRM_meta_notify_promote_resource) OCF_RESKEY_CRM_meta_notify_promote_uname=$(trim_var $OCF_RESKEY_CRM_meta_notify_promote_uname) return $OCF_SUCCESS } update_rabbit_start_time_if_rc() { local nowtime local rc=$1 if [ $rc -eq 0 ]; then nowtime="$(now)" ocf_log info "${LH} Rabbit app started successfully. Updating start time attribute with ${nowtime}" ocf_run crm_attribute -N $THIS_PCMK_NODE -l reboot --name 'rabbit-start-time' --update "${nowtime}" fi } join_to_cluster() { local node="$1" local rmq_node local rc=$OCF_ERR_GENERIC local LH="${LL} join_to_cluster():" ocf_log info "${LH} start." rmq_node=$(rabbit_node_name $node) ocf_log info "${LH} Joining to cluster by node '${rmq_node}'." get_status rabbit rc=$? if [ $rc -eq $OCF_SUCCESS ] ; then ocf_log info "${LH} rabbitmq app will be stopped." stop_rmq_server_app rc=$? if [ $rc -ne 0 ] ; then ocf_log err "${LH} Can't stop rabbitmq app by stop_app command. Stopping." action_stop return $OCF_ERR_GENERIC fi fi ocf_log info "${LH} Execute join_cluster with timeout: ${TIMEOUT_ARG}" su_rabbit_cmd "${OCF_RESKEY_ctl} join_cluster $rmq_node" rc=$? if [ $rc -ne 0 ] ; then ocf_log err "${LH} Can't join to cluster by node '${rmq_node}'. Stopping." action_stop return $OCF_ERR_GENERIC fi sleep 2 try_to_start_rmq_app rc=$? if [ $rc -ne 0 ] ; then ocf_log err "${LH} Can't start RMQ app after join to cluster. Stopping." action_stop return $OCF_ERR_GENERIC else update_rabbit_start_time_if_rc 0 ocf_log info "${LH} Joined to cluster succesfully." fi ocf_log info "${LH} end." return $rc } unjoin_nodes_from_cluster() { # node names of the nodes where the pcs resource is being stopped local nodelist="$1" local hostname local nodename local rc=$OCF_ERR_GENERIC local rnode # nodes in rabbit cluster db local nodes_in_cluster local LH="${LL} unjoin_nodes_from_cluster():" nodes_in_cluster=$(get_nodes) rc=$? if [ $rc -ne 0 ] ; then # no nodes in node list, nothing to do return $OCF_SUCCESS fi # unjoin all cluster nodes which are being stopped (i.e. recieved post-stop notify), except *this* node # before to unjoin the nodes, make sure they were disconnected from *this* node for hostname in $nodelist ; do nodename=$(rabbit_node_name $hostname) if [ "${nodename}" = "${RABBITMQ_NODENAME}" ] ; then continue fi for rnode in $nodes_in_cluster ; do if [ "${nodename}" = "${rnode}" ] ; then # disconnect node being unjoined from this node ocf_run ${OCF_RESKEY_ctl} eval "disconnect_node(list_to_atom(\"${nodename}\"))." 2>&1 rc=$? if [ $rc -eq $OCF_SUCCESS ] ; then ocf_log info "${LH} node '${nodename}' disconnected succesfully." else ocf_log info "${LH} disconnecting node '${nodename}' failed." fi # unjoin node # when the rabbit node went down, its status # remains 'running' for a while, so few retries are required local tries=0 until [ $tries -eq 5 ]; do tries=$((tries+1)) if is_clustered_with $nodename; then ocf_log info "${LH} the ${nodename} is alive and cannot be kicked from the cluster yet" else break fi sleep 10 done ocf_log info "${LH} Execute forget_cluster_node with timeout: ${TIMEOUT_ARG}" su_rabbit_cmd "${OCF_RESKEY_ctl} forget_cluster_node ${nodename}" rc=$? if [ $rc -eq 0 ] ; then ocf_log info "${LH} node '${nodename}' unjoined succesfully." else ocf_log warn "${LH} unjoining node '${nodename}' failed." fi fi done done return $OCF_SUCCESS } # Stop RMQ beam server process. Returns SUCCESS/ERROR stop_server_process() { local pid local rc=$OCF_ERR_GENERIC local LH="${LL} stop_server_process():" pid=$(cat ${OCF_RESKEY_pid_file}) rc=$? if [ $rc -ne 0 ] ; then # Try to stop without known PID ocf_log err "${LH} RMQ-server process PIDFILE was not found!" su_rabbit_cmd "${OCF_RESKEY_ctl} stop >> \"${OCF_RESKEY_log_dir}/shutdown_log\" 2>&1" if [ $? -eq 0 ] ; then ocf_log info "${LH} RMQ-server process stopped succesfully, although there was no PIDFILE found." ocf_log info "${LH} grant a graceful termintation window ${OCF_RESKEY_stop_time} to end its beam" sleep "${OCF_RESKEY_stop_time}" else kill_rmq_and_remove_pid fi elif [ "${pid}" ] ; then # Try to stop gracefully by known PID ocf_log info "${LH} Execute stop with timeout: ${TIMEOUT_ARG}" su_rabbit_cmd "${OCF_RESKEY_ctl} stop ${OCF_RESKEY_pid_file} >> \"${OCF_RESKEY_log_dir}/shutdown_log\" 2>&1" [ $? -eq 0 ] && ocf_log info "${LH} RMQ-server process (PID=${pid}) stopped succesfully." fi # Ensure there is no beam process and pidfile left pgrep -f "beam.*${RABBITMQ_NODENAME}" > /dev/null rc=$? if [ -f ${OCF_RESKEY_pid_file} ] || [ $rc -eq 0 ] ; then ocf_log warn "${LH} The pidfile or beam's still exist, forcing the RMQ-server cleanup" kill_rmq_and_remove_pid return $? else return $OCF_SUCCESS fi } # Stop RMQ-app. Return OCF_SUCCESS, if the app was stopped, # otherwise return OCF_ERR_GENERIC stop_rmq_server_app() { local rc=$OCF_ERR_GENERIC # if the beam process isn't running, then rabbit app is stopped as well get_status rc=$? if [ $rc -ne 0 ] ; then return $OCF_SUCCESS fi # stop the app ocf_log info "${LH} Execute stop_app with timeout: ${TIMEOUT_ARG}" su_rabbit_cmd "${OCF_RESKEY_ctl} stop_app >> \"${OCF_RESKEY_log_dir}/shutdown_log\" 2>&1" rc=$? if [ $rc -ne 0 ] ; then ocf_log err "${LH} RMQ-server app cannot be stopped." return $OCF_ERR_GENERIC fi get_status rabbit rc=$? if [ $rc -ne $OCF_SUCCESS ] ; then ocf_log info "${LH} RMQ-server app stopped succesfully." rc=$OCF_SUCCESS else ocf_log err "${LH} RMQ-server app cannot be stopped." rc=$OCF_ERR_GENERIC fi return $rc } start_beam_process() { local command local rc=$OCF_ERR_GENERIC local ts_end local pf_end local pid local LH="${LL} start_beam_process():" # remove old PID-file if it exists if [ -f "${OCF_RESKEY_pid_file}" ] ; then ocf_log warn "${LH} found old PID-file '${OCF_RESKEY_pid_file}'." pid=$(cat ${OCF_RESKEY_pid_file}) if [ "${pid}" ] && [ -d "/proc/${pid}" ] ; then ocf_run cat /proc/${pid}/cmdline | grep -c 'bin/beam' > /dev/null 2>&1 rc=$? if [ $rc -eq $OCF_SUCCESS ] ; then ocf_log warn "${LH} found beam process with PID=${pid}, killing...'." ocf_run kill -TERM $pid else ocf_log err "${LH} found unknown process with PID=${pid} from '${OCF_RESKEY_pid_file}'." return $OCF_ERR_GENERIC fi fi ocf_run rm -f $OCF_RESKEY_pid_file fi [ -f /etc/default/rabbitmq-server ] && . /etc/default/rabbitmq-server # RabbitMQ requires high soft and hard limits for NOFILE set_limits # run beam process command="${OCF_RESKEY_binary} >> \"${OCF_RESKEY_log_dir}/startup_log\" 2>/dev/null" RABBITMQ_NODE_ONLY=1 su rabbitmq -s /bin/sh -c "${command}"& ts_end=$(( $(now) + ${OCF_RESKEY_start_time} )) sleep 3 # give it some time, before attempting to start_app # PID-file is now created later, if the application started successfully # So assume beam.smp is started, and defer errors handling for start_app return $OCF_SUCCESS } check_plugins() { # Check if it's safe to load plugins and if we need to do so. Logic is: # if (EnabledPlugins > 0) and (ActivePlugins == 0) ; then it's safe to load # If we have at least one active plugin, then it's not safe to re-load them # because plugins:setup() would remove existing dependency plugins in plugins_expand_dir. ${OCF_RESKEY_ctl} eval '{ok, EnabledFile} = application:get_env(rabbit, enabled_plugins_file), EnabledPlugins = rabbit_plugins:read_enabled(EnabledFile), ActivePlugins = rabbit_plugins:active(), if length(EnabledPlugins)>0 -> if length(ActivePlugins)==0 -> erlang:error("need_to_load_plugins"); true -> false end; true -> false end.' return $? } load_plugins() { check_plugins local rc=$? if [ $rc -eq 0 ] ; then return 0 else ${OCF_RESKEY_ctl} eval 'ToBeLoaded = rabbit_plugins:setup(), ok = app_utils:load_applications(ToBeLoaded), StartupApps = app_utils:app_dependency_order(ToBeLoaded,false), app_utils:start_applications(StartupApps).' return $? fi } list_active_plugins() { local list list=`${OCF_RESKEY_ctl} eval 'rabbit_plugins:active().' 2>/dev/null` echo "${list}" } try_to_start_rmq_app() { local startup_log="${1:-${OCF_RESKEY_log_dir}/startup_log}" local rc=$OCF_ERR_GENERIC local LH="${LL} try_to_start_rmq_app():" get_status rc=$? if [ $rc -ne $OCF_SUCCESS ] ; then ocf_log info "${LH} RMQ-runtime (beam) not started, starting..." start_beam_process rc=$? if [ $rc -ne $OCF_SUCCESS ]; then ocf_log err "${LH} Failed to start beam - returning from the function" return $OCF_ERR_GENERIC fi fi if [ -z "${startup_log}" ] ; then startup_log="${OCF_RESKEY_log_dir}/startup_log" fi ocf_log info "${LH} begin." ocf_log info "${LH} Execute start_app with timeout: ${TIMEOUT_ARG}" su_rabbit_cmd "${OCF_RESKEY_ctl} start_app >>${startup_log} 2>&1" rc=$? if [ $rc -eq 0 ] ; then ocf_log info "${LH} start_app was successful." ocf_log info "${LH} waiting for start to finish with timeout: ${TIMEOUT_ARG}" su_rabbit_cmd "${OCF_RESKEY_ctl} wait ${OCF_RESKEY_pid_file}" rc=$? if [ $rc -ne 0 ] ; then ocf_log err "${LH} RMQ-server app failed to wait for start." return $OCF_ERR_GENERIC fi rc=$OCF_SUCCESS # Loading enabled modules ocf_log info "${LH} start plugins." load_plugins local mrc=$? if [ $mrc -eq 0 ] ; then local mlist mlist=`list_active_plugins` ocf_log info "${LH} Starting plugins: ${mlist}" else ocf_log info "${LH} Starting plugins: failed." fi else ocf_log info "${LH} start_app failed." rc=$OCF_ERR_GENERIC fi return $rc } start_rmq_server_app() { local rc=$OCF_ERR_GENERIC local startup_log="${OCF_RESKEY_log_dir}/startup_log" local startup_output local LH="${LL} start_rmq_server_app():" local a #We are performing initial start check. #We are not ready to provide service. #Clients should not have access. ocf_log info "${LH} begin." # Safe-unblock the rules, if there are any unblock_client_access "${LH}" # Apply the blocking rule block_client_access rc=$? if [ $rc -eq $OCF_SUCCESS ]; then ocf_log info "${LH} blocked access to RMQ port" else ocf_log err "${LH} cannot block access to RMQ port!" return $OCF_ERR_GENERIC fi get_status rc=$? if [ $rc -ne $OCF_SUCCESS ] ; then ocf_log info "${LH} RMQ-runtime (beam) not started, starting..." start_beam_process rc=$? if [ $rc -ne $OCF_SUCCESS ]; then unblock_client_access "${LH}" return $OCF_ERR_GENERIC fi fi ocf_log info "${LH} RMQ-server app not started, starting..." try_to_start_rmq_app "$startup_log" rc=$? if [ $rc -eq $OCF_SUCCESS ] ; then # rabbitmq-server started successfuly as master of cluster master_score $MIN_MASTER_SCORE stop_rmq_server_app rc=$? if [ $rc -ne 0 ] ; then ocf_log err "${LH} RMQ-server app can't be stopped. Beam will be killed." kill_rmq_and_remove_pid unblock_client_access "${LH}" return $OCF_ERR_GENERIC fi else # error at start RMQ-server ocf_log warn "${LH} RMQ-server app can't start without Mnesia cleaning." for a in $(seq 1 10) ; do rc=$OCF_ERR_GENERIC reset_mnesia || break try_to_start_rmq_app "$startup_log" rc=$? if [ $rc -eq $OCF_SUCCESS ]; then stop_rmq_server_app rc=$? if [ $rc -eq $OCF_SUCCESS ]; then ocf_log info "${LH} RMQ-server app Mnesia cleaned successfully." rc=$OCF_SUCCESS master_score $MIN_MASTER_SCORE break else ocf_log err "${LH} RMQ-server app can't be stopped during Mnesia cleaning. Beam will be killed." kill_rmq_and_remove_pid unblock_client_access "${LH}" return $OCF_ERR_GENERIC fi fi done fi if [ $rc -eq $OCF_ERR_GENERIC ] ; then ocf_log err "${LH} RMQ-server can't be started while many tries. Beam will be killed." kill_rmq_and_remove_pid fi ocf_log info "${LH} end." unblock_client_access "${LH}" return $rc } # check status of rabbit beam process or a rabbit app, if rabbit arg specified # by default, test if the kernel app is running, otherwise consider it is "not running" get_status() { local what="${1:-kernel}" local rc=$OCF_NOT_RUNNING local LH="${LL} get_status():" local body local beam_running body=$( ${COMMAND_TIMEOUT} ${OCF_RESKEY_ctl} eval 'rabbit_misc:which_applications().' 2>&1 ) rc=$? pgrep -f "beam.*${RABBITMQ_NODENAME}" > /dev/null beam_running=$? # report not running only if the which_applications() reported an error AND the beam is not running if [ $rc -ne 0 ] && [ $beam_running -ne 0 ] ; then ocf_log info "${LH} failed with code ${rc}. Command output: ${body}" return $OCF_NOT_RUNNING # return a generic error, if there were errors and beam is found running elif [ $rc -ne 0 ] ; then ocf_log info "${LH} found the beam process running but failed with code ${rc}. Command output: ${body}" return $OCF_ERR_GENERIC fi # try to parse the which_applications() output only if it exited w/o errors if [ "${what}" ] && [ $rc -eq 0 ] ; then rc=$OCF_NOT_RUNNING echo "$body" | grep "\{${what}," > /dev/null 2>&1 && rc=$OCF_SUCCESS if [ $rc -ne $OCF_SUCCESS ] ; then ocf_log info "${LH} app ${what} was not found in command output: ${body}" fi fi [ $rc -ne $OCF_SUCCESS ] && rc=$OCF_NOT_RUNNING return $rc } action_status() { local rc=$OCF_ERR_GENERIC get_status rc=$? return $rc } # return 0, if given node has a master attribute in CIB, # otherwise, return 1 is_master() { local result result=`crm_attribute -N "${1}" -l reboot --name 'rabbit-master' --query 2>/dev/null |\ awk '{print $3}' | awk -F "=" '{print $2}' | sed -e '/(null)/d'` if [ "${result}" != 'true' ] ; then return 1 fi return 0 } # Verify if su_rabbit_cmd exited by timeout by checking its return code. # If it did not, return 0. If it did AND it is # $OCF_RESKEY_max_rabbitmqctl_timeouts'th timeout in a row, # return 2 to signal get_monitor that it should # exit with error. Otherwise return 1 to signal that there was a timeout, # but it should be ignored. Timeouts for different operations are tracked # separately. The second argument is used to distingush them. check_timeouts() { local op_rc=$1 local timeouts_attr_name=$2 local op_name=$3 # 75 is EX_TEMPFAIL from sysexits, and is used by rabbitmqctl to signal about # timeout. if [ $op_rc -ne 124 ] && [ $op_rc -ne 137 ] && [ $op_rc -ne 75 ]; then ocf_update_private_attr $timeouts_attr_name 0 return 0 fi local count count=$(ocf_get_private_attr $timeouts_attr_name 0) count=$((count+1)) # There is a slight chance that this piece of code will be executed twice simultaneously. # As a result, $timeouts_attr_name's value will be one less than it should be. But we don't need # precise calculation here. ocf_update_private_attr $timeouts_attr_name $count if [ $count -lt $OCF_RESKEY_max_rabbitmqctl_timeouts ]; then ocf_log warn "${LH} 'rabbitmqctl $op_name' timed out $count of max. $OCF_RESKEY_max_rabbitmqctl_timeouts time(s) in a row. Doing nothing for now." return 1 else ocf_log err "${LH} 'rabbitmqctl $op_name' timed out $count of max. $OCF_RESKEY_max_rabbitmqctl_timeouts time(s) in a row and is not responding. The resource is failed." return 2 fi } wait_sync() { local wait_time=$1 local queues local opt_arg="" if [ "$OCF_RESKEY_rmq_feature_local_list_queues" = "true" ]; then opt_arg="--local" fi queues="${COMMAND_TIMEOUT} ${OCF_RESKEY_ctl} -p ${OCF_RESKEY_default_vhost} list_queues $opt_arg name state" su_rabbit_cmd -t "${wait_time}" "sh -c \"while ${queues} | grep -q 'syncing,'; \ do sleep 2; done\"" return $? } get_monitor() { local rc=$OCF_ERR_GENERIC local LH="${LL} get_monitor():" local status_master=1 local rabbit_running local name local node local node_start_time local nowtime local partitions_report local node_partitions ocf_log info "${LH} CHECK LEVEL IS: ${OCF_CHECK_LEVEL}" get_status rc=$? if [ $rc -eq $OCF_NOT_RUNNING ] ; then ocf_log info "${LH} get_status() returns ${rc}." ocf_log info "${LH} ensuring this slave does not get promoted." master_score 0 return $OCF_NOT_RUNNING elif [ $rc -eq $OCF_SUCCESS ] ; then ocf_log info "${LH} get_status() returns ${rc}." ocf_log info "${LH} also checking if we are master." get_status rabbit rabbit_running=$? is_master $THIS_PCMK_NODE status_master=$? ocf_log info "${LH} master attribute is ${status_master}" if [ $status_master -eq 0 ] && [ $rabbit_running -eq $OCF_SUCCESS ] then ocf_log info "${LH} We are the running master" rc=$OCF_RUNNING_MASTER elif [ $status_master -eq 0 ] && [ $rabbit_running -ne $OCF_SUCCESS ] ; then ocf_log err "${LH} We are the master and RMQ-runtime (beam) is not running. this is a failure" exit $OCF_FAILED_MASTER fi fi get_status rabbit rabbit_running=$? ocf_log info "${LH} checking if rabbit app is running" if [ $rc -eq $OCF_RUNNING_MASTER ]; then if [ $rabbit_running -eq $OCF_SUCCESS ]; then ocf_log info "${LH} rabbit app is running and is master of cluster" else ocf_log err "${LH} we are the master and rabbit app is not running. This is a failure" exit $OCF_FAILED_MASTER fi else start_time=$((180 + $(ocf_get_private_attr 'rabbit-start-phase-1-time' 0))) restart_order_time=$((60 + $(ocf_get_private_attr 'rabbit-ordered-to-restart' 0))) nowtime=$(now) # If we started more than 3 minutes ago, and # we got order to restart less than 1 minute ago if [ $nowtime -lt $restart_order_time ]; then if [ $nowtime -gt $start_time ]; then ocf_log err "${LH} failing because we have received an order to restart from the master" stop_server_process rc=$OCF_ERR_GENERIC else ocf_log warn "${LH} received an order to restart from the master, ignoring it because we have just started" fi fi fi if [ $rc -eq $OCF_ERR_GENERIC ]; then ocf_log err "${LH} get_status() returns generic error ${rc}" ocf_log info "${LH} ensuring this slave does not get promoted." master_score 0 return $OCF_ERR_GENERIC fi # Recounting our master score ocf_log info "${LH} preparing to update master score for node" local our_start_time local new_score local node_start_time local node_score our_start_time=$(get_node_start_time $THIS_PCMK_NODE) if [ $our_start_time -eq 0 ]; then new_score=$MIN_MASTER_SCORE else new_score=$BEST_MASTER_SCORE for node in $(get_alive_pacemaker_nodes_but $THIS_PCMK_NODE) do node_start_time=$(get_node_start_time $node) node_score=$(get_node_master_score $node) ocf_log info "${LH} comparing us (start time: $our_start_time, score: $new_score) with $node (start time: $node_start_time, score: $node_score)" if [ $node_start_time -ne 0 ] && [ $node_score -ne 0 ] && [ $node_start_time -lt $our_start_time ]; then new_score=$((node_score - 10 < new_score ? node_score - 10 : new_score )) elif [ $node_start_time -ne 0 ] && [ $node_score -ne 0 ] && [ $node_start_time -eq $our_start_time ]; then # Do not get promoted if the other node is already master and we have the same start time if is_master $node; then new_score=$((node_score - 10 < new_score ? node_score - 10 : new_score )) fi fi done fi if [ "$new_score" -ne "$(get_node_master_score $THIS_PCMK_NODE)" ]; then master_score $new_score fi ocf_log info "${LH} our start time is $our_start_time and score is $new_score" # Skip all other checks if rabbit app is not running if [ $rabbit_running -ne $OCF_SUCCESS ]; then ocf_log info "${LH} RabbitMQ is not running, get_monitor function ready to return ${rc}" return $rc fi # rc can be SUCCESS or RUNNING_MASTER, don't touch it unless there # is some error uncovered by node_health_check if ! node_health_check; then rc=$OCF_ERR_GENERIC fi if [ $rc -eq $OCF_RUNNING_MASTER ] ; then # If we are the master and healthy, perform various # connectivity checks for other nodes in the cluster. # Order a member to restart if something fishy happens with it. # All cross-node checks MUST happen only here. partitions_report="$(partitions_report)" for node in $(get_alive_pacemaker_nodes_but $THIS_PCMK_NODE); do # Restart node if we don't consider ourselves clustered with it if ! is_clustered_with $node; then ocf_log warn "${LH} node $node is not connected with us" order_node_restart "$node" continue fi # Restart node if it has any unresolved partitions node_partitions=$(grep_partitions_report $node "$partitions_report") if [ ! -z "$node_partitions" ]; then ocf_log warn "${LH} Node $node thinks that it is partitoned with $node_partitions" order_node_restart "$node" continue fi done fi ocf_log info "${LH} get_monitor function ready to return ${rc}" return $rc } order_node_restart() { local node=${1:?} ocf_log warn "${LH} Ordering node '$node' to restart" ocf_update_private_attr 'rabbit-ordered-to-restart' "$(now)" "$node" } # Checks whether node is mentioned somewhere in report returned by # partitions_report() grep_partitions_report() { local node="${1:?}" local report="${2:?}" local rabbit_node rabbit_node=$(rabbit_node_name "$node") echo "$report" | grep "PARTITIONED $rabbit_node:" | sed -e 's/^[^:]\+: //' } # Report partitions (if any) from viewpoint of every running node in cluster. # It is parseable/grepable version of `rabbitmqctl cluster_status`. # # If node sees partition, report will contain the line like: # PARTITIONED node-name: list-of-nodes, which-node-name-considers, itself-partitioned-with partitions_report() { $COMMAND_TIMEOUT xargs -0 ${OCF_RESKEY_ctl} eval < ok; ({Node, Partitions}) -> PartitionsStr = string:join([atom_to_list(Part) || Part <- Partitions], ", "), io:format("PARTITIONED ~s: ~s~n", [Node, PartitionsStr]) end, Replies), ok. EOF } # Check if the rabbitmqctl control plane is alive. node_health_check() { local rc if [ "$OCF_RESKEY_rmq_feature_health_check" = true ]; then node_health_check_local rc=$? else node_health_check_legacy rc=$? fi return $rc } node_health_check_local() { local LH="${LH} node_health_check_local():" local rc local rc_timeouts # Give node_health_check some time to handle timeout by itself. # By using internal rabbitmqctl timeouts, we allow it to print # more useful diagnostics local timeout=$((TIMEOUT_ARG - 2)) su_rabbit_cmd "${OCF_RESKEY_ctl} node_health_check -t $timeout" rc=$? check_timeouts $rc "rabbit_node_health_check_timeouts" "node_health_check" rc_timeouts=$? if [ "$rc_timeouts" -eq 2 ]; then master_score 0 ocf_log info "${LH} node_health_check timed out, retry limit reached" return $OCF_ERR_GENERIC elif [ "$rc_timeouts" -eq 1 ]; then ocf_log info "${LH} node_health_check timed out, going to retry" return $OCF_SUCCESS fi if [ "$rc" -ne 0 ]; then ocf_log err "${LH} rabbitmqctl node_health_check exited with errors." return $OCF_ERR_GENERIC else return $OCF_SUCCESS fi } node_health_check_legacy() { local rc_alive local timeout_alive su_rabbit_cmd "${OCF_RESKEY_ctl} list_channels > /dev/null 2>&1" rc_alive=$? { [ $rc_alive -eq 137 ] || [ $rc_alive -eq 124 ] ; } && ocf_log err "${LH} 'rabbitmqctl list_channels' timed out, per-node explanation: $(enhanced_list_channels)" check_timeouts $rc_alive "rabbit_list_channels_timeouts" "list_channels" timeout_alive=$? if [ $timeout_alive -eq 2 ]; then master_score 0 return $OCF_ERR_GENERIC elif [ $timeout_alive -eq 0 ]; then if [ $rc_alive -ne 0 ]; then ocf_log err "${LH} rabbitmqctl list_channels exited with errors." rc=$OCF_ERR_GENERIC fi fi # Check for memory alarms for this Master or Slave node. # If alert found, reset the alarm # and restart the resource as it likely means a dead end situation # when rabbitmq cluster is running with blocked publishing due # to high memory watermark exceeded. local alarms local rc_alarms local timeout_alarms alarms=`su_rabbit_cmd "${OCF_RESKEY_ctl} -q eval 'rabbit_alarm:get_alarms().'" 2>/dev/null` rc_alarms=$? check_timeouts $rc_alarms "rabbit_get_alarms_timeouts" "get_alarms" timeout_alarms=$? if [ $timeout_alarms -eq 2 ]; then master_score 0 return $OCF_ERR_GENERIC elif [ $timeout_alarms -eq 0 ]; then if [ $rc_alarms -ne 0 ]; then ocf_log err "${LH} rabbitmqctl get_alarms exited with errors." rc=$OCF_ERR_GENERIC elif [ -n "${alarms}" ]; then for node in ${alarms}; do name=`echo ${node} | perl -n -e "m/memory,'(?\S+)+'/ && print \"$+{n}\n\""` if [ "${name}" = "${RABBITMQ_NODENAME}" ] ; then ocf_log err "${LH} Found raised memory alarm. Erasing the alarm and restarting." su_rabbit_cmd "${OCF_RESKEY_ctl} set_vm_memory_high_watermark 10 > /dev/null 2>&1" rc=$OCF_ERR_GENERIC break fi done fi fi if ! is_cluster_status_ok ; then rc=$OCF_ERR_GENERIC fi # Check if the list of all queues is available, # Also report some queues stats and total virtual memory. local queues local rc_queues local timeout_queues queues=`su_rabbit_cmd "${OCF_RESKEY_ctl} -q -p ${OCF_RESKEY_default_vhost} list_queues memory messages consumer_utilisation"` rc_queues=$? check_timeouts $rc_queues "rabbit_list_queues_timeouts" "list_queues" timeout_queues=$? if [ $timeout_queues -eq 2 ]; then master_score 0 return $OCF_ERR_GENERIC elif [ $timeout_queues -eq 0 ]; then if [ $rc_queues -ne 0 ]; then ocf_log err "${LH} rabbitmqctl list_queues exited with errors." rc=$OCF_ERR_GENERIC elif [ -n "${queues}" ]; then local q_c q_c=`printf %b "${queues}\n" | wc -l` local mem mem=`printf %b "${queues}\n" | awk -v sum=0 '{sum+=$1} END {print (sum/1048576)}'` local mes mes=`printf %b "${queues}\n" | awk -v sum=0 '{sum+=$2} END {print sum}'` local c_u c_u=`printf %b "${queues}\n" | awk -v sum=0 -v cnt=${q_c} '{sum+=$3} END {print (sum+1)/(cnt+1)}'` local status status=`echo $(su_rabbit_cmd "${OCF_RESKEY_ctl} -q status")` ocf_log info "${LH} RabbitMQ is running ${q_c} queues consuming ${mem}m of ${TOTALVMEM}m total, with ${mes} queued messages, average consumer utilization ${c_u}" ocf_log info "${LH} RabbitMQ status: ${status}" fi fi return $rc } ocf_get_private_attr() { local attr_name="${1:?}" local attr_default_value="${2:?}" local nodename="${3:-$THIS_PCMK_NODE}" local count count=$(attrd_updater -p --name "$attr_name" --node "$nodename" --query) if [ $? -ne 0 ]; then echo $attr_default_value else echo "$count" | awk -vdef_val="$attr_default_value" '{ gsub(/"/, "", $3); split($3, vals, "="); if (vals[2] != "") print vals[2]; else print def_val }' fi } ocf_update_private_attr() { local attr_name="${1:?}" local attr_value="${2:?}" local nodename="${3:-$THIS_PCMK_NODE}" ocf_run attrd_updater -p --name "$attr_name" --node "$nodename" --update "$attr_value" } rabbitmqctl_with_timeout_check() { local command="${1:?}" local timeout_attr_name="${2:?}" su_rabbit_cmd "${OCF_RESKEY_ctl} $command" local rc=$? check_timeouts $rc $timeout_attr_name "$command" local has_timed_out=$? case "$has_timed_out" in 0) return $rc;; 1) return 0;; 2) return 1;; esac } is_cluster_status_ok() { local LH="${LH}: is_cluster_status_ok:" rabbitmqctl_with_timeout_check cluster_status rabbit_cluster_status_timeouts > /dev/null 2>&1 } action_monitor() { local rc=$OCF_ERR_GENERIC local LH="${LL} monitor:" ocf_log debug "${LH} action start." if [ "${OCF_RESKEY_debug}" = 'true' ] ; then d=`date '+%Y%m%d %H:%M:%S'` echo $d >> /tmp/rmq-monitor.log env >> /tmp/rmq-monitor.log echo "$d [monitor] start='${OCF_RESKEY_CRM_meta_notify_start_uname}' stop='${OCF_RESKEY_CRM_meta_notify_stop_uname}' active='${OCF_RESKEY_CRM_meta_notify_active_uname}' inactive='${OCF_RESKEY_CRM_meta_notify_inactive_uname}'" >> /tmp/rmq-ocf.log fi get_monitor rc=$? ocf_log debug "${LH} role: ${OCF_RESKEY_CRM_meta_role}" ocf_log debug "${LH} result: $rc" ocf_log debug "${LH} action end." return $rc } action_start() { local rc=$OCF_ERR_GENERIC local LH="${LL} start:" local nowtime if [ "${OCF_RESKEY_debug}" = 'true' ] ; then d=`date '+%Y%m%d %H:%M:%S'` echo $d >> /tmp/rmq-start.log env >> /tmp/rmq-start.log echo "$d [start] start='${OCF_RESKEY_CRM_meta_notify_start_uname}' stop='${OCF_RESKEY_CRM_meta_notify_stop_uname}' active='${OCF_RESKEY_CRM_meta_notify_active_uname}' inactive='${OCF_RESKEY_CRM_meta_notify_inactive_uname}'" >> /tmp/rmq-ocf.log fi ocf_log info "${LH} action begin." get_status rc=$? if [ $rc -eq $OCF_SUCCESS ] ; then ocf_log warn "${LH} RMQ-runtime (beam) already started." return $OCF_SUCCESS fi local attrs_to_zero="rabbit_list_channels_timeouts rabbit_get_alarms_timeouts rabbit_list_queues_timeouts rabbit_cluster_status_timeouts rabbit_node_health_check_timeouts" local attr_name_to_reset for attr_name_to_reset in $attrs_to_zero; do ocf_update_private_attr $attr_name_to_reset 0 done nowtime=$(now) ocf_log info "${LH} Setting phase 1 one start time to $nowtime" ocf_update_private_attr 'rabbit-start-phase-1-time' "$nowtime" ocf_log info "${LH} Deleting start time attribute" ocf_run crm_attribute -N $THIS_PCMK_NODE -l reboot --name 'rabbit-start-time' --delete ocf_log info "${LH} Deleting master attribute" ocf_run crm_attribute -N $THIS_PCMK_NODE -l reboot --name 'rabbit-master' --delete ocf_log info "${LH} RMQ going to start." start_rmq_server_app rc=$? if [ $rc -eq $OCF_SUCCESS ] ; then ocf_log info "${LH} RMQ prepared for start succesfully." fi ocf_log info "${LH} action end." return $rc } action_stop() { local rc=$OCF_ERR_GENERIC local LH="${LL} stop:" if [ "${OCF_RESKEY_debug}" = 'true' ] ; then d=$(date '+%Y%m%d %H:%M:%S') echo $d >> /tmp/rmq-stop.log env >> /tmp/rmq-stop.log echo "$d [stop] start='${OCF_RESKEY_CRM_meta_notify_start_uname}' stop='${OCF_RESKEY_CRM_meta_notify_stop_uname}' active='${OCF_RESKEY_CRM_meta_notify_active_uname}' inactive='${OCF_RESKEY_CRM_meta_notify_inactive_uname}'" >> /tmp/rmq-ocf.log fi ocf_log info "${LH} action begin." ocf_log info "${LH} Deleting master attribute" ocf_run crm_attribute -N $THIS_PCMK_NODE -l reboot --name 'rabbit-master' --delete master_score 0 ocf_log info "${LH} Deleting start time attribute" ocf_run crm_attribute -N $THIS_PCMK_NODE -l reboot --name 'rabbit-start-time' --delete # Wait for synced state first ocf_log info "${LH} waiting $((OCF_RESKEY_stop_time/2)) to sync" wait_sync $((OCF_RESKEY_stop_time/2)) ocf_log info "${LH} RMQ-runtime (beam) going to down." stop_server_process if [ $? -ne $OCF_SUCCESS ] ; then ocf_log err "RMQ-runtime (beam) couldn't be stopped and will likely became unmanaged. Take care of it manually!" ocf_log info "${LH} action end." exit $OCF_ERR_GENERIC fi ocf_log info "${LH} RMQ-runtime (beam) not running." ocf_log info "${LH} action end." return $OCF_SUCCESS } ####################################################################### # Enhanced list_channels: # - nodes are processed in parallel # - report contains information about which nodes timed out # # 'list_channels' is used as a healh-check for current node, but it # actually checks overall health of all node in cluster. And there were # some bugs where only one (non-local) channel became stuck, but OCF # script was wrongfully killing local node. # # Hopefully all such bugs are fixed, but if not - it will allow to # detect such conditions. # # Somewhat strange implementation is due to the following reasons: # - ability to support older versions of RabbitMQ which have reached # end-of-life with single version of the script # - zero dependencies - for older versions this functionality could be # implemented as a plugin, but it'll require this plugin installation enhanced_list_channels() { # One second less than timeout of su_rabbit_cmd local timeout=$((${TIMEOUT_ARG:-5} - 1)) su_rabbit_cmd "xargs -0 ${OCF_RESKEY_ctl} eval" < {Mega, Secs, Micro} = os:timestamp(), Mili = Micro div 1000, Mili + 1000 * (Secs + 1000000 * Mega) end, %% We shouldn't continue execution past this time ShouldEndAt = Now() + SecondsToCompletion * 1000, %% How many milliseconds we still have Timeout = fun() -> case ShouldEndAt - Now() of Past when Past =< 0 -> 0; Timeout -> Timeout end end, %% Lambda combinator - for defining anonymous recursive functions Y = fun(F) -> (fun (X) -> F(fun(Y) -> (X(X))(Y) end) end)( fun (X) -> F(fun(Y) -> (X(X))(Y) end) end) end, Parent = self(), ListChannels = Y(fun(Rec) -> fun (({Node, [], OkChannelsCount})) -> Parent ! {Node, ok, OkChannelsCount}; ({Node, [Chan|Rest], OkChannelsCount}) -> case catch rpc:call(Node, rabbit_channel, info, [Chan], Timeout()) of Infos when is_list(Infos) -> Rec({Node, Rest, OkChannelsCount + 1}); {badrpc, {'EXIT', {noproc, _}}} -> %% Channel became dead before we could request it's status, don't care Rec({Node, Rest, OkChannelsCount}); Err -> Parent ! {Node, Err, OkChannelsCount} end end end), SingleNodeListing = fun(Node) -> case catch rpc:call(Node, pg_local, get_members, [rabbit_channels], Timeout()) of LocalChannels when is_list(LocalChannels) -> ListChannels({Node, LocalChannels, 0}); Err -> Parent ! {Node, Err, 0} end end, AllNodes = rabbit_mnesia:cluster_nodes(running), [ spawn(fun() -> SingleNodeListing(Node) end) || Node <- AllNodes ], WaitForNodes = Y(fun(Rec) -> fun ({[], Acc}) -> Acc; ({RemainingNodes, Acc}) -> receive {Node, _Status, _ChannelCount} = Smth -> RemainingNodes1 = lists:delete(Node, RemainingNodes), Rec({RemainingNodes1, [Smth|Acc]}) after Timeout() + 100 -> Acc end end end), Result = WaitForNodes({AllNodes, []}), ExpandedResult = [ case lists:keysearch(Node, 1, Result) of {value, NodeResult} -> NodeResult; false -> {Node, no_data_collected, 0} end || Node <- AllNodes ], ExpandedResult. EOF } ####################################################################### # Join the cluster and return OCF_SUCCESS, if joined. # Return 10, if node is trying to join to itself or empty destination. # Return OCF_ERR_GENERIC, if cannot join. jjj_join () { local join_to="$1" local rc=$OCF_ERR_GENERIC local LH="${LL} jjj_join:" my_host ${join_to} rc=$? ocf_log debug "${LH} node='${join_to}' rc='${rc}'" # Check whether we are joining to ourselves # or master host is not given if [ $rc -ne 0 ] && [ "${join_to}" ] ; then ocf_log info "${LH} Joining to cluster by node '${join_to}'" join_to_cluster "${join_to}" rc=$? if [ $rc -ne $OCF_SUCCESS ] ; then ocf_log err "${LH} Failed to join the cluster. The mnesia will be reset." reset_mnesia rc=$OCF_ERR_GENERIC fi fi return $rc } action_notify() { local rc_join=$OCF_SUCCESS local rc=$OCF_ERR_GENERIC local rc2=$OCF_ERR_GENERIC local LH="${LL} notify:" local nodelist if [ "${OCF_RESKEY_debug}" = 'true' ] ; then d=`date '+%Y%m%d %H:%M:%S'` echo $d >> /tmp/rmq-notify.log env >> /tmp/rmq-notify.log echo "$d [notify] ${OCF_RESKEY_CRM_meta_notify_type}-${OCF_RESKEY_CRM_meta_notify_operation} promote='${OCF_RESKEY_CRM_meta_notify_promote_uname}' demote='${OCF_RESKEY_CRM_meta_notify_demote_uname}' master='${OCF_RESKEY_CRM_meta_notify_master_uname}' slave='${OCF_RESKEY_CRM_meta_notify_slave_uname}' start='${OCF_RESKEY_CRM_meta_notify_start_uname}' stop='${OCF_RESKEY_CRM_meta_notify_stop_uname}' active='${OCF_RESKEY_CRM_meta_notify_active_uname}' inactive='${OCF_RESKEY_CRM_meta_notify_inactive_uname}'" >> /tmp/rmq-ocf.log fi if [ "${OCF_RESKEY_CRM_meta_notify_type}" = 'post' ] ; then # POST- anything notify section case "$OCF_RESKEY_CRM_meta_notify_operation" in promote) ocf_log info "${LH} post-promote begin." rc=$OCF_SUCCESS # Do nothing, if the list of nodes being promoted reported empty. # Delegate recovery, if needed, to the "running out of the cluster" monitor's logic if [ -z "${OCF_RESKEY_CRM_meta_notify_promote_uname}" ] ; then ocf_log warn "${LH} there are no nodes to join to reported on post-promote. Nothing to do." elif my_host "${OCF_RESKEY_CRM_meta_notify_promote_uname}"; then ocf_log info "${LH} ignoring post-promote of self" elif is_clustered_with "${OCF_RESKEY_CRM_meta_notify_promote_uname}"; then if get_status rabbit; then ocf_log info "${LH} we are already clustered with master - ${OCF_RESKEY_CRM_meta_notify_promote_uname}. Nothing to do." else ocf_log info "${LH} we are already clustered with master - ${OCF_RESKEY_CRM_meta_notify_promote_uname}. We only need to start the app." try_to_start_rmq_app rc2=$? update_rabbit_start_time_if_rc $rc2 fi else # Note, this should fail when the mnesia is inconsistent. # For example, when the "old" master processing the promition of the new one. # Later this ex-master node will rejoin the cluster at post-start. jjj_join "${OCF_RESKEY_CRM_meta_notify_promote_uname}" rc=$? if [ $rc -eq $OCF_ERR_GENERIC ] ; then ocf_log err "${LH} Failed to join the cluster on post-promote. The resource will be restarted." fi fi ocf_log info "${LH} post-promote end." return $rc ;; start) ocf_log info "${LH} post-start begin." # Do nothing, if the list of nodes being started or running reported empty # Delegate recovery, if needed, to the "running out of the cluster" monitor's logic if [ -z "${OCF_RESKEY_CRM_meta_notify_start_uname}" ] && [ -z "${OCF_RESKEY_CRM_meta_notify_active_uname}" ] ; then ocf_log warn "${LH} I'm a last man standing and I must survive!" ocf_log info "${LH} post-start end." return $OCF_SUCCESS fi # check did this event from this host my_host "${OCF_RESKEY_CRM_meta_notify_start_uname}" rc=$? # Do nothing, if there is no master reported # Delegate recovery, if needed, to the "running out of the cluster" monitor's logic if [ -z "${OCF_RESKEY_CRM_meta_notify_master_uname}" ] ; then ocf_log warn "${LH} there are no nodes to join to reported on post-start. Nothing to do." ocf_log info "${LH} post-start end." return $OCF_SUCCESS fi if [ $rc -eq $OCF_SUCCESS ] ; then # Now we need to: # a. join to the cluster if we are not joined yet # b. start the RabbitMQ application, which is always # stopped after start action finishes check_need_join_to ${OCF_RESKEY_CRM_meta_notify_master_uname} rc_join=$? if [ $rc_join -eq $OCF_SUCCESS ]; then ocf_log warn "${LH} Going to join node ${OCF_RESKEY_CRM_meta_notify_master_uname}" jjj_join "${OCF_RESKEY_CRM_meta_notify_master_uname}" rc2=$? else ocf_log warn "${LH} We are already clustered with node ${OCF_RESKEY_CRM_meta_notify_master_uname}" try_to_start_rmq_app rc2=$? update_rabbit_start_time_if_rc $rc2 fi if [ -s "${OCF_RESKEY_definitions_dump_file}" ] ; then ocf_log info "File ${OCF_RESKEY_definitions_dump_file} exists" ocf_run curl --silent --show-error --request POST --user $OCF_RESKEY_admin_user:$OCF_RESKEY_admin_password $OCF_RESKEY_host_ip:15672/api/definitions --header "Content-Type:application/json" --data @$OCF_RESKEY_definitions_dump_file rc=$? if [ $rc -eq $OCF_SUCCESS ] ; then ocf_log info "RMQ definitions have imported succesfully." else ocf_log err "RMQ definitions have not imported." fi fi if [ $rc2 -eq $OCF_ERR_GENERIC ] ; then ocf_log warn "${LH} Failed to join the cluster on post-start. The resource will be restarted." ocf_log info "${LH} post-start end." return $OCF_ERR_GENERIC fi fi ocf_log info "${LH} post-start end." ;; stop) # if rabbitmq-server stops on any another node, we should remove it from cluster (as ordinary operation) ocf_log info "${LH} post-stop begin." # Report not running, if there are no nodes being stopped reported if [ -z "${OCF_RESKEY_CRM_meta_notify_stop_uname}" ] ; then ocf_log warn "${LH} there are no nodes being stopped reported on post-stop. The resource will be restarted." ocf_log info "${LH} post-stop end." return $OCF_ERR_GENERIC fi my_host "${OCF_RESKEY_CRM_meta_notify_stop_uname}" rc=$? if [ $rc -ne $OCF_SUCCESS ] ; then # Wait for synced state first ocf_log info "${LH} waiting $((OCF_RESKEY_stop_time/2)) to sync" wait_sync $((OCF_RESKEY_stop_time/2)) # On other nodes processing the post-stop, make sure the stopped node will be forgotten unjoin_nodes_from_cluster "${OCF_RESKEY_CRM_meta_notify_stop_uname}" else # On the nodes being stopped, reset the master score ocf_log info "${LH} resetting the master score." master_score 0 fi # always returns OCF_SUCCESS ocf_log info "${LH} post-stop end." ;; *) ;; esac fi return $OCF_SUCCESS } action_promote() { local rc=$OCF_ERR_GENERIC local LH="${LL} promote:" if [ "${OCF_RESKEY_debug}" = 'true' ] ; then d=$(date '+%Y%m%d %H:%M:%S') echo $d >> /tmp/rmq-promote.log env >> /tmp/rmq-promote.log echo "$d [promote] start='${OCF_RESKEY_CRM_meta_notify_start_uname}' stop='${OCF_RESKEY_CRM_meta_notify_stop_uname}' active='${OCF_RESKEY_CRM_meta_notify_active_uname}' inactive='${OCF_RESKEY_CRM_meta_notify_inactive_uname}'" >> /tmp/rmq-ocf.log fi ocf_log info "${LH} action begin." get_monitor rc=$? ocf_log info "${LH} get_monitor returns ${rc}" case "$rc" in "$OCF_SUCCESS") # Running as slave. Normal, expected behavior. ocf_log info "${LH} Resource is currently running as Slave" # rabbitmqctl start_app if need get_status rabbit rc=$? ocf_log info "${LH} Updating cluster master attribute" ocf_run crm_attribute -N $THIS_PCMK_NODE -l reboot --name 'rabbit-master' --update 'true' if [ $rc -ne $OCF_SUCCESS ] ; then ocf_log info "${LH} RMQ app is not started. Starting..." start_rmq_server_app rc=$? if [ $rc -eq 0 ] ; then try_to_start_rmq_app rc=$? if [ $rc -ne 0 ] ; then ocf_log err "${LH} Can't start RMQ app. Master resource is failed." ocf_log info "${LH} action end." exit $OCF_FAILED_MASTER fi [ -f "${OCF_RESKEY_policy_file}" ] && . "${OCF_RESKEY_policy_file}" update_rabbit_start_time_if_rc $rc ocf_log info "${LH} Checking master status" get_monitor rc=$? ocf_log info "${LH} Master status is $rc" if [ $rc = $OCF_RUNNING_MASTER ] then rc=$OCF_SUCCESS else ocf_log err "${LH} Master resource is failed." ocf_log info "${LH} action end." exit $OCF_FAILED_MASTER fi else ocf_log err "${LH} Can't start RMQ-runtime." rc=$OCF_ERR_GENERIC fi fi return $rc ;; "$OCF_RUNNING_MASTER") # Already a master. Unexpected, but not a problem. ocf_log warn "${LH} Resource is already running as Master" rc=$OCF_SUCCESS ;; "$OCF_FAILED_MASTER") # Master failed. ocf_log err "${LH} Master resource is failed and not running" ocf_log info "${LH} action end." exit $OCF_FAILED_MASTER ;; "$OCF_NOT_RUNNING") # Currently not running. ocf_log err "${LH} Resource is currently not running" rc=$OCF_NOT_RUNNING ;; *) # Failed resource. Let the cluster manager recover. ocf_log err "${LH} Unexpected error, cannot promote" ocf_log info "${LH} action end." exit $rc ;; esac # transform slave RMQ-server to master ocf_log info "${LH} action end." return $rc } action_demote() { local LH="${LL} demote:" ocf_log info "${LH} action begin." ocf_run crm_attribute -N $THIS_PCMK_NODE -l reboot --name 'rabbit-master' --delete ocf_log info "${LH} action end." return $OCF_SUCCESS } ####################################################################### rmq_setup_env case "$1" in meta-data) meta_data exit $OCF_SUCCESS;; usage|help) usage exit $OCF_SUCCESS;; esac # Anything except meta-data and help must pass validation action_validate || exit $? # What kind of method was invoked? case "$1" in start) action_start;; stop) action_stop;; status) action_status;; monitor) action_monitor;; validate) action_validate;; promote) action_promote;; demote) action_demote;; notify) action_notify;; validate-all) action_validate;; *) usage;; esac ###