Page MenuHomeClusterLabs Projects

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/.gitignore b/.gitignore
index c5ca86056f..42c5aa0098 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,192 +1,196 @@
# Common
\#*
.\#*
GPATH
GRTAGS
GTAGS
TAGS
Makefile
Makefile.in
.deps
.libs
*.pc
*.pyc
*.bz2
*.tar.gz
*.rpm
*.la
*.lo
*.o
*~
*.gcda
*.gcno
# Autobuild
aclocal.m4
autoconf
autoheader
autom4te.cache/
automake
build.counter
compile
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
include/stamp-*
libtool
libtool.m4
ltdl.m4
libltdl
ltmain.sh
missing
py-compile
/m4/argz.m4
/m4/ltargz.m4
/m4/ltoptions.m4
/m4/ltsugar.m4
/m4/ltversion.m4
/m4/lt~obsolete.m4
test-driver
ylwrap
# Configure targets
Doxyfile
cts/CTSlab.py
cts/CTSvars.py
cts/LSBDummy
cts/OCFIPraTest.py
cts/benchmark/clubench
cts/cts-coverage
cts/cts-lrmd
cts/cts-pengine
cts/cts-stonithd
cts/fence_dummy
cts/lxc_autogen.sh
extra/logrotate/pacemaker
+/fencing/fence_legacy
include/config.h
include/config.h.in
include/crm_config.h
lrmd/pacemaker_remote
lrmd/pacemaker_remoted
lrmd/pacemaker_remote.service
mcp/pacemaker
mcp/pacemaker.combined.upstart
mcp/pacemaker.service
mcp/pacemaker.upstart
publican.cfg
-tools/cibsecret
-tools/crm_error
-tools/crm_mon.service
-tools/crm_mon.upstart
-tools/crm_report
-tools/report.collector
-tools/report.common
+/tools/cibsecret
+/tools/crm_error
+/tools/crm_failcount
+/tools/crm_master
+/tools/crm_mon.service
+/tools/crm_mon.upstart
+/tools/crm_report
+/tools/crm_standby
+/tools/report.collector
+/tools/report.common
# Build targets
*.7
*.7.xml
*.7.html
*.8
*.8.xml
*.8.html
attrd/attrd
doc/*/en-US/images/*.png
doc/*/tmp/**
doc/*/publish
cib/cib
cib/cibmon
cib/cibpipe
crmd/atest
crmd/crmd
doc/api/*
doc/Clusters_from_Scratch.txt
doc/Pacemaker_Explained.txt
doc/acls.html
doc/crm_fencing.html
doc/publican-catalog*
fencing/stonith-test
fencing/stonith_admin
fencing/stonithd
fencing/stonithd.xml
lrmd/lrmd
lrmd/lrmd_internal_ctl
lrmd/lrmd_test
mcp/pacemakerd
pengine/pengine
pengine/pengine.xml
pengine/ptest
scratch
tools/attrd_updater
tools/cibadmin
tools/crm_attribute
tools/crm_diff
tools/crm_mon
tools/crm_node
tools/crm_resource
tools/crm_shadow
tools/crm_simulate
tools/crm_verify
tools/crmadmin
tools/iso8601
tools/crm_ticket
tools/report.collector.1
xml/crm.dtd
xml/pacemaker*.rng
xml/versions.rng
doc/shared/en-US/*.xml
doc/Clusters_from_Scratch.build
doc/Clusters_from_Scratch/en-US/Ap-*.xml
doc/Clusters_from_Scratch/en-US/Ch-*.xml
doc/Pacemaker_Administration.build
doc/Pacemaker_Administration/en-US/Ch-*.xml
doc/Pacemaker_Development.build
doc/Pacemaker_Development/en-US/Ch-*.xml
doc/Pacemaker_Explained.build
doc/Pacemaker_Explained/en-US/Ch-*.xml
doc/Pacemaker_Explained/en-US/Ap-*.xml
doc/Pacemaker_Remote.build
doc/Pacemaker_Remote/en-US/Ch-*.xml
lib/gnu/libgnu.a
lib/gnu/stdalign.h
*.coverity
# Test detritus
/cts/.regression.failed.diff
/cts/pengine/shadow.*
/cts/pengine/*.ref
/cts/pengine/*.up
/cts/pengine/*.up.err
/xml/test-2/*.up
/xml/test-2/*.up.err
# Formerly built files (helps when jumping back and forth in checkout)
/coverage.sh
/cts/HBDummy
/fencing/regression.py
/lrmd/regression.py
/pengine/.regression.failed.diff
/pengine/regression.core.sh
/pengine/test10/shadow.*
#Other
mock
HTML
pacemaker*.spec
coverity-*
compat_reports
.ABI-build
abi_dumps
logs
*.patch
*.diff
*.sed
*.orig
*.rej
*.swp
diff --git a/INSTALL.md b/INSTALL.md
index 852fbf4583..6cdc88bc01 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -1,53 +1,54 @@
# How to Install Pacemaker
## Build Dependencies
* automake 1.11 or later
* autoconf 2.64 or later
+* bash
* libtool
* libtool-ltdl-devel
* libuuid-devel
* pkgconfig
* python (or python-devel if that's preferred as a build dependency)
* glib2-devel 2.16.0 or later
* libxml2-devel
* libxslt-devel
* bzip2-devel
* gnutls-devel
* pam-devel
* libqb-devel
## Cluster Stack Dependencies (Pick at least one)
* Corosync: corosynclib-devel
* (no other stacks are currently supported)
## Optional Build Dependencies
* ncurses-devel (interactive crm_mon)
* systemd-devel (systemd support)
* dbus-devel (systemd/upstart resource support)
* cluster-glue-libs-devel (Linux-HA style fencing agents)
* asciidoc (documentation)
* help2man (documentation)
* publican (documentation)
* inkscape (documentation)
* docbook-style-xsl (documentation)
## Optional testing dependencies
* valgrind (if running CTS valgrind tests)
* systemd-python (if using CTS on cluster nodes running systemd)
* rsync (if running CTS container tests)
* libvirt-daemon-driver-lxc (if running CTS container tests)
* libvirt-daemon-lxc (if running CTS container tests)
* libvirt-login-shell (if running CTS container tests)
## Source Control (GIT)
git clone git://github.com/ClusterLabs/pacemaker.git
[See Github](https://github.com/ClusterLabs/pacemaker)
## Installing from source
$ ./autogen.sh
$ ./configure
$ make
$ sudo make install
diff --git a/configure.ac b/configure.ac
index b20a8f24f3..4b5262f55a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,1746 +1,1808 @@
dnl
dnl autoconf for Pacemaker
dnl
dnl License: GNU General Public License (GPL)
dnl ===============================================
dnl Bootstrap
dnl ===============================================
AC_PREREQ(2.64)
AC_CONFIG_MACRO_DIR([m4])
AC_DEFUN([AC_DATAROOTDIR_CHECKED])
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
m4_include([version.m4])
AC_INIT([pacemaker], VERSION_NUMBER, [users@clusterlabs.org], [pacemaker],
PCMK_URL)
PCMK_FEATURES=""
AC_CONFIG_AUX_DIR(.)
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 crm_internal.h
dnl (which is also not to be included in any other header files)
dnl
dnl External header: include/crm_config.h
dnl - Contains a subset of defines checked here
dnl - Manually edit include/crm_config.h.in to have configure include
dnl new defines
dnl - Should not include HAVE_* defines
dnl - Safe to include anywhere
AM_CONFIG_HEADER(include/config.h include/crm_config.h)
AC_ARG_WITH(version,
[ --with-version=version Override package version (if you are a packager needing to pretend) ],
[ PACKAGE_VERSION="$withval" ])
AC_ARG_WITH(pkg-name,
[ --with-pkg-name=name Override package name (if you are a packager needing to pretend) ],
[ PACKAGE_NAME="$withval" ])
dnl 1.11: minimum automake version required
dnl foreign: don't require GNU-standard top-level files
dnl silent-rules: allow "--enable-silent-rules" (no-op in 1.13+)
AM_INIT_AUTOMAKE([1.11 foreign silent-rules])
dnl Example 2.4. Silent Custom Rule to Generate a File
dnl %-bar.pc: %.pc
dnl $(AM_V_GEN)$(LN_S) $(notdir $^) $@
AC_DEFINE_UNQUOTED(PACEMAKER_VERSION, "$PACKAGE_VERSION",
[Current pacemaker version])
dnl Versioned attributes implementation is not yet production-ready
AC_DEFINE_UNQUOTED(ENABLE_VERSIONED_ATTRS, 0, [Enable versioned attributes])
PACKAGE_SERIES=`echo $PACKAGE_VERSION | awk -F. '{ print $1"."$2 }'`
AC_SUBST(PACKAGE_SERIES)
AC_SUBST(PACKAGE_VERSION)
CC_IN_CONFIGURE=yes
export CC_IN_CONFIGURE
LDD=ldd
dnl ========================================================================
dnl Compiler characteristics
dnl ========================================================================
AC_PROG_CC dnl Can force other with environment variable "CC".
AM_PROG_CC_C_O
AC_PROG_CC_STDC
gl_EARLY
gl_INIT
LT_INIT([dlopen])
LTDL_INIT([convenience])
AC_PROG_YACC
AM_PROG_LEX
AC_C_STRINGIZE
AC_TYPE_SIZE_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 CFLAGS="-Werror $@"
AC_MSG_CHECKING(whether $CC supports "$@")
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ ]], [[ ]])],
[RC=0; AC_MSG_RESULT(yes)],
[RC=1; AC_MSG_RESULT(no)])
return $RC
}
+# Some tests need to use their own CFLAGS
+
+cc_temp_flags() {
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$*"
+}
+
+cc_restore_flags() {
+ CFLAGS=$ac_save_CFLAGS
+}
+
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 standard for older compilers. [default=no] ])
AC_ARG_ENABLE([fatal-warnings],
[ --enable-fatal-warnings Enable pedantic and fatal warnings for gcc [default=yes] ])
AC_ARG_ENABLE([quiet],
[ --enable-quiet Suppress make output unless there is an error [default=no] ])
AC_ARG_ENABLE([no-stack],
[ --enable-no-stack Build only the Policy Engine and its requirements [default=no] ])
AC_ARG_ENABLE([upstart],
[ --enable-upstart Enable support for managing resources via Upstart [default=try] ],
[],
[enable_upstart=try],
)
AC_ARG_ENABLE([systemd],
[ --enable-systemd Enable support for managing resources via systemd [default=try]],
[],
[enable_systemd=try],
)
AC_ARG_ENABLE(hardening,
[ --with-hardening Harden the resulting executables/libraries (best effort by default) ],
[ HARDENING="${enableval}" ],
[ HARDENING=try ],
)
AC_ARG_WITH(corosync,
[ --with-corosync Support the Corosync messaging and membership layer ],
[ SUPPORT_CS=$withval ],
[ SUPPORT_CS=try ],
)
AC_ARG_WITH(nagios,
[ --with-nagios Support nagios remote monitoring ],
[ SUPPORT_NAGIOS=$withval ],
[ SUPPORT_NAGIOS=try ],
)
AC_ARG_WITH(nagios-plugin-dir,
[ --with-nagios-plugin-dir=DIR Directory for nagios plugins [${NAGIOS_PLUGIN_DIR}] ],
[ NAGIOS_PLUGIN_DIR="$withval" ]
)
AC_ARG_WITH(nagios-metadata-dir,
[ --with-nagios-metadata-dir=DIR Directory for nagios plugins metadata [${NAGIOS_METADATA_DIR}] ],
[ NAGIOS_METADATA_DIR="$withval" ]
)
AC_ARG_WITH(acl,
[ --with-acl Support CIB ACL ],
[ SUPPORT_ACL=$withval ],
[ SUPPORT_ACL=yes ],
)
AC_ARG_WITH(cibsecrets,
[ --with-cibsecrets Support separate file for CIB secrets ],
[ SUPPORT_CIBSECRETS=$withval ],
[ SUPPORT_CIBSECRETS=no ],
)
INITDIR=""
AC_ARG_WITH(initdir,
[ --with-initdir=DIR Directory for init (rc) scripts [${INITDIR}] ],
[ INITDIR="$withval" ])
SUPPORT_PROFILING=0
AC_ARG_WITH(profiling,
[ --with-profiling Disable optimizations for effective profiling ],
[ SUPPORT_PROFILING=$withval ])
AC_ARG_WITH(coverage,
[ --with-coverage Disable optimizations for effective profiling ],
[ SUPPORT_COVERAGE=$withval ])
PUBLICAN_BRAND="common"
AC_ARG_WITH(brand,
[ --with-brand=brand Brand to use for generated documentation (set empty for no docs) [$PUBLICAN_BRAND] ],
[ test x"$withval" = x"no" || PUBLICAN_BRAND="$withval" ])
AC_SUBST(PUBLICAN_BRAND)
CONFIGDIR=""
AC_ARG_WITH(configdir,
[ --with-configdir=DIR Directory for Pacemaker configuration file [${CONFIGDIR}]],
[ CONFIGDIR="$withval" ]
)
CRM_LOG_DIR=""
AC_ARG_WITH(logdir,
[ --with-logdir=DIR Directory for Pacemaker log file @<:@LOCALSTATEDIR/log/pacemaker@:>@ ],
[ CRM_LOG_DIR="$withval" ]
)
CRM_BUNDLE_DIR=""
AC_ARG_WITH(bundledir,
[ --with-bundledir=DIR Directory for Pacemaker bundle logs @<:@LOCALSTATEDIR/log/pacemaker/bundles@:>@ ],
[ CRM_BUNDLE_DIR="$withval" ]
)
dnl ===============================================
dnl General Processing
dnl ===============================================
+if cc_supports_flag -Werror; then
+ WERROR="-Werror"
+else
+ WERROR=""
+fi
+
+# Normalize enable_fatal_warnings (defaulting to yes, when compiler supports it)
+if test "x${enable_fatal_warnings}" != "xno" ; then
+ if test "$GCC" = "yes" && test "x${WERROR}" != "x" ; then
+ enable_fatal_warnings=yes
+ else
+ AC_MSG_NOTICE(Compiler does not support fatal warnings)
+ enable_fatal_warnings=no
+ fi
+fi
+
INIT_EXT=""
echo Our Host OS: $host_os/$host
AC_MSG_NOTICE(Sanitizing prefix: ${prefix})
case $prefix in
NONE)
prefix=/usr
dnl Fix default variables - "prefix" variable if not specified
if test "$localstatedir" = "\${prefix}/var"; then
localstatedir="/var"
fi
if test "$sysconfdir" = "\${prefix}/etc"; then
sysconfdir="/etc"
fi
;;
esac
AC_MSG_NOTICE(Sanitizing exec_prefix: ${exec_prefix})
case $exec_prefix in
prefix|NONE)
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
AC_MSG_RESULT($INITDIR)
;;
esac
AC_SUBST(INITDIR)
AC_MSG_NOTICE(Sanitizing libdir: ${libdir})
case $libdir in
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
dnl Expand autoconf variables so that we don't 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 Home-grown variables
eval INITDIR="${INITDIR}"
eval docdir="`eval echo ${docdir}`"
if test x"${docdir}" = x""; then
docdir=${datadir}/doc/${PACKAGE}-${VERSION}
fi
AC_SUBST(docdir)
if test x"${CONFIGDIR}" = x""; then
CONFIGDIR="${sysconfdir}/sysconfig"
fi
AC_SUBST(CONFIGDIR)
if test x"${CRM_LOG_DIR}" = x""; then
CRM_LOG_DIR="${localstatedir}/log/pacemaker"
fi
AC_DEFINE_UNQUOTED(CRM_LOG_DIR,"$CRM_LOG_DIR", Location for Pacemaker log file)
AC_SUBST(CRM_LOG_DIR)
if test x"${CRM_BUNDLE_DIR}" = x""; then
CRM_BUNDLE_DIR="${localstatedir}/log/pacemaker/bundles"
fi
AC_DEFINE_UNQUOTED(CRM_BUNDLE_DIR,"$CRM_BUNDLE_DIR", Location for Pacemaker bundle logs)
AC_SUBST(CRM_BUNDLE_DIR)
for j in prefix exec_prefix bindir sbindir libexecdir datadir sysconfdir \
sharedstatedir localstatedir libdir includedir oldincludedir infodir \
mandir INITDIR docdir CONFIGDIR
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".
case "$host_os" in
*bsd*)
AC_DEFINE_UNQUOTED(ON_BSD, 1, Compiling for BSD platform)
LIBS="-L/usr/local/lib"
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
INIT_EXT=".sh"
;;
*solaris*)
AC_DEFINE_UNQUOTED(ON_SOLARIS, 1, Compiling for Solaris platform)
;;
*linux*)
AC_DEFINE_UNQUOTED(ON_LINUX, 1, Compiling for Linux platform)
;;
darwin*)
AC_DEFINE_UNQUOTED(ON_DARWIN, 1, Compiling for Darwin platform)
LIBS="$LIBS -L${prefix}/lib"
CFLAGS="$CFLAGS -I${prefix}/include"
;;
esac
AC_SUBST(INIT_EXT)
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)
-ac_save_CFLAGS=$CFLAGS
-CFLAGS="-Wall -Werror"
+cc_temp_flags "-Wall $WERROR"
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
],
[
int max = 512;
uint64_t bignum = 42;
char *buffer = malloc(max);
const char *random = "random";
snprintf(buffer, max-1, "<quorum id=%lu quorate=%s/>", bignum, random);
fprintf(stderr, "Result: %s\n", buffer);
]
)],
[U64T="%lu"],
[U64T="%llu"]
)
-CFLAGS=$ac_save_CFLAGS
+cc_restore_flags
AC_MSG_RESULT($U64T)
AC_DEFINE_UNQUOTED(U64T, "$U64T", Correct printf format for logging uint64_t)
dnl ===============================================
dnl Program Paths
dnl ===============================================
PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin"
export PATH
dnl Replacing AC_PROG_LIBTOOL with AC_CHECK_PROG because LIBTOOL
dnl was NOT being expanded all the time thus causing things to fail.
AC_CHECK_PROGS(LIBTOOL, glibtool libtool libtool15 libtool13)
dnl Pacemaker's executable python scripts will invoke the python specified by
dnl configure's PYTHON variable. If not specified, AM_PATH_PYTHON will check a
dnl built-in list with (unversioned) "python" having precedence. To configure
dnl Pacemaker to use a specific python interpreter version, define PYTHON
dnl when calling configure, for example: ./configure PYTHON=/usr/bin/python3.6
+
+dnl PYTHON must be a full path
+case "x$PYTHON" in
+ /*)
+ ;;
+ *)
+ AC_PATH_PROG([PYTHON], [$PYTHON])
+ ;;
+esac
+
case "x$PYTHON" in
x*python3*)
dnl When used with Python 3, Pacemaker requires a minimum of 3.2
AM_PATH_PYTHON([3.2])
;;
*)
dnl Otherwise, Pacemaker requires a minimum of 2.7
AM_PATH_PYTHON([2.7])
;;
esac
AC_CHECK_PROGS(MAKE, gmake make)
AC_PATH_PROGS(HTML2TXT, lynx w3m)
AC_PATH_PROGS(HELP2MAN, help2man)
AC_PATH_PROGS(POD2MAN, pod2man, pod2man)
AC_PATH_PROGS(ASCIIDOC, asciidoc)
AC_PATH_PROGS(PUBLICAN, publican)
AC_PATH_PROGS(INKSCAPE, inkscape)
AC_PATH_PROGS(XSLTPROC, xsltproc)
AC_PATH_PROGS(XMLCATALOG, xmlcatalog)
AC_PATH_PROGS(FOP, fop)
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)
+dnl BASH is already an environment variable, so use something else
+AC_PATH_PROG([BASH_PATH], [bash])
AC_PATH_PROGS(TEST, test)
PKG_PROG_PKG_CONFIG
AC_PATH_PROGS(VALGRIND_BIN, valgrind, /usr/bin/valgrind)
AC_DEFINE_UNQUOTED(VALGRIND_BIN, "$VALGRIND_BIN", Valgrind command)
if test x"${LIBTOOL}" = x""; then
AC_MSG_ERROR(You need (g)libtool installed in order to build ${PACKAGE})
fi
if test x"${MAKE}" = x""; then
AC_MSG_ERROR(You need (g)make installed in order to build ${PACKAGE})
fi
+dnl Bash is needed for building man pages and running regression tests
+if test x"${BASH_PATH}" = x""; then
+ AC_MSG_ERROR(bash must be installed in order to build ${PACKAGE})
+fi
+
AM_CONDITIONAL(BUILD_HELP, test x"${HELP2MAN}" != x"")
if test x"${HELP2MAN}" != x""; then
PCMK_FEATURES="$PCMK_FEATURES generated-manpages"
fi
MANPAGE_XSLT=""
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'
MANPAGE_XSLT=$(${XMLCATALOG} "" ${DOCBOOK_XSL_URI}/${DOCBOOK_XSL_PATH} \
| sed -n 's|^file://||p;q')
if test x"${MANPAGE_XSLT}" = x""; then
DIRS=$(find "${datadir}" -name $(basename $(dirname ${DOCBOOK_XSL_PATH})) \
-type d | LC_ALL=C sort)
XSLT=$(basename ${DOCBOOK_XSL_PATH})
for d in ${DIRS}; do
if test -f "${d}/${XSLT}"; then
MANPAGE_XSLT="${d}/${XSLT}"
break
fi
done
fi
fi
AC_MSG_RESULT($MANPAGE_XSLT)
AC_SUBST(MANPAGE_XSLT)
AM_CONDITIONAL(BUILD_XML_HELP, test x"${MANPAGE_XSLT}" != x"")
if test x"${MANPAGE_XSLT}" != x""; then
PCMK_FEATURES="$PCMK_FEATURES agent-manpages"
fi
AM_CONDITIONAL(BUILD_ASCIIDOC, test x"${ASCIIDOC}" != x"")
if test x"${ASCIIDOC}" != x""; then
PCMK_FEATURES="$PCMK_FEATURES ascii-docs"
fi
publican_intree_brand=no
if test x"${PUBLICAN_BRAND}" != x"" \
&& test x"${PUBLICAN}" != x"" \
&& test x"${INKSCAPE}" != x""; then
dnl special handling for clusterlabs brand (possibly in-tree version used)
test "${PUBLICAN_BRAND}" != "clusterlabs" \
|| test -d /usr/share/publican/Common_Content/clusterlabs
if test $? -ne 0; then
dnl Unknown option: brand_dir vs. Option brand_dir requires an argument
if ${PUBLICAN} build --brand_dir 2>&1 | grep -Eq 'brand_dir$'; then
AC_MSG_WARN([Cannot use in-tree clusterlabs brand, resorting to common])
PUBLICAN_BRAND=common
else
publican_intree_brand=yes
fi
fi
AC_MSG_NOTICE([Enabling Publican-generated documentation using ${PUBLICAN_BRAND} brand])
PCMK_FEATURES="$PCMK_FEATURES publican-docs"
fi
AM_CONDITIONAL([BUILD_DOCBOOK],
[test x"${PUBLICAN_BRAND}" != x"" \
&& test x"${PUBLICAN}" != x"" \
&& test x"${INKSCAPE}" != x""])
AM_CONDITIONAL([PUBLICAN_INTREE_BRAND],
[test x"${publican_intree_brand}" = x"yes"])
+dnl Pacemaker's shell scripts (and thus man page builders) rely on GNU getopt
+AC_MSG_CHECKING([for GNU-compatible getopt])
+IFS_orig=$IFS
+IFS=:
+for PATH_DIR in $PATH; do
+ IFS=$IFS_orig
+ GETOPT_PATH="${PATH_DIR}/getopt"
+ if test -f "$GETOPT_PATH" && test -x "$GETOPT_PATH" ; then
+ $GETOPT_PATH -T >/dev/null 2>/dev/null
+ if test $? -eq 4; then
+ break
+ fi
+ fi
+ GETOPT_PATH=""
+done
+IFS=$IFS_orig
+if test -n "$GETOPT_PATH"; then
+ AC_MSG_RESULT([$GETOPT_PATH])
+else
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR(Pacemaker build requires a GNU-compatible getopt)
+fi
+AC_SUBST([GETOPT_PATH])
+
dnl ========================================================================
dnl checks for library functions to replace them
dnl
dnl NoSuchFunctionName:
dnl is a dummy function which no system supplies. It is here to make
dnl the system compile semi-correctly on OpenBSD which doesn't know
dnl how to create an empty archive
dnl
dnl scandir: Only on BSD.
dnl System-V systems may have it, but hidden and/or deprecated.
dnl A replacement function is supplied for it.
dnl
dnl setenv: is some bsdish function that should also be avoided (use
dnl putenv instead)
dnl On the other hand, putenv doesn't provide the right API for the
dnl code and has memory leaks designed in (sigh...) Fortunately this
dnl A replacement function is supplied for it.
dnl
dnl strerror: returns a string that corresponds to an errno.
dnl A replacement function is supplied for it.
dnl
dnl strnlen: is a gnu function similar to strlen, but safer.
dnl We wrote a tolearably-fast replacement function for it.
dnl
dnl strndup: is a gnu function similar to strdup, but safer.
dnl We wrote a tolearably-fast replacement function for it.
AC_REPLACE_FUNCS(alphasort NoSuchFunctionName scandir setenv strerror strchrnul unsetenv strnlen strndup)
dnl ===============================================
dnl Libraries
dnl ===============================================
AC_CHECK_LIB(socket, socket) dnl -lsocket
AC_CHECK_LIB(c, dlopen) dnl if dlopen is in libc...
AC_CHECK_LIB(dl, dlopen) dnl -ldl (for Linux)
AC_CHECK_LIB(rt, sched_getscheduler) dnl -lrt (for Tru64)
AC_CHECK_LIB(gnugetopt, getopt_long) dnl -lgnugetopt ( if available )
AC_CHECK_LIB(pam, pam_start) dnl -lpam (if available)
AC_CHECK_FUNCS([sched_setscheduler])
AC_CHECK_LIB(uuid, uuid_parse) dnl load the library if necessary
AC_CHECK_FUNCS(uuid_unparse) dnl OSX ships uuid_* as standard functions
AC_CHECK_HEADERS(uuid/uuid.h)
if test "x$ac_cv_func_uuid_unparse" != xyes; then
AC_MSG_ERROR(You do not have the libuuid development package installed)
fi
if test x"${PKG_CONFIG}" = x""; then
AC_MSG_ERROR(You need pkgconfig installed in order to build ${PACKAGE})
fi
if
$PKG_CONFIG --exists glib-2.0
then
GLIBCONFIG="$PKG_CONFIG glib-2.0"
else
set -x
echo PKG_CONFIG_PATH=$PKG_CONFIG_PATH
$PKG_CONFIG --exists glib-2.0; echo $?
$PKG_CONFIG --cflags glib-2.0; echo $?
$PKG_CONFIG glib-2.0; echo $?
set +x
AC_MSG_ERROR(You need glib2-devel installed in order to build ${PACKAGE})
fi
AC_MSG_RESULT(using $GLIBCONFIG)
#
# Where is dlopen?
#
if test "$ac_cv_lib_c_dlopen" = yes; then
LIBADD_DL=""
elif test "$ac_cv_lib_dl_dlopen" = yes; then
LIBADD_DL=-ldl
else
LIBADD_DL=${lt_cv_dlopen_libs}
fi
if test "X$GLIBCONFIG" != X; then
AC_MSG_CHECKING(for special glib includes: )
GLIBHEAD=`$GLIBCONFIG --cflags`
AC_MSG_RESULT($GLIBHEAD)
CPPFLAGS="$CPPFLAGS $GLIBHEAD"
AC_MSG_CHECKING(for glib library flags)
GLIBLIB=`$GLIBCONFIG --libs`
AC_MSG_RESULT($GLIBLIB)
LIBS="$LIBS $GLIBLIB"
fi
dnl FreeBSD needs -lcompat for ftime() used by lrmd.c
AC_CHECK_LIB([compat], [ftime], [COMPAT_LIBS='-lcompat'])
AC_SUBST(COMPAT_LIBS)
dnl ========================================================================
dnl Headers
dnl ========================================================================
-AC_HEADER_STDC
+dnl Some distributions insert #warnings into deprecated headers such as
+dnl timeb.h. If we will enable fatal warnings for the build, then enable
+dnl them for the header checks as well, otherwise the build could fail
+dnl even though the header check succeeds. (We should probably be doing
+dnl this in more places.)
+if test "x${enable_fatal_warnings}" = xyes ; then
+ cc_temp_flags "$CFLAGS $WERROR"
+fi
AC_CHECK_HEADERS(arpa/inet.h)
AC_CHECK_HEADERS(ctype.h)
AC_CHECK_HEADERS(dirent.h)
AC_CHECK_HEADERS(errno.h)
AC_CHECK_HEADERS(getopt.h)
AC_CHECK_HEADERS(glib.h)
AC_CHECK_HEADERS(grp.h)
AC_CHECK_HEADERS(limits.h)
AC_CHECK_HEADERS(linux/swab.h)
AC_CHECK_HEADERS(malloc.h)
AC_CHECK_HEADERS(netdb.h)
AC_CHECK_HEADERS(netinet/in.h)
AC_CHECK_HEADERS(netinet/ip.h)
AC_CHECK_HEADERS(pwd.h)
AC_CHECK_HEADERS(sgtty.h)
AC_CHECK_HEADERS(signal.h)
AC_CHECK_HEADERS(stdarg.h)
AC_CHECK_HEADERS(stddef.h)
AC_CHECK_HEADERS(stdio.h)
AC_CHECK_HEADERS(stdlib.h)
AC_CHECK_HEADERS(string.h)
AC_CHECK_HEADERS(strings.h)
AC_CHECK_HEADERS(sys/dir.h)
AC_CHECK_HEADERS(sys/ioctl.h)
AC_CHECK_HEADERS(sys/param.h)
AC_CHECK_HEADERS(sys/reboot.h)
AC_CHECK_HEADERS(sys/resource.h)
AC_CHECK_HEADERS(sys/socket.h)
AC_CHECK_HEADERS(sys/signalfd.h)
AC_CHECK_HEADERS(sys/sockio.h)
AC_CHECK_HEADERS(sys/stat.h)
AC_CHECK_HEADERS(sys/time.h)
AC_CHECK_HEADERS(sys/timeb.h)
AC_CHECK_HEADERS(sys/types.h)
AC_CHECK_HEADERS(sys/utsname.h)
AC_CHECK_HEADERS(sys/wait.h)
AC_CHECK_HEADERS(time.h)
AC_CHECK_HEADERS(unistd.h)
+if test "x${enable_fatal_warnings}" = xyes ; then
+ cc_restore_flags
+fi
dnl These headers need prerequisites before the tests will pass
dnl AC_CHECK_HEADERS(net/if.h)
PKG_CHECK_MODULES(LIBXML2, [libxml-2.0],
[CPPFLAGS="${CPPFLAGS} ${LIBXML2_CFLAGS}"
LIBS="${LIBS} ${LIBXML2_LIBS}"])
AC_CHECK_HEADERS(libxml/xpath.h)
if test "$ac_cv_header_libxml_xpath_h" != "yes"; then
AC_MSG_ERROR(libxml development headers not found)
fi
AC_CHECK_LIB(xslt, xsltApplyStylesheet, [],
AC_MSG_ERROR(Unsupported libxslt library version))
AC_CHECK_HEADERS(libxslt/xslt.h)
if test "$ac_cv_header_libxslt_xslt_h" != "yes"; then
AC_MSG_ERROR(libxslt development headers not found)
fi
AC_CACHE_CHECK(whether __progname and __progname_full are available,
pf_cv_var_progname,
AC_TRY_LINK([extern char *__progname, *__progname_full;],
[__progname = "foo"; __progname_full = "foo bar";],
pf_cv_var_progname="yes", pf_cv_var_progname="no"))
if test "$pf_cv_var_progname" = "yes"; then
AC_DEFINE(HAVE___PROGNAME,1,[ ])
fi
dnl ========================================================================
dnl Structures
dnl ========================================================================
AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,,[[#include <time.h>]])
AC_CHECK_MEMBERS([lrm_op_t.rsc_deleted],,,[[#include <lrm/lrm_api.h>]])
AC_CHECK_MEMBER([struct dirent.d_type],
AC_DEFINE(HAVE_STRUCT_DIRENT_D_TYPE,1,[Define this if struct dirent has d_type]),,
[#include <dirent.h>])
dnl ========================================================================
dnl Functions
dnl ========================================================================
AC_CHECK_FUNCS(getopt, AC_DEFINE(HAVE_DECL_GETOPT, 1, [Have getopt function]))
AC_CHECK_FUNCS(nanosleep, AC_DEFINE(HAVE_DECL_NANOSLEEP, 1, [Have nanosleep function]))
dnl ========================================================================
dnl bzip2
dnl ========================================================================
AC_CHECK_HEADERS(bzlib.h)
AC_CHECK_LIB(bz2, BZ2_bzBuffToBuffCompress)
if test x$ac_cv_lib_bz2_BZ2_bzBuffToBuffCompress != xyes ; then
AC_MSG_ERROR(BZ2 libraries not found)
fi
if test x$ac_cv_header_bzlib_h != xyes; then
AC_MSG_ERROR(BZ2 Development headers not found)
fi
dnl ========================================================================
dnl sighandler_t is missing from Illumos, Solaris11 systems
dnl ========================================================================
AC_MSG_CHECKING([for sighandler_t])
AC_TRY_COMPILE([#include <signal.h>],[sighandler_t *f;],
has_sighandler_t=yes,has_sighandler_t=no)
AC_MSG_RESULT($has_sighandler_t)
if test "$has_sighandler_t" = "yes" ; then
AC_DEFINE( HAVE_SIGHANDLER_T, 1, [Define if sighandler_t available] )
fi
dnl ========================================================================
dnl ncurses
dnl ========================================================================
dnl
dnl A few OSes (e.g. Linux) deliver a default "ncurses" alongside "curses".
dnl Many non-Linux deliver "curses"; sites may add "ncurses".
dnl
dnl However, the source-code recommendation for both is to #include "curses.h"
dnl (i.e. "ncurses" still wants the include to be simple, no-'n', "curses.h").
dnl
dnl ncurse takes precedence.
dnl
AC_CHECK_HEADERS(curses.h)
AC_CHECK_HEADERS(curses/curses.h)
AC_CHECK_HEADERS(ncurses.h)
AC_CHECK_HEADERS(ncurses/ncurses.h)
dnl Although n-library is preferred, only look for it if the n-header was found.
CURSESLIBS=''
if test "$ac_cv_header_ncurses_h" = "yes"; then
AC_CHECK_LIB(ncurses, printw,
[AC_DEFINE(HAVE_LIBNCURSES,1, have ncurses library)])
CURSESLIBS=`$PKG_CONFIG --libs ncurses` || CURSESLIBS='-lncurses'
fi
if test "$ac_cv_header_ncurses_ncurses_h" = "yes"; then
AC_CHECK_LIB(ncurses, printw,
[AC_DEFINE(HAVE_LIBNCURSES,1, have ncurses library)])
CURSESLIBS=`$PKG_CONFIG --libs ncurses` || CURSESLIBS='-lncurses'
fi
dnl Only look for non-n-library if there was no n-library.
if test X"$CURSESLIBS" = X"" -a "$ac_cv_header_curses_h" = "yes"; then
AC_CHECK_LIB(curses, printw,
[CURSESLIBS='-lcurses'; AC_DEFINE(HAVE_LIBCURSES,1, have curses library)])
fi
dnl Only look for non-n-library if there was no n-library.
if test X"$CURSESLIBS" = X"" -a "$ac_cv_header_curses_curses_h" = "yes"; then
AC_CHECK_LIB(curses, printw,
[CURSESLIBS='-lcurses'; AC_DEFINE(HAVE_LIBCURSES,1, have curses library)])
fi
if test "x$CURSESLIBS" != "x"; then
PCMK_FEATURES="$PCMK_FEATURES ncurses"
fi
dnl Check for printw() prototype compatibility
-if test X"$CURSESLIBS" != X"" && cc_supports_flag -Wcast-qual && cc_supports_flag -Werror; then
+if test X"$CURSESLIBS" != X"" && cc_supports_flag -Wcast-qual; then
ac_save_LIBS=$LIBS
LIBS="$CURSESLIBS"
- ac_save_CFLAGS=$CFLAGS
- CFLAGS="-Wcast-qual -Werror"
+ cc_temp_flags "-Wcast-qual $WERROR"
# avoid broken test because of hardened build environment in Fedora 23+
# - https://fedoraproject.org/wiki/Changes/Harden_All_Packages
# - https://bugzilla.redhat.com/1297985
if cc_supports_flag -fPIC; then
CFLAGS="$CFLAGS -fPIC"
fi
AC_MSG_CHECKING(whether printw() requires argument of "const char *")
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([
#if defined(HAVE_NCURSES_H)
# include <ncurses.h>
#elif defined(HAVE_NCURSES_NCURSES_H)
# include <ncurses/ncurses.h>
#elif defined(HAVE_CURSES_H)
# include <curses.h>
#endif
],
[printw((const char *)"Test");]
)],
[ac_cv_compatible_printw=yes],
[ac_cv_compatible_printw=no]
)
LIBS=$ac_save_LIBS
- CFLAGS=$ac_save_CFLAGS
+ cc_restore_flags
AC_MSG_RESULT([$ac_cv_compatible_printw])
if test "$ac_cv_compatible_printw" = no; then
AC_MSG_WARN([The printw() function of your ncurses or curses library is old, we will disable usage of the library. If you want to use this library anyway, please update to newer version of the library, ncurses 5.4 or later is recommended. You can get the library from http://www.gnu.org/software/ncurses/.])
AC_MSG_NOTICE([Disabling curses])
AC_DEFINE(HAVE_INCOMPATIBLE_PRINTW, 1, [Do we have incompatible printw() in curses library?])
fi
fi
AC_SUBST(CURSESLIBS)
dnl ========================================================================
dnl Profiling and GProf
dnl ========================================================================
AC_MSG_NOTICE(Old CFLAGS: $CFLAGS)
case $SUPPORT_COVERAGE in
1|yes|true)
SUPPORT_PROFILING=1
PCMK_FEATURES="$PCMK_FEATURES coverage"
CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage"
dnl During linking, make sure to specify -lgcov or -coverage
;;
esac
case $SUPPORT_PROFILING in
1|yes|true)
SUPPORT_PROFILING=1
dnl Disable various compiler optimizations
CFLAGS="$CFLAGS -fno-omit-frame-pointer -fno-inline -fno-builtin "
dnl CFLAGS="$CFLAGS -fno-inline-functions -fno-default-inline -fno-inline-functions-called-once -fno-optimize-sibling-calls"
dnl Turn off optimization so tools can get accurate line numbers
CFLAGS=`echo $CFLAGS | sed -e 's/-O.\ //g' -e 's/-Wp,-D_FORTIFY_SOURCE=.\ //g' -e 's/-D_FORTIFY_SOURCE=.\ //g'`
CFLAGS="$CFLAGS -O0 -g3 -gdwarf-2"
dnl Update features
PCMK_FEATURES="$PCMK_FEATURES profile"
;;
*)
SUPPORT_PROFILING=0
;;
esac
AC_MSG_NOTICE(New CFLAGS: $CFLAGS)
AC_DEFINE_UNQUOTED(SUPPORT_PROFILING, $SUPPORT_PROFILING, Support for profiling)
dnl ========================================================================
dnl Cluster infrastructure - LibQB
dnl ========================================================================
if test x${enable_no_stack} = xyes; then
SUPPORT_CS=no
fi
PKG_CHECK_MODULES(libqb, libqb >= 0.13)
CPPFLAGS="$libqb_CFLAGS $CPPFLAGS"
LIBS="$libqb_LIBS $LIBS"
dnl libqb 0.14.0+ (2012-06)
AC_CHECK_LIB(qb, qb_ipcs_connection_auth_set)
PCMK_FEATURES="$PCMK_FEATURES libqb-logging libqb-ipc"
dnl libqb 0.17.0+ (2014-02)
AC_CHECK_FUNCS(qb_ipcs_connection_get_buffer_size,
AC_DEFINE(HAVE_IPCS_GET_BUFFER_SIZE, 1,
[Have qb_ipcc_get_buffer_size function]))
dnl Support Linux-HA fence agents if available
if test "$cross_compiling" != "yes"; then
CPPFLAGS="$CPPFLAGS -I${prefix}/include/heartbeat"
fi
AC_CHECK_HEADERS(stonith/stonith.h)
if test "$ac_cv_header_stonith_stonith_h" = "yes"; then
dnl On Debian, AC_CHECK_LIBS fail if a library has any unresolved symbols
dnl So check for all the dependencies (so they're added to LIBS) before checking for -lplumb
AC_CHECK_LIB(pils, PILLoadPlugin)
AC_CHECK_LIB(plumb, G_main_add_IPC_Channel)
PCMK_FEATURES="$PCMK_FEATURES lha-fencing"
fi
dnl ===============================================
dnl Variables needed for substitution
dnl ===============================================
CRM_SCHEMA_DIRECTORY="${datadir}/pacemaker"
AC_DEFINE_UNQUOTED(CRM_SCHEMA_DIRECTORY,"$CRM_SCHEMA_DIRECTORY", Location for the Pacemaker Relax-NG Schema)
AC_SUBST(CRM_SCHEMA_DIRECTORY)
CRM_CORE_DIR="${localstatedir}/lib/pacemaker/cores"
AC_DEFINE_UNQUOTED(CRM_CORE_DIR,"$CRM_CORE_DIR", Location to store core files produced by Pacemaker daemons)
AC_SUBST(CRM_CORE_DIR)
CRM_DAEMON_USER="hacluster"
AC_DEFINE_UNQUOTED(CRM_DAEMON_USER,"$CRM_DAEMON_USER", User to run Pacemaker daemons as)
AC_SUBST(CRM_DAEMON_USER)
CRM_DAEMON_GROUP="haclient"
AC_DEFINE_UNQUOTED(CRM_DAEMON_GROUP,"$CRM_DAEMON_GROUP", Group to run Pacemaker daemons as)
AC_SUBST(CRM_DAEMON_GROUP)
CRM_STATE_DIR=${localstatedir}/run/crm
AC_DEFINE_UNQUOTED(CRM_STATE_DIR,"$CRM_STATE_DIR", Where to keep state files and sockets)
AC_SUBST(CRM_STATE_DIR)
CRM_PACEMAKER_DIR=${localstatedir}/lib/pacemaker
AC_DEFINE_UNQUOTED(CRM_PACEMAKER_DIR,"$CRM_PACEMAKER_DIR", Location to store directory produced by Pacemaker daemons)
AC_SUBST(CRM_PACEMAKER_DIR)
CRM_BLACKBOX_DIR=${localstatedir}/lib/pacemaker/blackbox
AC_DEFINE_UNQUOTED(CRM_BLACKBOX_DIR,"$CRM_BLACKBOX_DIR", Where to keep blackbox dumps)
AC_SUBST(CRM_BLACKBOX_DIR)
PE_STATE_DIR="${localstatedir}/lib/pacemaker/pengine"
AC_DEFINE_UNQUOTED(PE_STATE_DIR,"$PE_STATE_DIR", Where to keep PEngine outputs)
AC_SUBST(PE_STATE_DIR)
CRM_CONFIG_DIR="${localstatedir}/lib/pacemaker/cib"
AC_DEFINE_UNQUOTED(CRM_CONFIG_DIR,"$CRM_CONFIG_DIR", Where to keep configuration files)
AC_SUBST(CRM_CONFIG_DIR)
CRM_CONFIG_CTS="${localstatedir}/lib/pacemaker/cts"
AC_DEFINE_UNQUOTED(CRM_CONFIG_CTS,"$CRM_CONFIG_CTS", Where to keep cts stateful data)
AC_SUBST(CRM_CONFIG_CTS)
CRM_DAEMON_DIR="${libexecdir}/pacemaker"
AC_DEFINE_UNQUOTED(CRM_DAEMON_DIR,"$CRM_DAEMON_DIR", Location for Pacemaker daemons)
AC_SUBST(CRM_DAEMON_DIR)
HA_STATE_DIR="${localstatedir}/run"
AC_DEFINE_UNQUOTED(HA_STATE_DIR,"$HA_STATE_DIR", Where sbd keeps its PID file)
AC_SUBST(HA_STATE_DIR)
CRM_RSCTMP_DIR="${localstatedir}/run/resource-agents"
AC_DEFINE_UNQUOTED(CRM_RSCTMP_DIR,"$CRM_RSCTMP_DIR", Where resource agents should keep state files)
AC_SUBST(CRM_RSCTMP_DIR)
PACEMAKER_CONFIG_DIR="${sysconfdir}/pacemaker"
AC_DEFINE_UNQUOTED(PACEMAKER_CONFIG_DIR,"$PACEMAKER_CONFIG_DIR", Where to keep configuration files like authkey)
AC_SUBST(PACEMAKER_CONFIG_DIR)
OCF_ROOT_DIR="/usr/lib/ocf"
if test "X$OCF_ROOT_DIR" = X; then
AC_MSG_ERROR(Could not locate OCF directory)
fi
AC_SUBST(OCF_ROOT_DIR)
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)
RH_STONITH_DIR="$sbindir"
AC_DEFINE_UNQUOTED(RH_STONITH_DIR,"$RH_STONITH_DIR", Location for Red Hat Stonith agents)
AC_DEFINE_UNQUOTED(SBIN_DIR,"$sbindir", Location for system binaries)
RH_STONITH_PREFIX="fence_"
AC_DEFINE_UNQUOTED(RH_STONITH_PREFIX,"$RH_STONITH_PREFIX", Prefix for Red Hat Stonith agents)
AC_PATH_PROGS(GIT, git false)
AC_MSG_CHECKING(build version)
BUILD_VERSION=$Format:%h$
if test $BUILD_VERSION != ":%h$"; then
AC_MSG_RESULT(archive hash: $BUILD_VERSION)
elif test -x $GIT -a -d .git; then
BUILD_VERSION=`$GIT log --pretty="format:%h" -n 1`
AC_MSG_RESULT(git hash: $BUILD_VERSION)
else
# The current directory name make a reasonable default
# Most generated archives will include the hash or tag
BASE=`basename $PWD`
BUILD_VERSION=`echo $BASE | sed s:.*[[Pp]]acemaker-::`
AC_MSG_RESULT(directory based hash: $BUILD_VERSION)
fi
AC_DEFINE_UNQUOTED(BUILD_VERSION, "$BUILD_VERSION", Build version)
AC_SUBST(BUILD_VERSION)
HAVE_dbus=1
HAVE_upstart=0
HAVE_systemd=0
PKG_CHECK_MODULES(DBUS, dbus-1, ,HAVE_dbus=0)
AC_DEFINE_UNQUOTED(SUPPORT_DBUS, $HAVE_dbus, Support dbus)
AM_CONDITIONAL(BUILD_DBUS, test $HAVE_dbus = 1)
if test $HAVE_dbus = 1; then
CFLAGS="$CFLAGS `$PKG_CONFIG --cflags dbus-1`"
fi
DBUS_LIBS="$CFLAGS `$PKG_CONFIG --libs dbus-1`"
AC_SUBST(DBUS_LIBS)
AC_CHECK_TYPES([DBusBasicValue],,,[[#include <dbus/dbus.h>]])
if test "x${enable_systemd}" != xno; then
if test $HAVE_dbus = 0; then
if test "x${enable_systemd}" = xyes; then
AC_MSG_FAILURE([cannot enable systemd without DBus])
else
enable_systemd=no
fi
fi
if test "x${enable_systemd}" = xtry; then
AC_MSG_CHECKING([for systemd version query result via dbus-send])
ret=$({ dbus-send --system --print-reply \
--dest=org.freedesktop.systemd1 \
/org/freedesktop/systemd1 \
org.freedesktop.DBus.Properties.Get \
string:org.freedesktop.systemd1.Manager \
string:Version 2>/dev/null \
|| echo "this borked"; } | tail -n1)
# sanitize output a bit (interested just in value, not type),
# ret is intentionally unenquoted so as to normalize whitespace
ret=$(echo ${ret} | cut -d' ' -f2-)
AC_MSG_RESULT([${ret}])
if test "x${ret}" != xborked \
|| systemctl --version 2>/dev/null | grep -q systemd; then
enable_systemd=yes
else
enable_systemd=no
fi
fi
fi
AC_MSG_CHECKING([whether to enable support for managing resources via systemd])
AC_MSG_RESULT([${enable_systemd}])
if test "x${enable_systemd}" = xyes; then
HAVE_systemd=1
PCMK_FEATURES="$PCMK_FEATURES systemd"
AC_MSG_CHECKING([for systemd path for system unit files])
systemdunitdir="${systemdunitdir-}"
PKG_CHECK_VAR([systemdunitdir], [systemd],
[systemdsystemunitdir], [], [systemdunitdir=no])
AC_MSG_RESULT([${systemdunitdir}])
if test "x${systemdunitdir}" = xno; then
AC_MSG_FAILURE([cannot enable systemd when systemdunitdir unresolved])
fi
fi
AC_SUBST(systemdunitdir)
AC_DEFINE_UNQUOTED(SUPPORT_SYSTEMD, $HAVE_systemd, Support systemd based system services)
AM_CONDITIONAL(BUILD_SYSTEMD, test $HAVE_systemd = 1)
AC_SUBST(SUPPORT_SYSTEMD)
if test "x${enable_upstart}" != xno; then
if test $HAVE_dbus = 0; then
if test "x${enable_upstart}" = xyes; then
AC_MSG_FAILURE([cannot enable Upstart without DBus])
else
enable_upstart=no
fi
fi
if test "x${enable_upstart}" = xtry; then
AC_MSG_CHECKING([for Upstart version query result via dbus-send])
ret=$({ dbus-send --system --print-reply --dest=com.ubuntu.Upstart \
/com/ubuntu/Upstart org.freedesktop.DBus.Properties.Get \
string:com.ubuntu.Upstart0_6 string:version 2>/dev/null \
|| echo "this borked"; } | tail -n1)
# sanitize output a bit (interested just in value, not type),
# ret is intentionally unenquoted so as to normalize whitespace
ret=$(echo ${ret} | cut -d' ' -f2-)
AC_MSG_RESULT([${ret}])
if test "x${ret}" != xborked \
|| initctl --version 2>/dev/null | grep -q upstart; then
enable_upstart=yes
else
enable_upstart=no
fi
fi
fi
AC_MSG_CHECKING([whether to enable support for managing resources via Upstart])
AC_MSG_RESULT([${enable_upstart}])
if test "x${enable_upstart}" = xyes; then
HAVE_upstart=1
PCMK_FEATURES="$PCMK_FEATURES upstart"
fi
AC_DEFINE_UNQUOTED(SUPPORT_UPSTART, $HAVE_upstart, Support upstart based system services)
AM_CONDITIONAL(BUILD_UPSTART, test $HAVE_upstart = 1)
AC_SUBST(SUPPORT_UPSTART)
case $SUPPORT_NAGIOS in
1|yes|true|try)
SUPPORT_NAGIOS=1
;;
*)
SUPPORT_NAGIOS=0
;;
esac
if test $SUPPORT_NAGIOS = 1; then
PCMK_FEATURES="$PCMK_FEATURES nagios"
fi
AC_DEFINE_UNQUOTED(SUPPORT_NAGIOS, $SUPPORT_NAGIOS, Support nagios plugins)
AM_CONDITIONAL(BUILD_NAGIOS, test $SUPPORT_NAGIOS = 1)
if test x"$NAGIOS_PLUGIN_DIR" = x""; then
NAGIOS_PLUGIN_DIR="${libexecdir}/nagios/plugins"
fi
AC_DEFINE_UNQUOTED(NAGIOS_PLUGIN_DIR, "$NAGIOS_PLUGIN_DIR", Directory for nagios plugins)
AC_SUBST(NAGIOS_PLUGIN_DIR)
if test x"$NAGIOS_METADATA_DIR" = x""; then
NAGIOS_METADATA_DIR="${datadir}/nagios/plugins-metadata"
fi
AC_DEFINE_UNQUOTED(NAGIOS_METADATA_DIR, "$NAGIOS_METADATA_DIR", Directory for nagios plugins metadata)
AC_SUBST(NAGIOS_METADATA_DIR)
STACKS=""
CLUSTERLIBS=""
dnl ========================================================================
dnl Cluster stack - Corosync
dnl ========================================================================
dnl Normalize the values
case $SUPPORT_CS in
1|yes|true)
SUPPORT_CS=yes
missingisfatal=1
;;
try)
missingisfatal=0
;;
*)
SUPPORT_CS=no
;;
esac
AC_MSG_CHECKING(for native corosync)
COROSYNC_LIBS=""
if test $SUPPORT_CS = no; then
AC_MSG_RESULT(no (disabled))
SUPPORT_CS=0
else
AC_MSG_RESULT($SUPPORT_CS)
SUPPORT_CS=1
PKG_CHECK_MODULES(cpg, libcpg) dnl Fatal
PKG_CHECK_MODULES(cfg, libcfg) dnl Fatal
PKG_CHECK_MODULES(cmap, libcmap) dnl Fatal
PKG_CHECK_MODULES(quorum, libquorum) dnl Fatal
PKG_CHECK_MODULES(libcorosync_common, libcorosync_common) dnl Fatal
CFLAGS="$CFLAGS $libqb_FLAGS $cpg_FLAGS $cfg_FLAGS $cmap_CFLAGS $quorum_CFLAGS $libcorosync_common_CFLAGS"
COROSYNC_LIBS="$COROSYNC_LIBS $libqb_LIBS $cpg_LIBS $cfg_LIBS $cmap_LIBS $quorum_LIBS $libcorosync_common_LIBS"
CLUSTERLIBS="$CLUSTERLIBS $COROSYNC_LIBS"
STACKS="$STACKS corosync-native"
fi
AC_DEFINE_UNQUOTED(SUPPORT_COROSYNC, $SUPPORT_CS, Support the Corosync messaging and membership layer)
AM_CONDITIONAL(BUILD_CS_SUPPORT, test $SUPPORT_CS = 1)
AC_SUBST(SUPPORT_COROSYNC)
dnl
dnl Cluster stack - Sanity
dnl
if test x${enable_no_stack} = xyes; then
AC_MSG_NOTICE(No cluster stack supported. Just building the Policy Engine)
PCMK_FEATURES="$PCMK_FEATURES no-cluster-stack"
else
AC_MSG_CHECKING(for supported stacks)
if test x"$STACKS" = x; then
AC_MSG_FAILURE(You must support at least one cluster stack)
fi
AC_MSG_RESULT($STACKS)
PCMK_FEATURES="$PCMK_FEATURES $STACKS"
fi
PCMK_FEATURES="$PCMK_FEATURES atomic-attrd"
AC_SUBST(CLUSTERLIBS)
dnl ========================================================================
dnl ACL
dnl ========================================================================
case $SUPPORT_ACL in
1|yes|true)
missingisfatal=1
;;
try)
missingisfatal=0
;;
*)
SUPPORT_ACL=no
;;
esac
AC_MSG_CHECKING(for acl support)
if test $SUPPORT_ACL = no; then
AC_MSG_RESULT(no (disabled))
SUPPORT_ACL=0
else
AC_MSG_RESULT($SUPPORT_ACL)
SUPPORT_ACL=1
AC_CHECK_LIB(qb, qb_ipcs_connection_auth_set)
if test $ac_cv_lib_qb_qb_ipcs_connection_auth_set != yes; then
SUPPORT_ACL=0
fi
if test $SUPPORT_ACL = 0; then
if test $missingisfatal = 0; then
AC_MSG_WARN(Unable to support ACL. You need to use libqb > 0.13.0)
else
AC_MSG_FAILURE(Unable to support ACL. You need to use libqb > 0.13.0)
fi
fi
fi
if test $SUPPORT_ACL = 1; then
PCMK_FEATURES="$PCMK_FEATURES acls"
fi
AM_CONDITIONAL(ENABLE_ACL, test "$SUPPORT_ACL" = "1")
AC_DEFINE_UNQUOTED(ENABLE_ACL, $SUPPORT_ACL, Build in support for CIB ACL)
dnl ========================================================================
dnl CIB secrets
dnl ========================================================================
case $SUPPORT_CIBSECRETS in
1|yes|true|try)
SUPPORT_CIBSECRETS=1
;;
*)
SUPPORT_CIBSECRETS=0
;;
esac
AC_DEFINE_UNQUOTED(SUPPORT_CIBSECRETS, $SUPPORT_CIBSECRETS, Support CIB secrets)
AM_CONDITIONAL(BUILD_CIBSECRETS, test $SUPPORT_CIBSECRETS = 1)
if test $SUPPORT_CIBSECRETS = 1; then
PCMK_FEATURES="$PCMK_FEATURES cibsecrets"
LRM_CIBSECRETS_DIR="${localstatedir}/lib/pacemaker/lrm/secrets"
AC_DEFINE_UNQUOTED(LRM_CIBSECRETS_DIR,"$LRM_CIBSECRETS_DIR", Location for CIB secrets)
AC_SUBST(LRM_CIBSECRETS_DIR)
fi
dnl ========================================================================
dnl GnuTLS
dnl ========================================================================
AC_CHECK_HEADERS(gnutls/gnutls.h)
AC_CHECK_HEADERS(security/pam_appl.h pam/pam_appl.h)
dnl GNUTLS library: Attempt to determine by 'libgnutls-config' program.
dnl If no 'libgnutls-config', try traditional autoconf means.
AC_PATH_PROGS(LIBGNUTLS_CONFIG, libgnutls-config)
if test -n "$LIBGNUTLS_CONFIG"; then
AC_MSG_CHECKING(for gnutls header flags)
GNUTLSHEAD="`$LIBGNUTLS_CONFIG --cflags`";
AC_MSG_RESULT($GNUTLSHEAD)
AC_MSG_CHECKING(for gnutls library flags)
GNUTLSLIBS="`$LIBGNUTLS_CONFIG --libs`";
AC_MSG_RESULT($GNUTLSLIBS)
fi
AC_CHECK_LIB(gnutls, gnutls_init)
AC_CHECK_FUNCS(gnutls_priority_set_direct)
AC_SUBST(GNUTLSHEAD)
AC_SUBST(GNUTLSLIBS)
dnl ========================================================================
dnl System Health
dnl ========================================================================
dnl Check if servicelog development package is installed
SERVICELOG=servicelog-1
SERVICELOG_EXISTS="no"
AC_MSG_CHECKING(for $SERVICELOG packages)
if
$PKG_CONFIG --exists $SERVICELOG
then
PKG_CHECK_MODULES([SERVICELOG], [servicelog-1])
SERVICELOG_EXISTS="yes"
fi
AC_MSG_RESULT($SERVICELOG_EXISTS)
AM_CONDITIONAL(BUILD_SERVICELOG, test "$SERVICELOG_EXISTS" = "yes")
dnl Check if OpenIMPI packages and servicelog are installed
OPENIPMI="OpenIPMI OpenIPMIposix"
OPENIPMI_SERVICELOG_EXISTS="no"
AC_MSG_CHECKING(for $SERVICELOG $OPENIPMI packages)
if
$PKG_CONFIG --exists $OPENIPMI $SERVICELOG
then
PKG_CHECK_MODULES([OPENIPMI_SERVICELOG],[OpenIPMI OpenIPMIposix])
OPENIPMI_SERVICELOG_EXISTS="yes"
fi
AC_MSG_RESULT($OPENIPMI_SERVICELOG_EXISTS)
AM_CONDITIONAL(BUILD_OPENIPMI_SERVICELOG, test "$OPENIPMI_SERVICELOG_EXISTS" = "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.
if export | fgrep " CFLAGS=" > /dev/null; then
SAVED_CFLAGS="$CFLAGS"
unset CFLAGS
CFLAGS="$SAVED_CFLAGS"
unset SAVED_CFLAGS
fi
AC_ARG_VAR([CFLAGS_HARDENED_LIB], [extra C compiler flags for hardened libraries])
AC_ARG_VAR([LDFLAGS_HARDENED_LIB], [extra linker flags for hardened libraries])
AC_ARG_VAR([CFLAGS_HARDENED_EXE], [extra C compiler flags for hardened executables])
AC_ARG_VAR([LDFLAGS_HARDENED_EXE], [extra linker flags for hardened executables])
CC_EXTRAS=""
if test "$GCC" != yes; then
CFLAGS="$CFLAGS -g"
- enable_fatal_warnings=no
else
CFLAGS="$CFLAGS -ggdb"
dnl When we don't have diagnostic push / pull, we can't explicitly disable
dnl checking for nonliteral formats in the places where they occur on purpose
dnl thus we disable nonliteral format checking globally as we are aborting
dnl on warnings.
dnl what makes the things really ugly is that nonliteral format checking is
dnl obviously available as an extra switch in very modern gcc but for older
dnl gcc this is part of -Wformat=2
dnl so if we have push/pull we can enable -Wformat=2 -Wformat-nonliteral
dnl if we don't have push/pull but -Wformat-nonliteral we can enable -Wformat=2
dnl otherwise none of both
gcc_diagnostic_push_pull=no
- SAVED_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -Werror"
+ cc_temp_flags "$CFLAGS $WERROR"
AC_MSG_CHECKING([for gcc diagnostic push / pull])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#pragma GCC diagnostic push
#pragma GCC diagnostic pop
]])],
[
AC_MSG_RESULT([yes])
gcc_diagnostic_push_pull=yes
], AC_MSG_RESULT([no]))
- CFLAGS="$SAVED_CFLAGS"
+ cc_restore_flags
if cc_supports_flag "-Wformat-nonliteral"; then
gcc_format_nonliteral=yes
else
gcc_format_nonliteral=no
fi
# We had to eliminate -Wnested-externs because of libtool changes
# Make sure to order options so that the former stand for prerequisites
# of the latter (e.g., -Wformat-nonliteral requires -Wformat).
EXTRA_FLAGS="-fgnu89-inline
-Wall
-Waggregate-return
-Wbad-function-cast
-Wcast-align
-Wdeclaration-after-statement
-Wendif-labels
-Wfloat-equal
-Wformat-security
-Wmissing-prototypes
-Wmissing-declarations
-Wnested-externs
-Wno-long-long
-Wno-strict-aliasing
-Wpointer-arith
-Wstrict-prototypes
-Wwrite-strings
-Wunused-but-set-variable
-Wunsigned-char"
if test "x$gcc_diagnostic_push_pull" = "xyes"; then
AC_DEFINE([GCC_FORMAT_NONLITERAL_CHECKING_ENABLED], [],
[gcc can complain about nonliterals in format])
EXTRA_FLAGS="$EXTRA_FLAGS
-Wformat=2
-Wformat-nonliteral"
else
if test "x$gcc_format_nonliteral" = "xyes"; then
EXTRA_FLAGS="$EXTRA_FLAGS -Wformat=2"
fi
fi
# Additional warnings it might be nice to enable one day
# -Wshadow
# -Wunreachable-code
for j in $EXTRA_FLAGS
do
if
cc_supports_flag $CC_EXTRAS $j
then
CC_EXTRAS="$CC_EXTRAS $j"
fi
done
-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}" = xyes && 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
dnl
dnl Hardening flags
dnl
dnl The prime control of whether to apply (targeted) hardening build flags and
dnl which ones is --{enable,disable}-hardening option passed to ./configure:
dnl
dnl --enable-hardening=try (default):
dnl depending on whether any of CFLAGS_HARDENED_EXE, LDFLAGS_HARDENED_EXE,
dnl CFLAGS_HARDENED_LIB or LDFLAGS_HARDENED_LIB environment variables
dnl (see below) is set and non-null, all these custom flags (even if not
dnl set) are used as are, otherwise the best effort is made to offer
dnl reasonably strong hardening in several categories (RELRO, PIE,
dnl "bind now", stack protector) according to what the selected toolchain
dnl can offer
dnl
dnl --enable-hardening:
dnl same effect as --enable-hardening=try when the environment variables
dnl in question are suppressed
dnl
dnl --disable-hardening:
dnl do not apply any targeted hardening measures at all
dnl
dnl The user-injected environment variables that regulate the hardening in
dnl default case are as follows:
dnl
dnl * CFLAGS_HARDENED_EXE, LDFLAGS_HARDENED_EXE
dnl compiler and linker flags (respectively) for daemon programs
dnl (attrd, cib, crmd, lrmd, stonithd, pacemakerd, pacemaker_remoted,
dnl pengine)
dnl
dnl * CFLAGS_HARDENED_LIB, LDFLAGS_HARDENED_LIB
dnl compiler and linker flags (respectively) for libraries linked
dnl with the daemon programs
dnl
dnl Note that these are purposedly targeted variables (addressing particular
dnl targets all over the scattered Makefiles) and have no effect outside of
dnl the predestined scope (e.g., CLI utilities). For a global reach,
dnl use CFLAGS, LDFLAGS, etc. as usual.
dnl
dnl For guidance on the suitable flags consult, for instance:
dnl https://fedoraproject.org/wiki/Changes/Harden_All_Packages#Detailed_Harden_Flags_Description
dnl https://owasp.org/index.php/C-Based_Toolchain_Hardening#GCC.2FBinutils
dnl
if test "x${HARDENING}" != "xtry"; then
unset CFLAGS_HARDENED_EXE
unset CFLAGS_HARDENED_LIB
unset LDFLAGS_HARDENED_EXE
unset LDFLAGS_HARDENED_LIB
fi
if test "x${HARDENING}" = "xno"; then
AC_MSG_NOTICE([Hardening: explicitly disabled])
elif test "x${HARDENING}" = "xyes" \
|| test "$(env | grep -Ec '^(C|LD)FLAGS_HARDENED_(EXE|LIB)=.')" = 0; then
dnl We'll figure out on our own...
CFLAGS_HARDENED_EXE=
CFLAGS_HARDENED_LIB=
LDFLAGS_HARDENED_EXE=
LDFLAGS_HARDENED_LIB=
relro=0
pie=0
bindnow=0
# daemons incl. libs: partial RELRO
flag="-Wl,-z,relro"
CC_CHECK_LDFLAGS(["${flag}"],
[LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}";
LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}";
relro=1])
# daemons: PIE for both CFLAGS and LDFLAGS
if cc_supports_flag -fPIE; then
flag="-pie"
CC_CHECK_LDFLAGS(["${flag}"],
[CFLAGS_HARDENED_EXE="${CFLAGS_HARDENED_EXE} -fPIE";
LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}";
pie=1])
fi
# daemons incl. libs: full RELRO if sensible + as-needed linking
# so as to possibly mitigate startup performance
# hit caused by excessive linking with unneeded
# libraries
if test "${relro}" = 1 && test "${pie}" = 1; then
flag="-Wl,-z,now"
CC_CHECK_LDFLAGS(["${flag}"],
[LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}";
LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}";
bindnow=1])
fi
if test "${bindnow}" = 1; then
flag="-Wl,--as-needed"
CC_CHECK_LDFLAGS(["${flag}"],
[LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}";
LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}"])
fi
# universal: prefer strong > all > default stack protector if possible
flag=
if cc_supports_flag -fstack-protector-strong; then
flag="-fstack-protector-strong"
elif cc_supports_flag -fstack-protector-all; then
flag="-fstack-protector-all"
elif cc_supports_flag -fstack-protector; then
flag="-fstack-protector"
fi
if test -n "${flag}"; then
CC_EXTRAS="${CC_EXTRAS} ${flag}"
stackprot=1
fi
if test "${relro}" = 1 \
|| test "${pie}" = 1 \
|| test "${stackprot}" = 1; then
AC_MSG_NOTICE([Hardening: relro=${relro} pie=${pie} bindnow=${bindnow} stackprot=${flag}])
else
AC_MSG_WARN([Hardening: no suitable features in the toolchain detected])
fi
else
AC_MSG_NOTICE([Hardening: using custom flags])
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"
+ 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(LIBADD_DL) dnl extra flags for dynamic linking libraries
AC_SUBST(LIBADD_INTL) dnl extra flags for GNU gettext stuff...
AC_SUBST(LOCALE)
dnl Options for cleaning up the compiler output
QUIET_LIBTOOL_OPTS=""
QUIET_MAKE_OPTS=""
if test "x${enable_quiet}" = "xyes"; then
QUIET_LIBTOOL_OPTS="--quiet"
QUIET_MAKE_OPTS="--quiet"
fi
AC_MSG_RESULT(Supress make details: ${enable_quiet})
dnl Put the above variables to use
LIBTOOL="${LIBTOOL} --tag=CC \$(QUIET_LIBTOOL_OPTS)"
MAKE="${MAKE} \$(QUIET_MAKE_OPTS)"
AC_SUBST(CC)
AC_SUBST(MAKE)
AC_SUBST(LIBTOOL)
AC_SUBST(QUIET_MAKE_OPTS)
AC_SUBST(QUIET_LIBTOOL_OPTS)
AC_DEFINE_UNQUOTED(CRM_FEATURES, "$PCMK_FEATURES", Set of enabled features)
AC_SUBST(PCMK_FEATURES)
dnl Files we output that need to be executable
AC_CONFIG_FILES([cts/CTSlab.py], [chmod +x cts/CTSlab.py])
AC_CONFIG_FILES([cts/LSBDummy], [chmod +x cts/LSBDummy])
AC_CONFIG_FILES([cts/OCFIPraTest.py], [chmod +x cts/OCFIPraTest.py])
AC_CONFIG_FILES([cts/cts-coverage], [chmod +x cts/cts-coverage])
AC_CONFIG_FILES([cts/cts-lrmd], [chmod +x cts/cts-lrmd])
AC_CONFIG_FILES([cts/cts-pengine], [chmod +x cts/cts-pengine])
AC_CONFIG_FILES([cts/cts-stonithd], [chmod +x cts/cts-stonithd])
AC_CONFIG_FILES([cts/lxc_autogen.sh], [chmod +x cts/lxc_autogen.sh])
AC_CONFIG_FILES([cts/benchmark/clubench], [chmod +x cts/benchmark/clubench])
AC_CONFIG_FILES([cts/fence_dummy], [chmod +x cts/fence_dummy])
+AC_CONFIG_FILES([fencing/fence_legacy], [chmod +x fencing/fence_legacy])
+AC_CONFIG_FILES([tools/crm_failcount], [chmod +x tools/crm_failcount])
+AC_CONFIG_FILES([tools/crm_master], [chmod +x tools/crm_master])
AC_CONFIG_FILES([tools/crm_report], [chmod +x tools/crm_report])
+AC_CONFIG_FILES([tools/crm_standby], [chmod +x tools/crm_standby])
AC_CONFIG_FILES([tools/cibsecret], [chmod +x tools/cibsecret])
dnl Other files we output
AC_CONFIG_FILES(Makefile \
Doxyfile \
cts/Makefile \
cts/CTSvars.py \
cts/benchmark/Makefile \
cib/Makefile \
attrd/Makefile \
crmd/Makefile \
pengine/Makefile \
doc/Makefile \
doc/Clusters_from_Scratch/publican.cfg \
doc/Pacemaker_Administration/publican.cfg \
doc/Pacemaker_Development/publican.cfg \
doc/Pacemaker_Explained/publican.cfg \
doc/Pacemaker_Remote/publican.cfg \
fencing/Makefile \
include/Makefile \
include/crm/Makefile \
include/crm/cib/Makefile \
include/crm/common/Makefile \
include/crm/cluster/Makefile \
include/crm/fencing/Makefile \
include/crm/pengine/Makefile \
replace/Makefile \
lib/Makefile \
lib/pacemaker.pc \
lib/pacemaker-cib.pc \
lib/pacemaker-lrmd.pc \
lib/pacemaker-service.pc \
lib/pacemaker-pengine.pc \
lib/pacemaker-fencing.pc \
lib/pacemaker-cluster.pc \
lib/common/Makefile \
lib/cluster/Makefile \
lib/cib/Makefile \
lib/pengine/Makefile \
lib/transition/Makefile \
lib/fencing/Makefile \
lib/lrmd/Makefile \
lib/services/Makefile \
mcp/Makefile \
mcp/pacemaker \
mcp/pacemaker.service \
mcp/pacemaker.upstart \
mcp/pacemaker.combined.upstart \
lrmd/Makefile \
lrmd/pacemaker_remote.service \
lrmd/pacemaker_remote \
extra/Makefile \
extra/alerts/Makefile \
extra/resources/Makefile \
extra/logrotate/Makefile \
extra/logrotate/pacemaker \
tools/Makefile \
tools/report.collector \
tools/report.common \
tools/crm_mon.service \
tools/crm_mon.upstart \
xml/Makefile \
lib/gnu/Makefile \
)
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} (Build: $BUILD_VERSION)])
AC_MSG_RESULT([ Features =${PCMK_FEATURES}])
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([ State information = ${localstatedir}])
AC_MSG_RESULT([ System configuration = ${sysconfdir}])
AC_MSG_RESULT([])
AC_MSG_RESULT([ HA group name = ${CRM_DAEMON_GROUP}])
AC_MSG_RESULT([ HA user name = ${CRM_DAEMON_USER}])
AC_MSG_RESULT([])
AC_MSG_RESULT([ CFLAGS = ${CFLAGS}])
AC_MSG_RESULT([ CFLAGS_HARDENED_EXE = ${CFLAGS_HARDENED_EXE}])
AC_MSG_RESULT([ CFLAGS_HARDENED_LIB = ${CFLAGS_HARDENED_LIB}])
AC_MSG_RESULT([ LDFLAGS_HARDENED_EXE = ${LDFLAGS_HARDENED_EXE}])
AC_MSG_RESULT([ LDFLAGS_HARDENED_LIB = ${LDFLAGS_HARDENED_LIB}])
AC_MSG_RESULT([ Libraries = ${LIBS}])
AC_MSG_RESULT([ Stack Libraries = ${CLUSTERLIBS}])
diff --git a/crmd/throttle.c b/crmd/throttle.c
index 62d2896981..d5e69e002f 100644
--- a/crmd/throttle.c
+++ b/crmd/throttle.c
@@ -1,532 +1,534 @@
/*
* Copyright 2013-2018 Andrew Beekhof <andrew@beekhof.net>
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <dirent.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/cluster.h>
#include <crmd_fsa.h>
#include <throttle.h>
enum throttle_state_e {
throttle_extreme = 0x1000,
throttle_high = 0x0100,
throttle_med = 0x0010,
throttle_low = 0x0001,
throttle_none = 0x0000,
};
struct throttle_record_s {
int max;
enum throttle_state_e mode;
char *node;
};
static int throttle_job_max = 0;
static float throttle_load_target = 0.0;
#define THROTTLE_FACTOR_LOW 1.2
#define THROTTLE_FACTOR_MEDIUM 1.6
#define THROTTLE_FACTOR_HIGH 2.0
static GHashTable *throttle_records = NULL;
static mainloop_timer_t *throttle_timer = NULL;
+#if SUPPORT_PROCFS
/*!
* \internal
* \brief Return name of /proc file containing the CIB deamon's load statistics
*
* \return Newly allocated memory with file name on success, NULL otherwise
*
* \note It is the caller's responsibility to free the return value.
* This will return NULL if the daemon is being run via valgrind.
* This should be called only on Linux systems.
*/
static char *
find_cib_loadfile(void)
{
int pid = crm_procfs_pid_of("cib");
return pid? crm_strdup_printf("/proc/%d/stat", pid) : NULL;
}
static bool
throttle_cib_load(float *load)
{
/*
/proc/[pid]/stat
Status information about the process. This is used by ps(1). It is defined in /usr/src/linux/fs/proc/array.c.
The fields, in order, with their proper scanf(3) format specifiers, are:
pid %d (1) The process ID.
comm %s (2) The filename of the executable, in parentheses. This is visible whether or not the executable is swapped out.
state %c (3) One character from the string "RSDZTW" where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk sleep, Z is zombie, T is traced or stopped (on a signal), and W is paging.
ppid %d (4) The PID of the parent.
pgrp %d (5) The process group ID of the process.
session %d (6) The session ID of the process.
tty_nr %d (7) The controlling terminal of the process. (The minor device number is contained in the combination of bits 31 to 20 and 7 to 0; the major device number is in bits 15 to 8.)
tpgid %d (8) The ID of the foreground process group of the controlling terminal of the process.
flags %u (%lu before Linux 2.6.22)
(9) The kernel flags word of the process. For bit meanings, see the PF_* defines in the Linux kernel source file include/linux/sched.h. Details depend on the kernel version.
minflt %lu (10) The number of minor faults the process has made which have not required loading a memory page from disk.
cminflt %lu (11) The number of minor faults that the process's waited-for children have made.
majflt %lu (12) The number of major faults the process has made which have required loading a memory page from disk.
cmajflt %lu (13) The number of major faults that the process's waited-for children have made.
utime %lu (14) Amount of time that this process has been scheduled in user mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)). This includes guest time, guest_time (time spent running a virtual CPU, see below), so that applications that are not aware of the guest time field do not lose that time from their calculations.
stime %lu (15) Amount of time that this process has been scheduled in kernel mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).
*/
static char *loadfile = NULL;
static time_t last_call = 0;
static long ticks_per_s = 0;
static unsigned long last_utime, last_stime;
char buffer[64*1024];
FILE *stream = NULL;
time_t now = time(NULL);
if(load == NULL) {
return FALSE;
} else {
*load = 0.0;
}
if(loadfile == NULL) {
last_call = 0;
last_utime = 0;
last_stime = 0;
loadfile = find_cib_loadfile();
if (loadfile == NULL) {
crm_warn("Couldn't find CIB load file");
return FALSE;
}
ticks_per_s = sysconf(_SC_CLK_TCK);
crm_trace("Found %s", loadfile);
}
stream = fopen(loadfile, "r");
if(stream == NULL) {
int rc = errno;
crm_warn("Couldn't read %s: %s (%d)", loadfile, pcmk_strerror(rc), rc);
free(loadfile); loadfile = NULL;
return FALSE;
}
if(fgets(buffer, sizeof(buffer), stream)) {
char *comm = calloc(1, 256);
char state = 0;
int rc = 0, pid = 0, ppid = 0, pgrp = 0, session = 0, tty_nr = 0, tpgid = 0;
unsigned long flags = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0, utime = 0, stime = 0;
rc = sscanf(buffer, "%d %[^ ] %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu",
&pid, comm, &state,
&ppid, &pgrp, &session, &tty_nr, &tpgid,
&flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime);
free(comm);
if(rc != 15) {
crm_err("Only %d of 15 fields found in %s", rc, loadfile);
fclose(stream);
return FALSE;
} else if(last_call > 0
&& last_call < now
&& last_utime <= utime
&& last_stime <= stime) {
time_t elapsed = now - last_call;
unsigned long delta_utime = utime - last_utime;
unsigned long delta_stime = stime - last_stime;
*load = (delta_utime + delta_stime); /* Cast to a float before division */
*load /= ticks_per_s;
*load /= elapsed;
crm_debug("cib load: %f (%lu ticks in %lds)", *load, delta_utime + delta_stime, (long)elapsed);
} else {
crm_debug("Init %lu + %lu ticks at %ld (%lu tps)", utime, stime, (long)now, ticks_per_s);
}
last_call = now;
last_utime = utime;
last_stime = stime;
fclose(stream);
return TRUE;
}
fclose(stream);
return FALSE;
}
static bool
throttle_load_avg(float *load)
{
char buffer[256];
FILE *stream = NULL;
const char *loadfile = "/proc/loadavg";
if(load == NULL) {
return FALSE;
}
stream = fopen(loadfile, "r");
if(stream == NULL) {
int rc = errno;
crm_warn("Couldn't read %s: %s (%d)", loadfile, pcmk_strerror(rc), rc);
return FALSE;
}
if(fgets(buffer, sizeof(buffer), stream)) {
char *nl = strstr(buffer, "\n");
/* Grab the 1-minute average, ignore the rest */
*load = strtof(buffer, NULL);
if(nl) { nl[0] = 0; }
fclose(stream);
return TRUE;
}
fclose(stream);
return FALSE;
}
/*!
* \internal
* \brief Check a load value against throttling thresholds
*
* \param[in] load Load value to check
* \param[in] desc Description of metric (for logging)
* \param[in] thresholds Low/medium/high/extreme thresholds
*
* \return Throttle mode corresponding to load value
*/
static enum throttle_state_e
throttle_check_thresholds(float load, const char *desc, float thresholds[4])
{
if (load > thresholds[3]) {
crm_notice("Extreme %s detected: %f", desc, load);
return throttle_extreme;
} else if (load > thresholds[2]) {
crm_notice("High %s detected: %f", desc, load);
return throttle_high;
} else if (load > thresholds[1]) {
crm_info("Moderate %s detected: %f", desc, load);
return throttle_med;
} else if (load > thresholds[0]) {
crm_debug("Noticeable %s detected: %f", desc, load);
return throttle_low;
}
crm_trace("Negligible %s detected: %f", desc, load);
return throttle_none;
}
static enum throttle_state_e
throttle_handle_load(float load, const char *desc, int cores)
{
float normalize;
float thresholds[4];
if (cores == 1) {
/* On a single core machine, a load of 1.0 is already too high */
normalize = 0.6;
} else {
/* Normalize the load to be per-core */
normalize = cores;
}
thresholds[0] = throttle_load_target * normalize * THROTTLE_FACTOR_LOW;
thresholds[1] = throttle_load_target * normalize * THROTTLE_FACTOR_MEDIUM;
thresholds[2] = throttle_load_target * normalize * THROTTLE_FACTOR_HIGH;
thresholds[3] = load + 1.0; /* never extreme */
return throttle_check_thresholds(load, desc, thresholds);
}
+#endif
static enum throttle_state_e
throttle_mode(void)
{
#if SUPPORT_PROCFS
unsigned int cores;
float load;
float thresholds[4];
enum throttle_state_e mode = throttle_none;
cores = crm_procfs_num_cores();
if(throttle_cib_load(&load)) {
float cib_max_cpu = 0.95;
/* The CIB is a single-threaded task and thus cannot consume
* more than 100% of a CPU (and 1/cores of the overall system
* load).
*
* On a many-cored system, the CIB might therefore be maxed out
* (causing operations to fail or appear to fail) even though
* the overall system load is still reasonable.
*
* Therefore, the 'normal' thresholds can not apply here, and we
* need a special case.
*/
if(cores == 1) {
cib_max_cpu = 0.4;
}
if(throttle_load_target > 0.0 && throttle_load_target < cib_max_cpu) {
cib_max_cpu = throttle_load_target;
}
thresholds[0] = cib_max_cpu * 0.8;
thresholds[1] = cib_max_cpu * 0.9;
thresholds[2] = cib_max_cpu;
/* Can only happen on machines with a low number of cores */
thresholds[3] = cib_max_cpu * 1.5;
mode |= throttle_check_thresholds(load, "CIB load", thresholds);
}
if(throttle_load_target <= 0) {
/* If we ever make this a valid value, the cluster will at least behave as expected */
return mode;
}
if(throttle_load_avg(&load)) {
crm_debug("Current load is %f across %u core(s)", load, cores);
mode |= throttle_handle_load(load, "CPU load", cores);
}
if(mode & throttle_extreme) {
return throttle_extreme;
} else if(mode & throttle_high) {
return throttle_high;
} else if(mode & throttle_med) {
return throttle_med;
} else if(mode & throttle_low) {
return throttle_low;
}
#endif // SUPPORT_PROCFS
return throttle_none;
}
static void
throttle_send_command(enum throttle_state_e mode)
{
xmlNode *xml = NULL;
static enum throttle_state_e last = -1;
if(mode != last) {
crm_info("New throttle mode: %.4x (was %.4x)", mode, last);
last = mode;
xml = create_request(CRM_OP_THROTTLE, NULL, NULL, CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
crm_xml_add_int(xml, F_CRM_THROTTLE_MODE, mode);
crm_xml_add_int(xml, F_CRM_THROTTLE_MAX, throttle_job_max);
send_cluster_message(NULL, crm_msg_crmd, xml, TRUE);
free_xml(xml);
}
}
static gboolean
throttle_timer_cb(gpointer data)
{
throttle_send_command(throttle_mode());
return TRUE;
}
static void
throttle_record_free(gpointer p)
{
struct throttle_record_s *r = p;
free(r->node);
free(r);
}
void
throttle_set_load_target(float target)
{
throttle_load_target = target;
}
void
throttle_update_job_max(const char *preference)
{
int max = 0;
throttle_job_max = 2 * crm_procfs_num_cores();
if(preference) {
/* Global preference from the CIB */
max = crm_int_helper(preference, NULL);
if(max > 0) {
throttle_job_max = max;
}
}
preference = getenv("PCMK_node_action_limit");
if(preference) {
/* Per-node override */
max = crm_int_helper(preference, NULL);
if(max > 0) {
throttle_job_max = max;
}
}
}
void
throttle_init(void)
{
if(throttle_records == NULL) {
throttle_records = g_hash_table_new_full(
crm_str_hash, g_str_equal, NULL, throttle_record_free);
throttle_timer = mainloop_timer_add("throttle", 30 * 1000, TRUE, throttle_timer_cb, NULL);
}
throttle_update_job_max(NULL);
mainloop_timer_start(throttle_timer);
}
void
throttle_fini(void)
{
mainloop_timer_del(throttle_timer); throttle_timer = NULL;
g_hash_table_destroy(throttle_records); throttle_records = NULL;
}
int
throttle_get_total_job_limit(int l)
{
/* Cluster-wide limit */
GHashTableIter iter;
int limit = l;
int peers = crm_active_peers();
struct throttle_record_s *r = NULL;
g_hash_table_iter_init(&iter, throttle_records);
while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &r)) {
switch(r->mode) {
case throttle_extreme:
if(limit == 0 || limit > peers/4) {
limit = QB_MAX(1, peers/4);
}
break;
case throttle_high:
if(limit == 0 || limit > peers/2) {
limit = QB_MAX(1, peers/2);
}
break;
default:
break;
}
}
if(limit == l) {
/* crm_trace("No change to batch-limit=%d", limit); */
} else if(l == 0) {
crm_trace("Using batch-limit=%d", limit);
} else {
crm_trace("Using batch-limit=%d instead of %d", limit, l);
}
return limit;
}
int
throttle_get_job_limit(const char *node)
{
int jobs = 1;
struct throttle_record_s *r = NULL;
r = g_hash_table_lookup(throttle_records, node);
if(r == NULL) {
r = calloc(1, sizeof(struct throttle_record_s));
r->node = strdup(node);
r->mode = throttle_low;
r->max = throttle_job_max;
crm_trace("Defaulting to local values for unknown node %s", node);
g_hash_table_insert(throttle_records, r->node, r);
}
switch(r->mode) {
case throttle_extreme:
case throttle_high:
jobs = 1; /* At least one job must always be allowed */
break;
case throttle_med:
jobs = QB_MAX(1, r->max / 4);
break;
case throttle_low:
jobs = QB_MAX(1, r->max / 2);
break;
case throttle_none:
jobs = QB_MAX(1, r->max);
break;
default:
crm_err("Unknown throttle mode %.4x on %s", r->mode, node);
break;
}
return jobs;
}
void
throttle_update(xmlNode *xml)
{
int max = 0;
enum throttle_state_e mode = 0;
struct throttle_record_s *r = NULL;
const char *from = crm_element_value(xml, F_CRM_HOST_FROM);
crm_element_value_int(xml, F_CRM_THROTTLE_MODE, (int*)&mode);
crm_element_value_int(xml, F_CRM_THROTTLE_MAX, &max);
r = g_hash_table_lookup(throttle_records, from);
if(r == NULL) {
r = calloc(1, sizeof(struct throttle_record_s));
r->node = strdup(from);
g_hash_table_insert(throttle_records, r->node, r);
}
r->max = max;
r->mode = mode;
crm_debug("Host %s supports a maximum of %d jobs and throttle mode %.4x. New job limit is %d",
from, max, mode, throttle_get_job_limit(from));
}
diff --git a/cts/cts-coverage.in b/cts/cts-coverage.in
index 5ebfb03830..0fdfe918fd 100644
--- a/cts/cts-coverage.in
+++ b/cts/cts-coverage.in
@@ -1,62 +1,62 @@
-#!/bin/bash
+#!@BASH_PATH@
start=$PWD
test_home=`dirname $0`
test_dir="@datadir@/@PACKAGE@/tests"
if [ "$test_home" != "$test_dir" ]; then
# Running against the source tree
GCOV_BASE=@abs_top_srcdir@
test_dir="@abs_top_srcdir@/cts"
cd @abs_top_srcdir@
grep with-gcov config.log
if [ $? = 0 ]; then
echo "Pacemaker was built with gcov support"
else
echo "Re-building with gcov support"
last=`grep --color=never "$.*configure" config.log | tail -n 1 | sed s:.*configure:./configure: | sed s:--no-create:--with-gcov:`
eval $last
fi
#sudo make core core-install
else
GCOV_BASE=@localstatedir@/lib/pacemaker/gcov/
mkdir -p $GCOV_BASE
export GCOV_PREFIX_STRIP=4
export GCOV_PREFIX=$GCOV_BASE
top=`find / -name crm_internal.h 2>/dev/null | grep debug | head -n 1`
if [ "x$top" = x ]; then
echo "Could not locate the pacemaker headers"
exit 1
fi
cd `dirname $top`
cd ..
echo "Creating the directory structure in $GCOV_BASE from $PWD"
# The .gcno files will already be there for sources,
# but we still need to create the include/ subtree
find . -type d -exec mkdir -p $GCOV_BASE/\{\} \;
echo "Now linking the source files into place"
find . -type f -name "*.c" -exec ln -s $PWD/\{\} $GCOV_BASE\{\} \;
find . -type f -name "*.h" -exec ln -s $PWD/\{\} $GCOV_BASE\{\} \;
find . -type f -name "*.debug" -exec ln -s $PWD/\{\} $GCOV_BASE\{\} \;
fi
cd $start
lcov -d $GCOV_BASE -z
# Run all active regression tests
$test_dir/cts-regression
lcov -d $GCOV_BASE -c -o pacemaker.info
rm -rf html
mkdir html
genhtml -o html pacemaker.info
diff --git a/cts/cts-pengine.in b/cts/cts-pengine.in
index 8a0810dfaa..4f283a45e0 100644
--- a/cts/cts-pengine.in
+++ b/cts/cts-pengine.in
@@ -1,1276 +1,1276 @@
-#!/bin/bash
+#!@BASH_PATH@
# Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
USAGE_TEXT="Usage: cts-pengine [<options>]
Options:
--help Display this text, then exit
-V, --verbose Display any differences from expected output
--run TEST Run only single specified test
--update Update expected results with actual results
-b, --binary PATH Specify path to crm_simulate
-i, --io-dir PATH Specify path to regression test data directory
-v, --valgrind Run all commands under valgrind
--valgrind-dhat Run all commands under valgrind with heap analyzer
--valgrind-skip-output If running under valgrind, don't display output
--testcmd-options Additional options for command under test"
SBINDIR="@sbindir@"
BUILDDIR="@abs_top_builddir@"
CRM_SCHEMA_DIRECTORY="@CRM_SCHEMA_DIRECTORY@"
test_home=$(dirname $(readlink -e $0))
io_dir="$test_home/pengine"
failed="$test_home/.regression.failed.diff"
test_binary=
testcmd_options=
single_test=
verbose=0
num_failed=0
num_tests=0
VALGRIND_CMD=""
VALGRIND_OPTS="-q
--gen-suppressions=all
--log-file=%q{valgrind_output}
--time-stamp=yes
--trace-children=no
--show-reachable=no
--leak-check=full
--num-callers=20
--suppressions=$test_home/valgrind-pcmk.suppressions"
VALGRIND_DHAT_OPTS="--tool=exp-dhat
--log-file=%q{valgrind_output}
--time-stamp=yes
--trace-children=no
--show-top-n=100
--num-callers=4"
diff_opts="--ignore-all-space --ignore-blank-lines -u -N"
# These constants must track crm_exit_t values
CRM_EX_OK=0
CRM_EX_ERROR=1
CRM_EX_NOT_INSTALLED=5
CRM_EX_USAGE=64
CRM_EX_NOINPUT=66
EXITCODE=$CRM_EX_OK
function info() {
printf "$*\n"
}
function error() {
printf " * ERROR: $*\n"
}
function failed() {
printf " * FAILED: $*\n"
}
function show_test() {
name=$1; shift
printf " Test %-25s $*\n" "$name:"
}
info "Test home is:\t$test_home"
create_mode="false"
while [ $# -gt 0 ] ; do
case "$1" in
-V|--verbose)
verbose=1
shift
;;
-v|--valgrind)
export G_SLICE=always-malloc
VALGRIND_CMD="valgrind $VALGRIND_OPTS"
shift
;;
--valgrind-dhat)
VALGRIND_CMD="valgrind $VALGRIND_DHAT_OPTS"
shift
;;
--valgrind-skip-output)
VALGRIND_SKIP_OUTPUT=1
shift
;;
--update)
create_mode="true"
shift
;;
--run)
single_test="$2"
shift 2
;;
-b|--binary)
test_binary="$2"
shift 2
;;
-i|--io-dir)
io_dir="$2"
shift 2
;;
--help)
echo "$USAGE_TEXT"
exit $CRM_EX_OK
;;
--testcmd-options)
testcmd_options=$2
shift 2
;;
*)
error "unknown option: $1"
exit $CRM_EX_USAGE
;;
esac
done
if [ -z "$PCMK_schema_directory" ]; then
if [ -d "$BUILDDIR/xml" ]; then
export PCMK_schema_directory="$BUILDDIR/xml"
elif [ -d "$CRM_SCHEMA_DIRECTORY" ]; then
export PCMK_schema_directory="$CRM_SCHEMA_DIRECTORY"
fi
fi
if [ -z "$test_binary" ]; then
if [ -x "$BUILDDIR/tools/crm_simulate" ]; then
test_binary="$BUILDDIR/tools/crm_simulate"
elif [ -x "$SBINDIR/crm_simulate" ]; then
test_binary="$SBINDIR/crm_simulate"
fi
fi
if [ ! -x "$test_binary" ]; then
error "Test binary $test_binary not found"
exit $CRM_EX_NOT_INSTALLED
fi
info "Test binary is:\t$test_binary"
if [ -n "$PCMK_schema_directory" ]; then
info "Schema home is:\t$PCMK_schema_directory"
fi
if [ "x$VALGRIND_CMD" != "x" ]; then
info "Activating memory testing with valgrind";
fi
info " "
test_cmd="$VALGRIND_CMD $test_binary $testcmd_options"
#echo $test_cmd
if [ `whoami` != root ]; then
declare -x CIB_shadow_dir=/tmp
fi
do_test() {
did_fail=0
expected_rc=0
num_tests=$(( $num_tests + 1 ))
base=$1; shift
name=$1; shift
input=$io_dir/${base}.xml
output=$io_dir/${base}.out
expected=$io_dir/${base}.exp
dot_png=$io_dir/${base}.png
dot_expected=$io_dir/${base}.dot
dot_output=$io_dir/${base}.pe.dot
scores=$io_dir/${base}.scores
score_output=$io_dir/${base}.scores.pe
stderr_expected=$io_dir/${base}.stderr
stderr_output=$io_dir/${base}.stderr.pe
summary=$io_dir/${base}.summary
summary_output=$io_dir/${base}.summary.pe
valgrind_output=$io_dir/${base}.valgrind
export valgrind_output
if [ "x$1" = "x--rc" ]; then
expected_rc=$2
shift; shift;
fi
show_test "$base" "$name"
if [ ! -f $input ]; then
error "No input";
did_fail=1
num_failed=$(( $num_failed + 1 ))
return $CRM_EX_NOINPUT;
fi
if [ "$create_mode" != "true" -a ! -f $expected ]; then
error "no stored output";
return $CRM_EX_NOINPUT;
fi
# ../admin/crm_verify -X $input
if [ ! -z "$single_test" ]; then
echo CIB_shadow_dir=$io_dir $test_cmd -x $input -D $dot_output -G $output -S $*
CIB_shadow_dir=$io_dir $test_cmd -x $input -D $dot_output -G $output -S $* 2>&1 | tee $summary_output
else
CIB_shadow_dir=$io_dir $test_cmd -x $input -S &> $summary_output
fi
CIB_shadow_dir=$io_dir $test_cmd -x $input -D $dot_output -G $output -SQ -s $* 2> $stderr_output > $score_output
rc=$?
if [ $rc -ne $expected_rc ]; then
failed "Test returned: $rc";
did_fail=1
echo "CIB_shadow_dir=$io_dir $test_cmd -x $input -D $dot_output -G $output -SQ -s $*"
fi
if [ -z "$VALGRIND_SKIP_OUTPUT" ]; then
if [ -s "${valgrind_output}" ]; then
error "Valgrind reported errors";
did_fail=1
cat ${valgrind_output}
fi
rm -f ${valgrind_output}
fi
if [ -s core ]; then
error "Core-file detected: core.${base}";
did_fail=1
rm -f $test_home/core.$base
mv core $test_home/core.$base
fi
if [ -e "$stderr_expected" ]; then
diff $diff_opts $stderr_expected $stderr_output >/dev/null
rc2=$?
if [ $rc2 -ne 0 ]; then
failed "stderr changed";
diff $diff_opts $stderr_expected $stderr_output 2>/dev/null >> $failed
echo "" >> $failed
did_fail=1
fi
elif [ -s "$stderr_output" ]; then
error "Output was written to stderr"
did_fail=1
cat $stderr_output
fi
rm -f $stderr_output
if [ ! -s $output ]; then
error "No graph produced";
did_fail=1
num_failed=$(( $num_failed + 1 ))
rm -f $output
return $CRM_EX_ERROR;
fi
if [ ! -s $dot_output ]; then
error "No dot-file summary produced";
did_fail=1
num_failed=$(( $num_failed + 1 ))
rm -f $output
return $CRM_EX_ERROR;
else
echo "digraph \"g\" {" > $dot_output.sort
LC_ALL=POSIX sort -u $dot_output | grep -v -e ^}$ -e digraph >> $dot_output.sort
echo "}" >> $dot_output.sort
mv -f $dot_output.sort $dot_output
fi
if [ ! -s $score_output ]; then
error "No allocation scores produced";
did_fail=1
num_failed=$(( $num_failed + 1 ))
rm $output
return $CRM_EX_ERROR;
else
LC_ALL=POSIX sort $score_output > $score_output.sorted
mv -f $score_output.sorted $score_output
fi
if [ "$create_mode" = "true" ]; then
cp "$output" "$expected"
cp "$dot_output" "$dot_expected"
cp "$score_output" "$scores"
cp "$summary_output" "$summary"
info " Updated expected outputs"
fi
diff $diff_opts $summary $summary_output >/dev/null
rc2=$?
if [ $rc2 -ne 0 ]; then
failed "summary changed";
diff $diff_opts $summary $summary_output 2>/dev/null >> $failed
echo "" >> $failed
did_fail=1
fi
diff $diff_opts $dot_expected $dot_output >/dev/null
rc=$?
if [ $rc -ne 0 ]; then
failed "dot-file summary changed";
diff $diff_opts $dot_expected $dot_output 2>/dev/null >> $failed
echo "" >> $failed
did_fail=1
else
rm -f $dot_output
fi
sed -i -e 's/crm_feature_set="[^"]*"//' -e 's/batch-limit="[0-9]*"//' $expected $output
diff $diff_opts $expected $output >/dev/null
rc2=$?
if [ $rc2 -ne 0 ]; then
failed "xml-file changed";
diff $diff_opts $expected $output 2>/dev/null >> $failed
echo "" >> $failed
did_fail=1
fi
diff $diff_opts $scores $score_output >/dev/null
rc=$?
if [ $rc -ne 0 ]; then
failed "scores-file changed";
diff $diff_opts $scores $score_output 2>/dev/null >> $failed
echo "" >> $failed
did_fail=1
fi
rm -f $output $score_output $summary_output
if [ $did_fail -eq 1 ]; then
num_failed=$(( $num_failed + 1 ))
return $CRM_EX_ERROR
fi
return $CRM_EX_OK
}
function test_results {
if [ $num_failed -ne 0 ]; then
if [ -s "$failed" ]; then
if [ $verbose -eq 1 ]; then
error "Results of $num_failed failed tests (out of $num_tests)...."
cat $failed
else
error "Results of $num_failed failed tests (out of $num_tests) are in $failed...."
error "Use $0 -V to display them automatically."
fi
else
error "$num_failed (of $num_tests) tests failed (no diff results)"
rm $failed
fi
EXITCODE=$CRM_EX_ERROR
fi
}
# zero out the error log
> $failed
if [ -n "$single_test" ]; then
do_test $single_test "Single shot" $*
TEST_RC=$?
cat $failed
exit $TEST_RC
fi
DO_VERSIONED_TESTS=0
info Performing the following tests from $io_dir
echo ""
do_test simple1 "Offline "
do_test simple2 "Start "
do_test simple3 "Start 2 "
do_test simple4 "Start Failed"
do_test simple6 "Stop Start "
do_test simple7 "Shutdown "
#do_test simple8 "Stonith "
#do_test simple9 "Lower version"
#do_test simple10 "Higher version"
do_test simple11 "Priority (ne)"
do_test simple12 "Priority (eq)"
do_test simple8 "Stickiness"
echo ""
do_test group1 "Group "
do_test group2 "Group + Native "
do_test group3 "Group + Group "
do_test group4 "Group + Native (nothing)"
do_test group5 "Group + Native (move) "
do_test group6 "Group + Group (move) "
do_test group7 "Group colocation"
do_test group13 "Group colocation (cant run)"
do_test group8 "Group anti-colocation"
do_test group9 "Group recovery"
do_test group10 "Group partial recovery"
do_test group11 "Group target_role"
do_test group14 "Group stop (graph terminated)"
do_test group15 "-ve group colocation"
do_test bug-1573 "Partial stop of a group with two children"
do_test bug-1718 "Mandatory group ordering - Stop group_FUN"
do_test bug-lf-2613 "Move group on failure"
do_test bug-lf-2619 "Move group on clone failure"
do_test group-fail "Ensure stop order is preserved for partially active groups"
do_test group-unmanaged "No need to restart r115 because r114 is unmanaged"
do_test group-unmanaged-stopped "Make sure r115 is stopped when r114 fails"
do_test group-dependents "Account for the location preferences of things colocated with a group"
echo ""
do_test rsc_dep1 "Must not "
do_test rsc_dep3 "Must "
do_test rsc_dep5 "Must not 3 "
do_test rsc_dep7 "Must 3 "
do_test rsc_dep10 "Must (but cant)"
do_test rsc_dep2 "Must (running) "
do_test rsc_dep8 "Must (running : alt) "
do_test rsc_dep4 "Must (running + move)"
do_test asymmetric "Asymmetric - require explicit location constraints"
echo ""
do_test orphan-0 "Orphan ignore"
do_test orphan-1 "Orphan stop"
do_test orphan-2 "Orphan stop, remove failcount"
echo ""
do_test params-0 "Params: No change"
do_test params-1 "Params: Changed"
do_test params-2 "Params: Resource definition"
do_test params-4 "Params: Reload"
do_test params-5 "Params: Restart based on probe digest"
do_test novell-251689 "Resource definition change + target_role=stopped"
do_test bug-lf-2106 "Restart all anonymous clone instances after config change"
do_test params-6 "Params: Detect reload in previously migrated resource"
do_test nvpair-id-ref "Support id-ref in nvpair with optional name"
do_test not-reschedule-unneeded-monitor "Do not reschedule unneeded monitors while resource definitions have changed"
do_test reload-becomes-restart "Cancel reload if restart becomes required"
echo ""
do_test target-0 "Target Role : baseline"
do_test target-1 "Target Role : master"
do_test target-2 "Target Role : invalid"
echo ""
do_test base-score "Set a node's default score for all nodes"
echo ""
do_test date-1 "Dates" -t "2005-020"
do_test date-2 "Date Spec - Pass" -t "2005-020T12:30"
do_test date-3 "Date Spec - Fail" -t "2005-020T11:30"
do_test origin "Timing of recurring operations" -t "2014-05-07 00:28:00"
do_test probe-0 "Probe (anon clone)"
do_test probe-1 "Pending Probe"
do_test probe-2 "Correctly re-probe cloned groups"
do_test probe-3 "Probe (pending node)"
do_test probe-4 "Probe (pending node + stopped resource)"
do_test standby "Standby"
do_test comments "Comments"
echo ""
do_test one-or-more-0 "Everything starts"
do_test one-or-more-1 "Nothing starts because of A"
do_test one-or-more-2 "D can start because of C"
do_test one-or-more-3 "D cannot start because of B and C"
do_test one-or-more-4 "D cannot start because of target-role"
do_test one-or-more-5 "Start A and F even though C and D are stopped"
do_test one-or-more-6 "Leave A running even though B is stopped"
do_test one-or-more-7 "Leave A running even though C is stopped"
do_test bug-5140-require-all-false "Allow basegrp:0 to stop"
do_test clone-require-all-1 "clone B starts node 3 and 4"
do_test clone-require-all-2 "clone B remains stopped everywhere"
do_test clone-require-all-3 "clone B stops everywhere because A stops everywhere"
do_test clone-require-all-4 "clone B remains on node 3 and 4 with only one instance of A remaining."
do_test clone-require-all-5 "clone B starts on node 1 3 and 4"
do_test clone-require-all-6 "clone B remains active after shutting down instances of A"
do_test clone-require-all-7 "clone A and B both start at the same time. all instances of A start before B."
do_test clone-require-all-no-interleave-1 "C starts everywhere after A and B"
do_test clone-require-all-no-interleave-2 "C starts on nodes 1, 2, and 4 with only one active instance of B"
do_test clone-require-all-no-interleave-3 "C remains active when instance of B is stopped on one node and started on another."
do_test one-or-more-unrunnable-instances "Avoid dependencies on instances that won't ever be started"
echo ""
do_test order1 "Order start 1 "
do_test order2 "Order start 2 "
do_test order3 "Order stop "
do_test order4 "Order (multiple) "
do_test order5 "Order (move) "
do_test order6 "Order (move w/ restart) "
do_test order7 "Order (mandatory) "
do_test order-optional "Order (score=0) "
do_test order-required "Order (score=INFINITY) "
do_test bug-lf-2171 "Prevent group start when clone is stopped"
do_test order-clone "Clone ordering should be able to prevent startup of dependent clones"
do_test order-sets "Ordering for resource sets"
do_test order-serialize "Serialize resources without inhibiting migration"
do_test order-serialize-set "Serialize a set of resources without inhibiting migration"
do_test clone-order-primitive "Order clone start after a primitive"
do_test clone-order-16instances "Verify ordering of 16 cloned resources"
do_test order-optional-keyword "Order (optional keyword)"
do_test order-mandatory "Order (mandatory keyword)"
do_test bug-lf-2493 "Don't imply colocation requirements when applying ordering constraints with clones"
do_test ordered-set-basic-startup "Constraint set with default order settings."
do_test ordered-set-natural "Allow natural set ordering"
do_test order-wrong-kind "Order (error)"
echo ""
do_test coloc-loop "Colocation - loop"
do_test coloc-many-one "Colocation - many-to-one"
do_test coloc-list "Colocation - many-to-one with list"
do_test coloc-group "Colocation - groups"
do_test coloc-slave-anti "Anti-colocation with slave shouldn't prevent master colocation"
do_test coloc-attr "Colocation based on node attributes"
do_test coloc-negative-group "Negative colocation with a group"
do_test coloc-intra-set "Intra-set colocation"
do_test bug-lf-2435 "Colocation sets with a negative score"
do_test coloc-clone-stays-active "Ensure clones don't get stopped/demoted because a dependent must stop"
do_test coloc_fp_logic "Verify floating point calculations in colocation are working"
do_test colo_master_w_native "cl#5070 - Verify promotion order is affected when colocating master to native rsc."
do_test colo_slave_w_native "cl#5070 - Verify promotion order is affected when colocating slave to native rsc."
do_test anti-colocation-order "cl#5187 - Prevent resources in an anti-colocation from even temporarily running on a same node"
do_test anti-colocation-master "Organize order of actions for master resources in anti-colocations"
do_test anti-colocation-slave "Organize order of actions for slave resources in anti-colocations"
do_test enforce-colo1 "Always enforce B with A INFINITY."
do_test complex_enforce_colo "Always enforce B with A INFINITY. (make sure heat-engine stops)"
echo ""
do_test rsc-sets-seq-true "Resource Sets - sequential=false"
do_test rsc-sets-seq-false "Resource Sets - sequential=true"
do_test rsc-sets-clone "Resource Sets - Clone"
do_test rsc-sets-master "Resource Sets - Master"
do_test rsc-sets-clone-1 "Resource Sets - Clone (lf#2404)"
#echo ""
#do_test agent1 "version: lt (empty)"
#do_test agent2 "version: eq "
#do_test agent3 "version: gt "
echo ""
do_test attrs1 "string: eq (and) "
do_test attrs2 "string: lt / gt (and)"
do_test attrs3 "string: ne (or) "
do_test attrs4 "string: exists "
do_test attrs5 "string: not_exists "
do_test attrs6 "is_dc: true "
do_test attrs7 "is_dc: false "
do_test attrs8 "score_attribute "
do_test per-node-attrs "Per node resource parameters"
echo ""
do_test mon-rsc-1 "Schedule Monitor - start"
do_test mon-rsc-2 "Schedule Monitor - move "
do_test mon-rsc-3 "Schedule Monitor - pending start "
do_test mon-rsc-4 "Schedule Monitor - move/pending start"
echo ""
do_test rec-rsc-0 "Resource Recover - no start "
do_test rec-rsc-1 "Resource Recover - start "
do_test rec-rsc-2 "Resource Recover - monitor "
do_test rec-rsc-3 "Resource Recover - stop - ignore"
do_test rec-rsc-4 "Resource Recover - stop - block "
do_test rec-rsc-5 "Resource Recover - stop - fence "
do_test rec-rsc-6 "Resource Recover - multiple - restart"
do_test rec-rsc-7 "Resource Recover - multiple - stop "
do_test rec-rsc-8 "Resource Recover - multiple - block "
do_test rec-rsc-9 "Resource Recover - group/group"
do_test monitor-recovery "on-fail=block + resource recovery detected by recurring monitor"
do_test stop-failure-no-quorum "Stop failure without quorum"
do_test stop-failure-no-fencing "Stop failure without fencing available"
do_test stop-failure-with-fencing "Stop failure with fencing available"
do_test multiple-active-block-group "Support of multiple-active=block for resource groups"
do_test multiple-monitor-one-failed "Consider resource failed if any of the configured monitor operations failed"
echo ""
do_test quorum-1 "No quorum - ignore"
do_test quorum-2 "No quorum - freeze"
do_test quorum-3 "No quorum - stop "
do_test quorum-4 "No quorum - start anyway"
do_test quorum-5 "No quorum - start anyway (group)"
do_test quorum-6 "No quorum - start anyway (clone)"
do_test bug-cl-5212 "No promotion with no-quorum-policy=freeze"
do_test suicide-needed-inquorate "no-quorum-policy=suicide: suicide necessary"
do_test suicide-not-needed-initial-quorum "no-quorum-policy=suicide: suicide not necessary at initial quorum"
do_test suicide-not-needed-never-quorate "no-quorum-policy=suicide: suicide not necessary if never quorate"
do_test suicide-not-needed-quorate "no-quorum-policy=suicide: suicide necessary if quorate"
echo ""
do_test rec-node-1 "Node Recover - Startup - no fence"
do_test rec-node-2 "Node Recover - Startup - fence "
do_test rec-node-3 "Node Recover - HA down - no fence"
do_test rec-node-4 "Node Recover - HA down - fence "
do_test rec-node-5 "Node Recover - CRM down - no fence"
do_test rec-node-6 "Node Recover - CRM down - fence "
do_test rec-node-7 "Node Recover - no quorum - ignore "
do_test rec-node-8 "Node Recover - no quorum - freeze "
do_test rec-node-9 "Node Recover - no quorum - stop "
do_test rec-node-10 "Node Recover - no quorum - stop w/fence"
do_test rec-node-11 "Node Recover - CRM down w/ group - fence "
do_test rec-node-12 "Node Recover - nothing active - fence "
do_test rec-node-13 "Node Recover - failed resource + shutdown - fence "
do_test rec-node-15 "Node Recover - unknown lrm section"
do_test rec-node-14 "Serialize all stonith's"
echo ""
do_test multi1 "Multiple Active (stop/start)"
echo ""
do_test migrate-begin "Normal migration"
do_test migrate-success "Completed migration"
do_test migrate-partial-1 "Completed migration, missing stop on source"
do_test migrate-partial-2 "Successful migrate_to only"
do_test migrate-partial-3 "Successful migrate_to only, target down"
do_test migrate-partial-4 "Migrate from the correct host after migrate_to+migrate_from"
do_test bug-5186-partial-migrate "Handle partial migration when src node loses membership"
do_test migrate-fail-2 "Failed migrate_from"
do_test migrate-fail-3 "Failed migrate_from + stop on source"
do_test migrate-fail-4 "Failed migrate_from + stop on target - ideally we wouldn't need to re-stop on target"
do_test migrate-fail-5 "Failed migrate_from + stop on source and target"
do_test migrate-fail-6 "Failed migrate_to"
do_test migrate-fail-7 "Failed migrate_to + stop on source"
do_test migrate-fail-8 "Failed migrate_to + stop on target - ideally we wouldn't need to re-stop on target"
do_test migrate-fail-9 "Failed migrate_to + stop on source and target"
do_test migrate-stop "Migration in a stopping stack"
do_test migrate-start "Migration in a starting stack"
do_test migrate-stop_start "Migration in a restarting stack"
do_test migrate-stop-complex "Migration in a complex stopping stack"
do_test migrate-start-complex "Migration in a complex starting stack"
do_test migrate-stop-start-complex "Migration in a complex moving stack"
do_test migrate-shutdown "Order the post-migration 'stop' before node shutdown"
do_test migrate-1 "Migrate (migrate)"
do_test migrate-2 "Migrate (stable)"
do_test migrate-3 "Migrate (failed migrate_to)"
do_test migrate-4 "Migrate (failed migrate_from)"
do_test novell-252693 "Migration in a stopping stack"
do_test novell-252693-2 "Migration in a starting stack"
do_test novell-252693-3 "Non-Migration in a starting and stopping stack"
do_test bug-1820 "Migration in a group"
do_test bug-1820-1 "Non-migration in a group"
do_test migrate-5 "Primitive migration with a clone"
do_test migrate-fencing "Migration after Fencing"
do_test migrate-both-vms "Migrate two VMs that have no colocation"
do_test migration-behind-migrating-remote "Migrate resource behind migrating remote connection"
do_test 1-a-then-bm-move-b "Advanced migrate logic. A then B. migrate B."
do_test 2-am-then-b-move-a "Advanced migrate logic, A then B, migrate A without stopping B"
do_test 3-am-then-bm-both-migrate "Advanced migrate logic. A then B. migrate both"
do_test 4-am-then-bm-b-not-migratable "Advanced migrate logic, A then B, B not migratable"
do_test 5-am-then-bm-a-not-migratable "Advanced migrate logic. A then B. move both, a not migratable"
do_test 6-migrate-group "Advanced migrate logic, migrate a group"
do_test 7-migrate-group-one-unmigratable "Advanced migrate logic, migrate group mixed with allow-migrate true/false"
do_test 8-am-then-bm-a-migrating-b-stopping "Advanced migrate logic, A then B, A migrating, B stopping"
do_test 9-am-then-bm-b-migrating-a-stopping "Advanced migrate logic, A then B, B migrate, A stopping"
do_test 10-a-then-bm-b-move-a-clone "Advanced migrate logic, A clone then B, migrate B while stopping A"
do_test 11-a-then-bm-b-move-a-clone-starting "Advanced migrate logic, A clone then B, B moving while A is start/stopping"
do_test a-promote-then-b-migrate "A promote then B start. migrate B"
do_test a-demote-then-b-migrate "A demote then B stop. migrate B"
if [ $DO_VERSIONED_TESTS -eq 1 ]; then
do_test migrate-versioned "Disable migration for versioned resources"
fi
#echo ""
#do_test complex1 "Complex "
do_test bug-lf-2422 "Dependency on partially active group - stop ocfs:*"
echo ""
do_test clone-anon-probe-1 "Probe the correct (anonymous) clone instance for each node"
do_test clone-anon-probe-2 "Avoid needless re-probing of anonymous clones"
do_test clone-anon-failcount "Merge failcounts for anonymous clones"
do_test inc0 "Incarnation start"
do_test inc1 "Incarnation start order"
do_test inc2 "Incarnation silent restart, stop, move"
do_test inc3 "Inter-incarnation ordering, silent restart, stop, move"
do_test inc4 "Inter-incarnation ordering, silent restart, stop, move (ordered)"
do_test inc5 "Inter-incarnation ordering, silent restart, stop, move (restart 1)"
do_test inc6 "Inter-incarnation ordering, silent restart, stop, move (restart 2)"
do_test inc7 "Clone colocation"
do_test inc8 "Clone anti-colocation"
do_test inc9 "Non-unique clone"
do_test inc10 "Non-unique clone (stop)"
do_test inc11 "Primitive colocation with clones"
do_test inc12 "Clone shutdown"
do_test cloned-group "Make sure only the correct number of cloned groups are started"
do_test cloned-group-stop "Ensure stopping qpidd also stops glance and cinder"
do_test clone-no-shuffle "Don't prioritize allocation of instances that must be moved"
do_test clone-max-zero "Orphan processing with clone-max=0"
do_test clone-anon-dup "Bug LF#2087 - Correctly parse the state of anonymous clones that are active more than once per node"
do_test bug-lf-2160 "Don't shuffle clones due to colocation"
do_test bug-lf-2213 "clone-node-max enforcement for cloned groups"
do_test bug-lf-2153 "Clone ordering constraints"
do_test bug-lf-2361 "Ensure clones observe mandatory ordering constraints if the LHS is unrunnable"
do_test bug-lf-2317 "Avoid needless restart of primitive depending on a clone"
do_test clone-colocate-instance-1 "Colocation with a specific clone instance (negative example)"
do_test clone-colocate-instance-2 "Colocation with a specific clone instance"
do_test clone-order-instance "Ordering with specific clone instances"
do_test bug-lf-2453 "Enforce mandatory clone ordering without colocation"
do_test bug-lf-2508 "Correctly reconstruct the status of anonymous cloned groups"
do_test bug-lf-2544 "Balanced clone placement"
do_test bug-lf-2445 "Redistribute clones with node-max > 1 and stickiness = 0"
do_test bug-lf-2574 "Avoid clone shuffle"
do_test bug-lf-2581 "Avoid group restart due to unrelated clone (re)start"
do_test bug-cl-5168 "Don't shuffle clones"
do_test bug-cl-5170 "Prevent clone from starting with on-fail=block"
do_test clone-fail-block-colocation "Move colocated group when failed clone has on-fail=block"
do_test clone-interleave-1 "Clone-3 cannot start on pcmk-1 due to interleaved ordering (no colocation)"
do_test clone-interleave-2 "Clone-3 must stop on pcmk-1 due to interleaved ordering (no colocation)"
do_test clone-interleave-3 "Clone-3 must be recovered on pcmk-1 due to interleaved ordering (no colocation)"
do_test rebalance-unique-clones "Rebalance unique clone instances with no stickiness"
echo ""
do_test cloned_start_one "order first clone then clone... first clone_min=2"
do_test cloned_start_two "order first clone then clone... first clone_min=2"
do_test cloned_stop_one "order first clone then clone... first clone_min=2"
do_test cloned_stop_two "order first clone then clone... first clone_min=2"
do_test clone_min_interleave_start_one "order first clone then clone... first clone_min=2 and then has interleave=true"
do_test clone_min_interleave_start_two "order first clone then clone... first clone_min=2 and then has interleave=true"
do_test clone_min_interleave_stop_one "order first clone then clone... first clone_min=2 and then has interleave=true"
do_test clone_min_interleave_stop_two "order first clone then clone... first clone_min=2 and then has interleave=true"
do_test clone_min_start_one "order first clone then primitive... first clone_min=2"
do_test clone_min_start_two "order first clone then primitive... first clone_min=2"
do_test clone_min_stop_all "order first clone then primitive... first clone_min=2"
do_test clone_min_stop_one "order first clone then primitive... first clone_min=2"
do_test clone_min_stop_two "order first clone then primitive... first clone_min=2"
echo ""
do_test unfence-startup "Clean unfencing"
do_test unfence-definition "Unfencing when the agent changes"
do_test unfence-parameters "Unfencing when the agent parameters changes"
do_test unfence-device "Unfencing when a cluster has only fence devices"
echo ""
do_test master-0 "Stopped -> Slave"
do_test master-1 "Stopped -> Promote"
do_test master-2 "Stopped -> Promote : notify"
do_test master-3 "Stopped -> Promote : master location"
do_test master-4 "Started -> Promote : master location"
do_test master-5 "Promoted -> Promoted"
do_test master-6 "Promoted -> Promoted (2)"
do_test master-7 "Promoted -> Fenced"
do_test master-8 "Promoted -> Fenced -> Moved"
do_test master-9 "Stopped + Promotable + No quorum"
do_test master-10 "Stopped -> Promotable : notify with monitor"
do_test master-11 "Stopped -> Promote : colocation"
do_test novell-239082 "Demote/Promote ordering"
do_test novell-239087 "Stable master placement"
do_test master-12 "Promotion based solely on rsc_location constraints"
do_test master-13 "Include preferences of colocated resources when placing master"
do_test master-demote "Ordering when actions depends on demoting a slave resource"
do_test master-ordering "Prevent resources from starting that need a master"
do_test bug-1765 "Master-Master Colocation (dont stop the slaves)"
do_test master-group "Promotion of cloned groups"
do_test bug-lf-1852 "Don't shuffle master/slave instances unnecessarily"
do_test master-failed-demote "Don't retry failed demote actions"
do_test master-failed-demote-2 "Don't retry failed demote actions (notify=false)"
do_test master-depend "Ensure resources that depend on the master don't get allocated until the master does"
do_test master-reattach "Re-attach to a running master"
do_test master-allow-start "Don't include master score if it would prevent allocation"
do_test master-colocation "Allow master instances placemaker to be influenced by colocation constraints"
do_test master-pseudo "Make sure promote/demote pseudo actions are created correctly"
do_test master-role "Prevent target-role from promoting more than master-max instances"
do_test bug-lf-2358 "Master-Master anti-colocation"
do_test master-promotion-constraint "Mandatory master colocation constraints"
do_test unmanaged-master "Ensure role is preserved for unmanaged resources"
do_test master-unmanaged-monitor "Start the correct monitor operation for unmanaged masters"
do_test master-demote-2 "Demote does not clear past failure"
do_test master-move "Move master based on failure of colocated group"
do_test master-probed-score "Observe the promotion score of probed resources"
do_test colocation_constraint_stops_master "cl#5054 - Ensure master is demoted when stopped by colocation constraint"
do_test colocation_constraint_stops_slave "cl#5054 - Ensure slave is not demoted when stopped by colocation constraint"
do_test order_constraint_stops_master "cl#5054 - Ensure master is demoted when stopped by order constraint"
do_test order_constraint_stops_slave "cl#5054 - Ensure slave is not demoted when stopped by order constraint"
do_test master_monitor_restart "cl#5072 - Ensure master monitor operation will start after promotion."
do_test bug-rh-880249 "Handle replacement of an m/s resource with a primitive"
do_test bug-5143-ms-shuffle "Prevent master shuffling due to promotion score"
do_test master-demote-block "Block promotion if demote fails with on-fail=block"
do_test master-dependent-ban "Don't stop instances from being active because a dependent is banned from that host"
do_test master-stop "Stop instances due to location constraint with role=Started"
do_test master-partially-demoted-group "Allow partially demoted group to finish demoting"
do_test bug-cl-5213 "Ensure role colocation with -INFINITY is enforced"
do_test bug-cl-5219 "Allow unrelated resources with a common colocation target to remain promoted"
do_test master-asymmetrical-order "Fix the behaviors of multi-state resources with asymmetrical ordering"
do_test master-notify "Master promotion with notifies"
do_test master-score-startup "Use permanent master scores without LRM history"
do_test failed-demote-recovery "Recover resource in slave role after demote fails"
do_test failed-demote-recovery-master "Recover resource in master role after demote fails"
echo ""
do_test history-1 "Correctly parse stateful-1 resource state"
echo ""
do_test managed-0 "Managed (reference)"
do_test managed-1 "Not managed - down "
do_test managed-2 "Not managed - up "
do_test bug-5028 "Shutdown should block if anything depends on an unmanaged resource"
do_test bug-5028-detach "Ensure detach still works"
do_test bug-5028-bottom "Ensure shutdown still blocks if the blocked resource is at the bottom of the stack"
do_test unmanaged-stop-1 "cl#5155 - Block the stop of resources if any depending resource is unmanaged "
do_test unmanaged-stop-2 "cl#5155 - Block the stop of resources if the first resource in a mandatory stop order is unmanaged "
do_test unmanaged-stop-3 "cl#5155 - Block the stop of resources if any depending resource in a group is unmanaged "
do_test unmanaged-stop-4 "cl#5155 - Block the stop of resources if any depending resource in the middle of a group is unmanaged "
do_test unmanaged-block-restart "Block restart of resources if any dependent resource in a group is unmanaged"
echo ""
do_test interleave-0 "Interleave (reference)"
do_test interleave-1 "coloc - not interleaved"
do_test interleave-2 "coloc - interleaved "
do_test interleave-3 "coloc - interleaved (2)"
do_test interleave-pseudo-stop "Interleaved clone during stonith"
do_test interleave-stop "Interleaved clone during stop"
do_test interleave-restart "Interleaved clone during dependency restart"
echo ""
do_test notify-0 "Notify reference"
do_test notify-1 "Notify simple"
do_test notify-2 "Notify simple, confirm"
do_test notify-3 "Notify move, confirm"
do_test novell-239079 "Notification priority"
#do_test notify-2 "Notify - 764"
do_test notifs-for-unrunnable "Don't schedule notifications for an unrunnable action"
echo ""
do_test 594 "OSDL #594 - Unrunnable actions scheduled in transition"
do_test 662 "OSDL #662 - Two resources start on one node when incarnation_node_max = 1"
do_test 696 "OSDL #696 - CRM starts stonith RA without monitor"
do_test 726 "OSDL #726 - Attempting to schedule rsc_posic041_monitor_5000 _after_ a stop"
do_test 735 "OSDL #735 - Correctly detect that rsc_hadev1 is stopped on hadev3"
do_test 764 "OSDL #764 - Missing monitor op for DoFencing:child_DoFencing:1"
do_test 797 "OSDL #797 - Assert triggered: task_id_i > max_call_id"
do_test 829 "OSDL #829"
do_test 994 "OSDL #994 - Stopping the last resource in a resource group causes the entire group to be restarted"
do_test 994-2 "OSDL #994 - with a dependent resource"
do_test 1360 "OSDL #1360 - Clone stickiness"
do_test 1484 "OSDL #1484 - on_fail=stop"
do_test 1494 "OSDL #1494 - Clone stability"
do_test unrunnable-1 "Unrunnable"
do_test unrunnable-2 "Unrunnable 2"
do_test stonith-0 "Stonith loop - 1"
do_test stonith-1 "Stonith loop - 2"
do_test stonith-2 "Stonith loop - 3"
do_test stonith-3 "Stonith startup"
do_test stonith-4 "Stonith node state"
do_test bug-1572-1 "Recovery of groups depending on master/slave"
do_test bug-1572-2 "Recovery of groups depending on master/slave when the master is never re-promoted"
do_test bug-1685 "Depends-on-master ordering"
do_test bug-1822 "Don't promote partially active groups"
do_test bug-pm-11 "New resource added to a m/s group"
do_test bug-pm-12 "Recover only the failed portion of a cloned group"
do_test bug-n-387749 "Don't shuffle clone instances"
do_test bug-n-385265 "Don't ignore the failure stickiness of group children - resource_idvscommon should stay stopped"
do_test bug-n-385265-2 "Ensure groups are migrated instead of remaining partially active on the current node"
do_test bug-lf-1920 "Correctly handle probes that find active resources"
do_test bnc-515172 "Location constraint with multiple expressions"
do_test colocate-primitive-with-clone "Optional colocation with a clone"
do_test use-after-free-merge "Use-after-free in native_merge_weights"
do_test bug-lf-2551 "STONITH ordering for stop"
do_test bug-lf-2606 "Stonith implies demote"
do_test bug-lf-2474 "Ensure resource op timeout takes precedence over op_defaults"
do_test bug-suse-707150 "Prevent vm-01 from starting due to colocation/ordering"
do_test bug-5014-A-start-B-start "Verify when A starts B starts using symmetrical=false"
do_test bug-5014-A-stop-B-started "Verify when A stops B does not stop if it has already started using symmetric=false"
do_test bug-5014-A-stopped-B-stopped "Verify when A is stopped and B has not started, B does not start before A using symmetric=false"
do_test bug-5014-CthenAthenB-C-stopped "Verify when C then A is symmetrical=true, A then B is symmetric=false, and C is stopped that nothing starts."
do_test bug-5014-CLONE-A-start-B-start "Verify when A starts B starts using clone resources with symmetric=false"
do_test bug-5014-CLONE-A-stop-B-started "Verify when A stops B does not stop if it has already started using clone resources with symmetric=false."
do_test bug-5014-GROUP-A-start-B-start "Verify when A starts B starts when using group resources with symmetric=false."
do_test bug-5014-GROUP-A-stopped-B-started "Verify when A stops B does not stop if it has already started using group resources with symmetric=false."
do_test bug-5014-GROUP-A-stopped-B-stopped "Verify when A is stopped and B has not started, B does not start before A using group resources with symmetric=false."
do_test bug-5014-ordered-set-symmetrical-false "Verify ordered sets work with symmetrical=false"
do_test bug-5014-ordered-set-symmetrical-true "Verify ordered sets work with symmetrical=true"
do_test bug-5007-masterslave_colocation "Verify use of colocation scores other than INFINITY and -INFINITY work on multi-state resources."
do_test bug-5038 "Prevent restart of anonymous clones when clone-max decreases"
do_test bug-5025-1 "Automatically clean up failcount after resource config change with reload"
do_test bug-5025-2 "Make sure clear failcount action isn't set when config does not change."
do_test bug-5025-3 "Automatically clean up failcount after resource config change with restart"
do_test bug-5025-4 "Clear failcount when last failure is a start op and rsc attributes changed."
do_test failcount "Ensure failcounts are correctly expired"
do_test failcount-block "Ensure failcounts are not expired when on-fail=block is present"
do_test per-op-failcount "Ensure per-operation failcount is handled and not passed to fence agent"
do_test on-fail-ignore "Ensure on-fail=ignore works even beyond migration-threshold"
do_test monitor-onfail-restart "bug-5058 - Monitor failure with on-fail set to restart"
do_test monitor-onfail-stop "bug-5058 - Monitor failure wiht on-fail set to stop"
do_test bug-5059 "No need to restart p_stateful1:*"
do_test bug-5069-op-enabled "Test on-fail=ignore with failure when monitor is enabled."
do_test bug-5069-op-disabled "Test on-fail-ignore with failure when monitor is disabled."
do_test obsolete-lrm-resource "cl#5115 - Do not use obsolete lrm_resource sections"
do_test expire-non-blocked-failure "Ignore failure-timeout only if the failed operation has on-fail=block"
do_test asymmetrical-order-move "Respect asymmetrical ordering when trying to move resources"
do_test start-then-stop-with-unfence "Avoid graph loop with start-then-stop constraint plus unfencing"
do_test ignore_stonith_rsc_order1 "cl#5056- Ignore order constraint between stonith and non-stonith rsc."
do_test ignore_stonith_rsc_order2 "cl#5056- Ignore order constraint with group rsc containing mixed stonith and non-stonith."
do_test ignore_stonith_rsc_order3 "cl#5056- Ignore order constraint, stonith clone and mixed group"
do_test ignore_stonith_rsc_order4 "cl#5056- Ignore order constraint, stonith clone and clone with nested mixed group"
do_test honor_stonith_rsc_order1 "cl#5056- Honor order constraint, stonith clone and pure stonith group(single rsc)."
do_test honor_stonith_rsc_order2 "cl#5056- Honor order constraint, stonith clone and pure stonith group(multiple rsc)"
do_test honor_stonith_rsc_order3 "cl#5056- Honor order constraint, stonith clones with nested pure stonith group."
do_test honor_stonith_rsc_order4 "cl#5056- Honor order constraint, between two native stonith rscs."
do_test probe-timeout "cl#5099 - Default probe timeout"
do_test concurrent-fencing "Allow performing fencing operations in parallel"
echo ""
do_test systemhealth1 "System Health () #1"
do_test systemhealth2 "System Health () #2"
do_test systemhealth3 "System Health () #3"
do_test systemhealthn1 "System Health (None) #1"
do_test systemhealthn2 "System Health (None) #2"
do_test systemhealthn3 "System Health (None) #3"
do_test systemhealthm1 "System Health (Migrate On Red) #1"
do_test systemhealthm2 "System Health (Migrate On Red) #2"
do_test systemhealthm3 "System Health (Migrate On Red) #3"
do_test systemhealtho1 "System Health (Only Green) #1"
do_test systemhealtho2 "System Health (Only Green) #2"
do_test systemhealtho3 "System Health (Only Green) #3"
do_test systemhealthp1 "System Health (Progessive) #1"
do_test systemhealthp2 "System Health (Progessive) #2"
do_test systemhealthp3 "System Health (Progessive) #3"
echo ""
do_test utilization "Placement Strategy - utilization"
do_test minimal "Placement Strategy - minimal"
do_test balanced "Placement Strategy - balanced"
echo ""
do_test placement-stickiness "Optimized Placement Strategy - stickiness"
do_test placement-priority "Optimized Placement Strategy - priority"
do_test placement-location "Optimized Placement Strategy - location"
do_test placement-capacity "Optimized Placement Strategy - capacity"
echo ""
do_test utilization-order1 "Utilization Order - Simple"
do_test utilization-order2 "Utilization Order - Complex"
do_test utilization-order3 "Utilization Order - Migrate"
do_test utilization-order4 "Utilization Order - Live Migration (bnc#695440)"
do_test utilization-shuffle "Don't displace prmExPostgreSQLDB2 on act2, Start prmExPostgreSQLDB1 on act3"
do_test load-stopped-loop "Avoid transition loop due to load_stopped (cl#5044)"
do_test load-stopped-loop-2 "cl#5235 - Prevent graph loops that can be introduced by load_stopped -> migrate_to ordering"
echo ""
do_test colocated-utilization-primitive-1 "Colocated Utilization - Primitive"
do_test colocated-utilization-primitive-2 "Colocated Utilization - Choose the most capable node"
do_test colocated-utilization-group "Colocated Utilization - Group"
do_test colocated-utilization-clone "Colocated Utilization - Clone"
do_test utilization-check-allowed-nodes "Only check the capacities of the nodes that can run the resource"
echo ""
do_test reprobe-target_rc "Ensure correct target_rc for reprobe of inactive resources"
do_test node-maintenance-1 "cl#5128 - Node maintenance"
do_test node-maintenance-2 "cl#5128 - Node maintenance (coming out of maintenance mode)"
do_test shutdown-maintenance-node "Do not fence a maintenance node if it shuts down cleanly"
do_test rsc-maintenance "Per-resource maintenance"
echo ""
do_test not-installed-agent "The resource agent is missing"
do_test not-installed-tools "Something the resource agent needs is missing"
echo ""
do_test stopped-monitor-00 "Stopped Monitor - initial start"
do_test stopped-monitor-01 "Stopped Monitor - failed started"
do_test stopped-monitor-02 "Stopped Monitor - started multi-up"
do_test stopped-monitor-03 "Stopped Monitor - stop started"
do_test stopped-monitor-04 "Stopped Monitor - failed stop"
do_test stopped-monitor-05 "Stopped Monitor - start unmanaged"
do_test stopped-monitor-06 "Stopped Monitor - unmanaged multi-up"
do_test stopped-monitor-07 "Stopped Monitor - start unmanaged multi-up"
do_test stopped-monitor-08 "Stopped Monitor - migrate"
do_test stopped-monitor-09 "Stopped Monitor - unmanage started"
do_test stopped-monitor-10 "Stopped Monitor - unmanaged started multi-up"
do_test stopped-monitor-11 "Stopped Monitor - stop unmanaged started"
do_test stopped-monitor-12 "Stopped Monitor - unmanaged started multi-up (targer-role="Stopped")"
do_test stopped-monitor-20 "Stopped Monitor - initial stop"
do_test stopped-monitor-21 "Stopped Monitor - stopped single-up"
do_test stopped-monitor-22 "Stopped Monitor - stopped multi-up"
do_test stopped-monitor-23 "Stopped Monitor - start stopped"
do_test stopped-monitor-24 "Stopped Monitor - unmanage stopped"
do_test stopped-monitor-25 "Stopped Monitor - unmanaged stopped multi-up"
do_test stopped-monitor-26 "Stopped Monitor - start unmanaged stopped"
do_test stopped-monitor-27 "Stopped Monitor - unmanaged stopped multi-up (target-role="Started")"
do_test stopped-monitor-30 "Stopped Monitor - new node started"
do_test stopped-monitor-31 "Stopped Monitor - new node stopped"
echo ""
# This is a combo test to check:
# - probe timeout defaults to the minimum-interval monitor's
# - duplicate recurring operations are ignored
# - if timeout spec is bad, the default timeout is used
# - failure is blocked with on-fail=block even if ISO8601 interval is specified
# - started/stopped role monitors are started/stopped on right nodes
do_test intervals "Recurring monitor interval handling"
echo""
do_test ticket-primitive-1 "Ticket - Primitive (loss-policy=stop, initial)"
do_test ticket-primitive-2 "Ticket - Primitive (loss-policy=stop, granted)"
do_test ticket-primitive-3 "Ticket - Primitive (loss-policy-stop, revoked)"
do_test ticket-primitive-4 "Ticket - Primitive (loss-policy=demote, initial)"
do_test ticket-primitive-5 "Ticket - Primitive (loss-policy=demote, granted)"
do_test ticket-primitive-6 "Ticket - Primitive (loss-policy=demote, revoked)"
do_test ticket-primitive-7 "Ticket - Primitive (loss-policy=fence, initial)"
do_test ticket-primitive-8 "Ticket - Primitive (loss-policy=fence, granted)"
do_test ticket-primitive-9 "Ticket - Primitive (loss-policy=fence, revoked)"
do_test ticket-primitive-10 "Ticket - Primitive (loss-policy=freeze, initial)"
do_test ticket-primitive-11 "Ticket - Primitive (loss-policy=freeze, granted)"
do_test ticket-primitive-12 "Ticket - Primitive (loss-policy=freeze, revoked)"
do_test ticket-primitive-13 "Ticket - Primitive (loss-policy=stop, standby, granted)"
do_test ticket-primitive-14 "Ticket - Primitive (loss-policy=stop, granted, standby)"
do_test ticket-primitive-15 "Ticket - Primitive (loss-policy=stop, standby, revoked)"
do_test ticket-primitive-16 "Ticket - Primitive (loss-policy=demote, standby, granted)"
do_test ticket-primitive-17 "Ticket - Primitive (loss-policy=demote, granted, standby)"
do_test ticket-primitive-18 "Ticket - Primitive (loss-policy=demote, standby, revoked)"
do_test ticket-primitive-19 "Ticket - Primitive (loss-policy=fence, standby, granted)"
do_test ticket-primitive-20 "Ticket - Primitive (loss-policy=fence, granted, standby)"
do_test ticket-primitive-21 "Ticket - Primitive (loss-policy=fence, standby, revoked)"
do_test ticket-primitive-22 "Ticket - Primitive (loss-policy=freeze, standby, granted)"
do_test ticket-primitive-23 "Ticket - Primitive (loss-policy=freeze, granted, standby)"
do_test ticket-primitive-24 "Ticket - Primitive (loss-policy=freeze, standby, revoked)"
echo""
do_test ticket-group-1 "Ticket - Group (loss-policy=stop, initial)"
do_test ticket-group-2 "Ticket - Group (loss-policy=stop, granted)"
do_test ticket-group-3 "Ticket - Group (loss-policy-stop, revoked)"
do_test ticket-group-4 "Ticket - Group (loss-policy=demote, initial)"
do_test ticket-group-5 "Ticket - Group (loss-policy=demote, granted)"
do_test ticket-group-6 "Ticket - Group (loss-policy=demote, revoked)"
do_test ticket-group-7 "Ticket - Group (loss-policy=fence, initial)"
do_test ticket-group-8 "Ticket - Group (loss-policy=fence, granted)"
do_test ticket-group-9 "Ticket - Group (loss-policy=fence, revoked)"
do_test ticket-group-10 "Ticket - Group (loss-policy=freeze, initial)"
do_test ticket-group-11 "Ticket - Group (loss-policy=freeze, granted)"
do_test ticket-group-12 "Ticket - Group (loss-policy=freeze, revoked)"
do_test ticket-group-13 "Ticket - Group (loss-policy=stop, standby, granted)"
do_test ticket-group-14 "Ticket - Group (loss-policy=stop, granted, standby)"
do_test ticket-group-15 "Ticket - Group (loss-policy=stop, standby, revoked)"
do_test ticket-group-16 "Ticket - Group (loss-policy=demote, standby, granted)"
do_test ticket-group-17 "Ticket - Group (loss-policy=demote, granted, standby)"
do_test ticket-group-18 "Ticket - Group (loss-policy=demote, standby, revoked)"
do_test ticket-group-19 "Ticket - Group (loss-policy=fence, standby, granted)"
do_test ticket-group-20 "Ticket - Group (loss-policy=fence, granted, standby)"
do_test ticket-group-21 "Ticket - Group (loss-policy=fence, standby, revoked)"
do_test ticket-group-22 "Ticket - Group (loss-policy=freeze, standby, granted)"
do_test ticket-group-23 "Ticket - Group (loss-policy=freeze, granted, standby)"
do_test ticket-group-24 "Ticket - Group (loss-policy=freeze, standby, revoked)"
echo""
do_test ticket-clone-1 "Ticket - Clone (loss-policy=stop, initial)"
do_test ticket-clone-2 "Ticket - Clone (loss-policy=stop, granted)"
do_test ticket-clone-3 "Ticket - Clone (loss-policy-stop, revoked)"
do_test ticket-clone-4 "Ticket - Clone (loss-policy=demote, initial)"
do_test ticket-clone-5 "Ticket - Clone (loss-policy=demote, granted)"
do_test ticket-clone-6 "Ticket - Clone (loss-policy=demote, revoked)"
do_test ticket-clone-7 "Ticket - Clone (loss-policy=fence, initial)"
do_test ticket-clone-8 "Ticket - Clone (loss-policy=fence, granted)"
do_test ticket-clone-9 "Ticket - Clone (loss-policy=fence, revoked)"
do_test ticket-clone-10 "Ticket - Clone (loss-policy=freeze, initial)"
do_test ticket-clone-11 "Ticket - Clone (loss-policy=freeze, granted)"
do_test ticket-clone-12 "Ticket - Clone (loss-policy=freeze, revoked)"
do_test ticket-clone-13 "Ticket - Clone (loss-policy=stop, standby, granted)"
do_test ticket-clone-14 "Ticket - Clone (loss-policy=stop, granted, standby)"
do_test ticket-clone-15 "Ticket - Clone (loss-policy=stop, standby, revoked)"
do_test ticket-clone-16 "Ticket - Clone (loss-policy=demote, standby, granted)"
do_test ticket-clone-17 "Ticket - Clone (loss-policy=demote, granted, standby)"
do_test ticket-clone-18 "Ticket - Clone (loss-policy=demote, standby, revoked)"
do_test ticket-clone-19 "Ticket - Clone (loss-policy=fence, standby, granted)"
do_test ticket-clone-20 "Ticket - Clone (loss-policy=fence, granted, standby)"
do_test ticket-clone-21 "Ticket - Clone (loss-policy=fence, standby, revoked)"
do_test ticket-clone-22 "Ticket - Clone (loss-policy=freeze, standby, granted)"
do_test ticket-clone-23 "Ticket - Clone (loss-policy=freeze, granted, standby)"
do_test ticket-clone-24 "Ticket - Clone (loss-policy=freeze, standby, revoked)"
echo""
do_test ticket-master-1 "Ticket - Master (loss-policy=stop, initial)"
do_test ticket-master-2 "Ticket - Master (loss-policy=stop, granted)"
do_test ticket-master-3 "Ticket - Master (loss-policy-stop, revoked)"
do_test ticket-master-4 "Ticket - Master (loss-policy=demote, initial)"
do_test ticket-master-5 "Ticket - Master (loss-policy=demote, granted)"
do_test ticket-master-6 "Ticket - Master (loss-policy=demote, revoked)"
do_test ticket-master-7 "Ticket - Master (loss-policy=fence, initial)"
do_test ticket-master-8 "Ticket - Master (loss-policy=fence, granted)"
do_test ticket-master-9 "Ticket - Master (loss-policy=fence, revoked)"
do_test ticket-master-10 "Ticket - Master (loss-policy=freeze, initial)"
do_test ticket-master-11 "Ticket - Master (loss-policy=freeze, granted)"
do_test ticket-master-12 "Ticket - Master (loss-policy=freeze, revoked)"
do_test ticket-master-13 "Ticket - Master (loss-policy=stop, standby, granted)"
do_test ticket-master-14 "Ticket - Master (loss-policy=stop, granted, standby)"
do_test ticket-master-15 "Ticket - Master (loss-policy=stop, standby, revoked)"
do_test ticket-master-16 "Ticket - Master (loss-policy=demote, standby, granted)"
do_test ticket-master-17 "Ticket - Master (loss-policy=demote, granted, standby)"
do_test ticket-master-18 "Ticket - Master (loss-policy=demote, standby, revoked)"
do_test ticket-master-19 "Ticket - Master (loss-policy=fence, standby, granted)"
do_test ticket-master-20 "Ticket - Master (loss-policy=fence, granted, standby)"
do_test ticket-master-21 "Ticket - Master (loss-policy=fence, standby, revoked)"
do_test ticket-master-22 "Ticket - Master (loss-policy=freeze, standby, granted)"
do_test ticket-master-23 "Ticket - Master (loss-policy=freeze, granted, standby)"
do_test ticket-master-24 "Ticket - Master (loss-policy=freeze, standby, revoked)"
echo ""
do_test ticket-rsc-sets-1 "Ticket - Resource sets (1 ticket, initial)"
do_test ticket-rsc-sets-2 "Ticket - Resource sets (1 ticket, granted)"
do_test ticket-rsc-sets-3 "Ticket - Resource sets (1 ticket, revoked)"
do_test ticket-rsc-sets-4 "Ticket - Resource sets (2 tickets, initial)"
do_test ticket-rsc-sets-5 "Ticket - Resource sets (2 tickets, granted)"
do_test ticket-rsc-sets-6 "Ticket - Resource sets (2 tickets, granted)"
do_test ticket-rsc-sets-7 "Ticket - Resource sets (2 tickets, revoked)"
do_test ticket-rsc-sets-8 "Ticket - Resource sets (1 ticket, standby, granted)"
do_test ticket-rsc-sets-9 "Ticket - Resource sets (1 ticket, granted, standby)"
do_test ticket-rsc-sets-10 "Ticket - Resource sets (1 ticket, standby, revoked)"
do_test ticket-rsc-sets-11 "Ticket - Resource sets (2 tickets, standby, granted)"
do_test ticket-rsc-sets-12 "Ticket - Resource sets (2 tickets, standby, granted)"
do_test ticket-rsc-sets-13 "Ticket - Resource sets (2 tickets, granted, standby)"
do_test ticket-rsc-sets-14 "Ticket - Resource sets (2 tickets, standby, revoked)"
do_test cluster-specific-params "Cluster-specific instance attributes based on rules"
do_test site-specific-params "Site-specific instance attributes based on rules"
echo ""
do_test template-1 "Template - 1"
do_test template-2 "Template - 2"
do_test template-3 "Template - 3 (merge operations)"
do_test template-coloc-1 "Template - Colocation 1"
do_test template-coloc-2 "Template - Colocation 2"
do_test template-coloc-3 "Template - Colocation 3"
do_test template-order-1 "Template - Order 1"
do_test template-order-2 "Template - Order 2"
do_test template-order-3 "Template - Order 3"
do_test template-ticket "Template - Ticket"
do_test template-rsc-sets-1 "Template - Resource Sets 1"
do_test template-rsc-sets-2 "Template - Resource Sets 2"
do_test template-rsc-sets-3 "Template - Resource Sets 3"
do_test template-rsc-sets-4 "Template - Resource Sets 4"
do_test template-clone-primitive "Cloned primitive from template"
do_test template-clone-group "Cloned group from template"
do_test location-sets-templates "Resource sets and templates - Location"
do_test tags-coloc-order-1 "Tags - Colocation and Order (Simple)"
do_test tags-coloc-order-2 "Tags - Colocation and Order (Resource Sets with Templates)"
do_test tags-location "Tags - Location"
do_test tags-ticket "Tags - Ticket"
echo ""
do_test container-1 "Container - initial"
do_test container-2 "Container - monitor failed"
do_test container-3 "Container - stop failed"
do_test container-4 "Container - reached migration-threshold"
do_test container-group-1 "Container in group - initial"
do_test container-group-2 "Container in group - monitor failed"
do_test container-group-3 "Container in group - stop failed"
do_test container-group-4 "Container in group - reached migration-threshold"
do_test container-is-remote-node "Place resource within container when container is remote-node"
do_test bug-rh-1097457 "Kill user defined container/contents ordering"
do_test bug-cl-5247 "Graph loop when recovering m/s resource in a container"
do_test bundle-order-startup "Bundle startup ordering"
do_test bundle-order-partial-start "Bundle startup ordering when some dependancies are already running"
do_test bundle-order-partial-start-2 "Bundle startup ordering when some dependancies and the container are already running"
do_test bundle-order-stop "Bundle stop ordering"
do_test bundle-order-partial-stop "Bundle startup ordering when some dependancies are already stopped"
do_test bundle-order-stop-on-remote "Stop nested resource after bringing up the connection"
do_test bundle-order-startup-clone "Prevent startup because bundle isn't promoted"
do_test bundle-order-startup-clone-2 "Bundle startup with clones"
do_test bundle-order-stop-clone "Stop bundle because clone is stopping"
do_test bundle-nested-colocation "Colocation of nested connection resources"
do_test bundle-order-fencing "Order pseudo bundle fencing after parent node fencing if both are happening"
do_test bundle-probe-order-1 "order 1"
do_test bundle-probe-order-2 "order 2"
do_test bundle-probe-order-3 "order 3"
do_test bundle-probe-remotes "Ensure remotes get probed too"
do_test bundle-replicas-change "Change bundle from 1 replica to multiple"
echo ""
do_test whitebox-fail1 "Fail whitebox container rsc."
do_test whitebox-fail2 "Fail whitebox container rsc lrmd connection."
do_test whitebox-fail3 "Failed containers should not run nested on remote nodes."
do_test whitebox-start "Start whitebox container with resources assigned to it"
do_test whitebox-stop "Stop whitebox container with resources assigned to it"
do_test whitebox-move "Move whitebox container with resources assigned to it"
do_test whitebox-asymmetric "Verify connection rsc opts-in based on container resource"
do_test whitebox-ms-ordering "Verify promote/demote can not occur before connection is established"
do_test whitebox-ms-ordering-move "Stop/Start cycle within a moving container"
do_test whitebox-orphaned "Properly shutdown orphaned whitebox container"
do_test whitebox-orphan-ms "Properly tear down orphan ms resources on remote-nodes"
do_test whitebox-unexpectedly-running "Recover container nodes the cluster did not start."
do_test whitebox-migrate1 "Migrate both container and connection resource"
do_test whitebox-imply-stop-on-fence "imply stop action on container node rsc when host node is fenced"
do_test whitebox-nested-group "Verify guest remote-node works nested in a group"
do_test guest-node-host-dies "Verify guest node is recovered if host goes away"
echo ""
do_test remote-startup-probes "Baremetal remote-node startup probes"
do_test remote-startup "Startup a newly discovered remote-nodes with no status."
do_test remote-fence-unclean "Fence unclean baremetal remote-node"
do_test remote-fence-unclean2 "Fence baremetal remote-node after cluster node fails and connection can not be recovered"
do_test remote-fence-unclean-3 "Probe failed remote nodes (triggers fencing)"
do_test remote-move "Move remote-node connection resource"
do_test remote-disable "Disable a baremetal remote-node"
do_test remote-probe-disable "Probe then stop a baremetal remote-node"
do_test remote-orphaned "Properly shutdown orphaned connection resource"
do_test remote-orphaned2 "verify we can handle orphaned remote connections with active resources on the remote"
do_test remote-recover "Recover connection resource after cluster-node fails."
do_test remote-stale-node-entry "Make sure we properly handle leftover remote-node entries in the node section"
do_test remote-partial-migrate "Make sure partial migrations are handled before ops on the remote node."
do_test remote-partial-migrate2 "Make sure partial migration target is prefered for remote connection."
do_test remote-recover-fail "Make sure start failure causes fencing if rsc are active on remote."
do_test remote-start-fail "Make sure a start failure does not result in fencing if no active resources are on remote."
do_test remote-unclean2 "Make monitor failure always results in fencing, even if no rsc are active on remote."
do_test remote-fence-before-reconnect "Fence before clearing recurring monitor failure"
do_test remote-recovery "Recover remote connections before attempting demotion"
do_test remote-recover-connection "Optimistically recovery of only the connection"
do_test remote-recover-all "Fencing when the connection has no home"
do_test remote-recover-no-resources "Fencing when the connection has no home and no active resources"
do_test remote-recover-unknown "Fencing when the connection has no home and the remote has no operation history"
do_test remote-reconnect-delay "Waiting for remote reconnect interval to expire"
do_test remote-connection-unrecoverable "Remote connection host must be fenced, with connection unrecoverable"
echo ""
do_test resource-discovery "Exercises resource-discovery location constraint option."
do_test rsc-discovery-per-node "Disable resource discovery per node"
if [ $DO_VERSIONED_TESTS -eq 1 ]; then
echo ""
do_test versioned-resources "Start resources with #ra-version rules"
do_test restart-versioned "Restart resources on #ra-version change"
do_test reload-versioned "Reload resources on #ra-version change"
echo ""
do_test versioned-operations-1 "Use #ra-version to configure operations of native resources"
do_test versioned-operations-2 "Use #ra-version to configure operations of stonith resources"
do_test versioned-operations-3 "Use #ra-version to configure operations of master/slave resources"
do_test versioned-operations-4 "Use #ra-version to configure operations of groups of the resources"
fi
echo ""
test_results
exit $EXITCODE
diff --git a/cts/lxc_autogen.sh.in b/cts/lxc_autogen.sh.in
index e7b87f2113..ab828311df 100644
--- a/cts/lxc_autogen.sh.in
+++ b/cts/lxc_autogen.sh.in
@@ -1,526 +1,526 @@
-#!/bin/bash
+#!@BASH_PATH@
containers="2"
download=0
share_configs=0
# different than default libvirt network in case this is run nested in a KVM instance
addr="192.168.123.1"
restore=0
restore_pcmk=0
restore_all=0
generate=0
key_gen=0
cib=0
anywhere=0
add_master=0
verify=0
working_dir="@CRM_CONFIG_CTS@/lxc"
run_dirs="/run /var/run /usr/var/run"
SSH_CMD_OPTS="
-o StrictHostKeyChecking=no
-o ConnectTimeout=30
-o BatchMode=yes
-l root
-T
"
# must be on one line b/c used inside quotes
SSH_RSYNC_OPTS="-o UserKnownHostsFile=/dev/null -o BatchMode=yes -o StrictHostKeyChecking=no"
function helptext() {
echo "lxc_autogen.sh - A tool for generating libvirt lxc containers for testing purposes."
echo ""
echo "Usage: lxc-autogen [options]"
echo ""
echo "Options:"
echo "-g, --generate Generate libvirt lxc environment in the directory this script is run from."
echo "-k, --key-gen Generate pacemaker remote key only."
echo "-r, --restore-libvirt Restore the default network, and libvirt config to before this script ran."
echo "-p, --restore-cib Remove cib entries this script generated."
echo "-R, --restore-all Restore both libvirt and cib plus clean working directory. This will leave libvirt xml files though so rsc can be stopped properly."
echo ""
echo "-A, --allow-anywhere Allow the containers to live anywhere in the cluster"
echo "-a, --add-cib Add remote-node entries for each lxc instance into the cib"
echo "-m, --add-master Add master resource shared between remote-nodes"
echo "-d, --download-agent Download and install the latest VirtualDomain agent."
echo "-s, --share-configs Synchronize on all known cluster nodes"
echo "-c, --containers Specify the number of containers to generate, defaults to $containers. Used with -g"
echo "-n, --network What network to override default libvirt network to. Example: -n 192.168.123.1. Used with -g"
echo "-v, --verify Verify environment is capable of running lxc"
echo ""
exit $1
}
while true ; do
case "$1" in
--help|-h|-\?) helptext 0;;
-c|--containers) containers="$2"; shift; shift;;
-d|--download-agent) download=1; shift;;
-s|--share-configs) share_configs=1; shift;;
-n|--network) addr="$2"; shift; shift;;
-r|--restore-libvirt) restore=1; shift;;
-p|--restore-cib) restore_pcmk=1; shift;;
-R|--restore-all)
restore_all=1
restore=1
restore_pcmk=1
shift;;
-g|--generate) generate=1; key_gen=1; shift;;
-k|--key-gen) key_gen=1; shift;;
-a|--add-cib) cib=1; shift;;
-A|--allow-anywhere) anywhere=1; shift;;
-m|--add-master) add_master=1; shift;;
-v|--verify) verify=1; shift;;
"") break;;
*) helptext 1;;
esac
done
if [ $verify -eq 1 ]; then
# verify virsh tool is available and that
# we can connect to lxc driver.
virsh -c lxc:/// list --all > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Could not connect 'virsh -c lxc:///' check that libvirt lxc driver is installed"
# yum install -y libvirt-daemon-driver-lxc libvirt-daemon-lxc libvirt-login-shell
exit 1
fi
cat /etc/selinux/config | grep -e "SELINUX.*=.*permissive" -e "SELINUX.*=.*enforcing" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "/etc/selinux/config must have SELINUX set to permissive or enforcing mode."
exit 1
fi
ps x > /tmp/lxc-autogen-libvirt-test.txt
grep "libvirtd" /tmp/lxc-autogen-libvirt-test.txt
if [ $? -ne 0 ]; then
rm -f /tmp/lxc-autogen-libvirt-test.txt
echo "libvirtd isn't up."
exit 1
fi
rm -f /tmp/lxc-autogen-libvirt-test.txt
which rsync > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "rsync is required"
fi
which pacemaker_remoted > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "pacemaker_remoted is required"
fi
fi
#strip last digits off addr
addr=$(echo $addr | awk -F. '{print $1"."$2"."$3}')
this_node()
{
crm_node -n
}
other_nodes()
{
crm_node -l | awk "\$2 != \"$(this_node)\" {print \$2}"
}
make_directory()
{
# argument must be full path
DIR="$1"
mkdir -p "$DIR"
if [ $share_configs -eq 1 ]; then
for node in $(other_nodes); do
ssh $SSH_CMD_OPTS $node mkdir -p "$DIR"
done
fi
}
sync_file()
{
TARGET="$1"
if [ $share_configs -eq 1 ]; then
for node in $(other_nodes); do
rsync -ave "ssh $SSH_RSYNC_OPTS" "$TARGET" "${node}:${TARGET}"
done
fi
}
download_agent()
{
wget https://raw.github.com/ClusterLabs/resource-agents/master/heartbeat/VirtualDomain
chmod 755 VirtualDomain
mv -f VirtualDomain /usr/lib/ocf/resource.d/heartbeat/VirtualDomain
sync_file /usr/lib/ocf/resource.d/heartbeat/VirtualDomain
}
set_network()
{
rm -f cur_network.xml
cat << END >> cur_network.xml
<network>
<name>default</name>
<uuid>41ebdb84-7134-1111-a136-91f0f1119225</uuid>
<forward mode='nat'/>
<bridge name='virbr0' stp='on' delay='0' />
<mac address='52:54:00:A8:12:35'/>
<ip address='$addr.1' netmask='255.255.255.0'>
<dhcp>
<range start='$addr.2' end='$addr.254' />
</dhcp>
</ip>
</network>
END
sync_file ${working_dir}/cur_network.xml
}
distribute_configs()
{
for node in $(other_nodes); do
rsync -ave "ssh $SSH_RSYNC_OPTS" ${working_dir}/lxc*.xml ${node}:${working_dir}
rsync -ave "ssh $SSH_RSYNC_OPTS" ${working_dir}/lxc*-filesystem ${node}:${working_dir}
done
}
start_network()
{
NODE="$1"
ssh $SSH_CMD_OPTS $NODE <<-EOF
cd $working_dir
virsh net-info default >/dev/null 2>&1
if [ \$? -eq 0 ]; then
if [ ! -f restore_default.xml ]; then
virsh net-dumpxml default > restore_default.xml
fi
virsh net-destroy default
virsh net-undefine default
fi
virsh net-define cur_network.xml
virsh net-start default
virsh net-autostart default
EOF
}
start_network_all()
{
start_network $(this_node)
if [ $share_configs -eq 1 ]; then
for node in $(other_nodes); do
start_network $node
done
fi
}
add_hosts_entry()
{
IP="$1"
HNAME="$2"
echo $IP $HNAME >>/etc/hosts
if [ $share_configs -eq 1 ]; then
for node in $(other_nodes); do
ssh $SSH_CMD_OPTS $node "echo $IP $HNAME >>/etc/hosts"
done
fi
}
generate_key()
{
if [ ! -e /etc/pacemaker/authkey ]; then
make_directory /etc/pacemaker
dd if=/dev/urandom of=/etc/pacemaker/authkey bs=4096 count=1
sync_file /etc/pacemaker/authkey
fi
}
generate()
{
set_network
# Generate libvirt domains in xml
for (( c=1; c <= $containers; c++ ))
do
# Clean any previous definition
rm -rf lxc$c.xml lxc$c-filesystem
# Create a basic filesystem with run directories
for dir in $run_dirs; do
mkdir -p lxc$c-filesystem/$dir
done
# Create libvirt definition
suffix=$((10 + $c))
prefix=$(echo $addr | awk -F. '{print $1"."$2}')
subnet=$(echo $addr | awk -F. '{print $3}')
while [ $suffix -gt 255 ]; do
subnet=$(($subnet + 1))
suffix=$(($subnet - 255))
done
cip=$prefix.$subnet.$suffix
cat << END >> lxc$c.xml
<domain type='lxc'>
<name>lxc$c</name>
<memory unit='KiB'>200704</memory>
<os>
<type>exe</type>
<init>$working_dir/lxc$c-filesystem/launch-helper</init>
</os>
<devices>
<console type='pty'/>
<filesystem type='ram'>
<source usage='150528'/>
<target dir='/dev/shm'/>
</filesystem>
END
for dir in $run_dirs; do
cat << END >> lxc$c.xml
<filesystem type='mount'>
<source dir='$working_dir/lxc$c-filesystem${dir}'/>
<target dir='$dir'/>
</filesystem>
END
done
cat << END >> lxc$c.xml
<interface type='network'>
<mac address='52:54:$(($RANDOM % 9))$(($RANDOM % 9)):$(($RANDOM % 9))$(($RANDOM % 9)):$(($RANDOM % 9))$(($RANDOM % 9)):$(($RANDOM % 9))$(($RANDOM % 9))'/>
<source network='default'/>
</interface>
</devices>
</domain>
END
# Create CIB definition
rm -f container$c.cib
cat << END >> container$c.cib
<primitive class="ocf" id="container$c" provider="heartbeat" type="VirtualDomain">
<instance_attributes id="container$c-instance_attributes">
<nvpair id="container$c-instance_attributes-force_stop" name="force_stop" value="true"/>
<nvpair id="container$c-instance_attributes-hypervisor" name="hypervisor" value="lxc:///"/>
<nvpair id="container$c-instance_attributes-config" name="config" value="$working_dir/lxc$c.xml"/>
</instance_attributes>
<utilization id="container$c-utilization">
<nvpair id="container$c-utilization-cpu" name="cpu" value="1"/>
<nvpair id="container$c-utilization-hv_memory" name="hv_memory" value="100"/>
</utilization>
<meta_attributes id="container$c-meta_attributes">
<nvpair id="container$c-meta_attributes-remote-node" name="remote-node" value="lxc$c"/>
</meta_attributes>
</primitive>
END
# Create container init
rm -f lxc$c-filesystem/launch-helper
cat << END >> lxc$c-filesystem/launch-helper
-#!/bin/bash
+#!@BASH_PATH@
ip -f inet addr add $cip/24 dev eth0
ip link set eth0 up
ip route add default via $addr.1
hostname lxc$c
df > $working_dir/lxc$c-filesystem/disk_usage.txt
export PCMK_debugfile=@CRM_LOG_DIR@/pacemaker_remote_lxc$c.log
/usr/sbin/pacemaker_remoted
END
chmod 711 lxc$c-filesystem/launch-helper
add_hosts_entry $cip lxc$c
done
# Create CIB fragment for a master-slave resource
rm -f lxc-ms.cib
cat << END >> lxc-ms.cib
<master id="lxc-ms-master">
<primitive class="ocf" id="lxc-ms" provider="pacemaker" type="Stateful">
<instance_attributes id="lxc-ms-instance_attributes"/>
<operations>
<op id="lxc-ms-monitor-interval-10s" interval="10s" name="monitor"/>
</operations>
</primitive>
<meta_attributes id="lxc-ms-meta_attributes">
<nvpair id="lxc-ms-meta_attributes-master-max" name="master-max" value="1"/>
<nvpair id="lxc-ms-meta_attributes-clone-max" name="clone-max" value="$containers"/>
</meta_attributes>
</master>
END
}
apply_cib_master()
{
cibadmin -Q > cur.cib
export CIB_file=cur.cib
cibadmin -o resources -Mc -x lxc-ms.cib
for tmp in $(ls lxc*.xml | sed -e 's/\.xml//g'); do
echo "<rsc_location id=\"lxc-ms-location-${tmp}\" node=\"${tmp}\" rsc=\"lxc-ms-master\" score=\"INFINITY\"/>" > tmp_constraint
cibadmin -o constraints -Mc -x tmp_constraint
done
# Make sure the version changes even if the content doesn't
cibadmin -B
unset CIB_file
cibadmin --replace -o configuration --xml-file cur.cib
rm -f cur.cib
}
apply_cib_entries()
{
cibadmin -Q > cur.cib
export CIB_file=cur.cib
for tmp in $(ls container*.cib); do
cibadmin -o resources -Mc -x $tmp
remote_node=$(cat ${tmp} | grep remote-node | sed -n -e 's/^.*value=\"\(.*\)\".*/\1/p')
if [ $anywhere -eq 0 ]; then
tmp=$(echo $tmp | sed -e 's/\.cib//g')
crm_resource -M -r $tmp -H $(this_node)
fi
echo "<rsc_location id=\"lxc-ping-location-${remote_node}\" node=\"${remote_node}\" rsc=\"Connectivity\" score=\"-INFINITY\"/>" > tmp_constraint
# it's fine if applying this constraint fails. it's just to help with cts
# when the connectivity resources are in use. those resources fail the remote-nodes.
cibadmin -o constraints -Mc -x tmp_constraint > /dev/null 2>&1
for rsc in $(crm_resource -l | grep rsc_ ); do
echo "<rsc_location id=\"lxc-${rsc}-location-${remote_node}\" node=\"${remote_node}\" rsc=\"${rsc}\" score=\"-INFINITY\"/>" > tmp_constraint
cibadmin -o constraints -Mc -x tmp_constraint > /dev/null 2>&1
done
rm -f tmp_constraint
done
# Make sure the version changes even if the content doesn't
cibadmin -B
unset CIB_file
cibadmin --replace -o configuration --xml-file cur.cib
rm -f cur.cib
}
restore_cib()
{
cibadmin -Q > cur.cib
export CIB_file=cur.cib
for tmp in $(ls lxc*.xml | sed -e 's/\.xml//g'); do
echo "<rsc_location id=\"lxc-ms-location-${tmp}\" node=\"${tmp}\" rsc=\"lxc-ms-master\" score=\"INFINITY\"/>" > tmp_constraint
cibadmin -o constraints -D -x tmp_constraint
echo "<rsc_location id=\"lxc-ping-location-${tmp}\" node=\"${tmp}\" rsc=\"Connectivity\" score=\"-INFINITY\"/>" > tmp_constraint
cibadmin -o constraints -D -x tmp_constraint
for rsc in $(crm_resource -l | grep rsc_ ); do
echo "<rsc_location id=\"lxc-${rsc}-location-${tmp}\" node=\"${tmp}\" rsc=\"${rsc}\" score=\"-INFINITY\"/>" > tmp_constraint
cibadmin -o constraints -D -x tmp_constraint
done
rm -f tmp_constraint
done
cibadmin -o resources -D -x lxc-ms.cib
for tmp in $(ls container*.cib); do
tmp=$(echo $tmp | sed -e 's/\.cib//g')
crm_resource -U -r $tmp -H $(this_node)
crm_resource -D -r $tmp -t primitive
done
# Make sure the version changes even if the content doesn't
cibadmin -B
unset CIB_file
cibadmin --replace -o configuration --xml-file cur.cib
rm -f cur.cib
# Allow the cluster to stabilize before continuing
crm_resource --wait
# Purge nodes from caches and CIB status section
for tmp in $(ls lxc*.xml | sed -e 's/\.xml//g'); do
crm_node --force --remove $tmp
done
}
restore_network()
{
NODE="$1"
ssh $SSH_CMD_OPTS $NODE <<-EOF
cd $working_dir
for tmp in \$(ls lxc*.xml | sed -e 's/\.xml//g'); do
virsh -c lxc:/// destroy \$tmp >/dev/null 2>&1
virsh -c lxc:/// undefine \$tmp >/dev/null 2>&1
sed -i.bak "/...\....\....\..* \${tmp}/d" /etc/hosts
done
virsh net-destroy default >/dev/null 2>&1
virsh net-undefine default >/dev/null 2>&1
if [ -f restore_default.xml ]; then
virsh net-define restore_default.xml
virsh net-start default
rm restore_default.xml
fi
EOF
echo "Containers destroyed and default network restored on $NODE"
}
restore_libvirt()
{
restore_network $(this_node)
if [ $share_configs -eq 1 ]; then
for node in $(other_nodes); do
restore_network $node
done
fi
}
restore_files()
{
ls | grep -v "lxc.\.xml" | xargs rm -rf
if [ $share_configs -eq 1 ]; then
for node in $(other_nodes); do
ssh $SSH_CMD_OPTS $node rm -rf \
$working_dir/lxc*-filesystem \
$working_dir/cur_network.xml
done
fi
}
make_directory $working_dir
cd $working_dir
# Generate files as requested
if [ $download -eq 1 ]; then
download_agent
fi
if [ $key_gen -eq 1 ]; then
generate_key
fi
if [ $generate -eq 1 ]; then
generate
fi
if [ $share_configs -eq 1 ]; then
distribute_configs
fi
if [ $generate -eq 1 ]; then
start_network_all
fi
# Update cluster as requested
if [ $cib -eq 1 ]; then
apply_cib_entries
fi
if [ $add_master -eq 1 ]; then
apply_cib_master
fi
# Restore original state as requested
if [ $restore_pcmk -eq 1 ]; then
restore_cib
fi
if [ $restore -eq 1 ]; then
restore_libvirt
fi
if [ $restore_all -eq 1 ]; then
restore_files
fi
diff --git a/fencing/fence_legacy b/fencing/fence_legacy
deleted file mode 100755
index 3625687366..0000000000
--- a/fencing/fence_legacy
+++ /dev/null
@@ -1,239 +0,0 @@
-#!/usr/bin/perl
-
-use Getopt::Long;
-
-my $ME = $0;
-
-END {
- defined fileno STDOUT or return;
- close STDOUT and return;
- warn "$ME: failed to close standard output: $!\n";
- $? ||= 1;
-}
-
-# Get the program name from $0 and strip directory names
-$_=$0;
-s/.*\///;
-my $pname = $_;
-
-$opt_o = 'reset'; # Default fence action
-$opt_s = 'stonith'; # Default fence binary
-$opt_t = 'none'; # Default fence type
-$extra_args = '-E';
-
-sub usage
-{
- print "Helper that presents a RHCS-style interface for Linux-HA stonith plugins\n\n";
- print "Should never need to use invoked by the user directly\n\n";
- print "\n";
- print "Usage: $pname [options]\n";
- print "\n";
- print "Options:\n";
- print " -h usage\n";
- print " -t <sub agent> sub agent\n";
- print " -n <name> nodename\n";
- print " -o <string> Action: on | off | reset (default) | stat | hostlist\n";
- print " -s <stonith> stonith command\n";
- print " -q quiet mode\n";
- print " -V version\n";
-
- exit 0;
-}
-
-sub print_metadata
-{
-print '<?xml version="1.0" ?>
-<resource-agent name="fence_pcmk" shortdesc="Helper that presents a RHCS-style interface for Linux-HA stonith plugins" >
-<longdesc>
-Should never need to use invoked by the user directly and should only
-be configured in cluster.conf, not directly in Pacemaker.
-</longdesc>
-<vendor-url>http://www.clusterlabs.org</vendor-url>
-<parameters>
- <parameter name="action" unique="1" required="1">
- <getopt mixed="-o &lt;action&gt;" />
- <content type="string" default="disable" />
- <shortdesc lang="en">Fencing Action</shortdesc>
- </parameter>
- <parameter name="port" unique="1" required="1">
- <getopt mixed="-n &lt;id&gt;" />
- <content type="string" />
- <shortdesc lang="en">Physical plug number or name of virtual machine</shortdesc>
- </parameter>
- <parameter name="help" unique="1" required="0">
- <getopt mixed="-h" />
- <content type="string" />
- <shortdesc lang="en">Display help and exit</shortdesc>
- </parameter>
-</parameters>
-<actions>
- <action name="enable" />
- <action name="disable" />
- <action name="reboot" />
- <action name="off" />
- <action name="on" />
- <action name="status" />
- <action name="list" />
- <action name="metadata" />
-</actions>
-</resource-agent>
-';
-}
-
-sub fail
-{
- ($msg) = @_;
- print $msg."\n" unless defined $opt_q;
- $t->close if defined $t;
- exit 1;
-}
-
-sub fail_usage
-{
- ($msg)=@_;
- print STDERR $msg."\n" if $msg;
- print STDERR "Please use '-h' for usage.\n";
- exit 1;
-}
-
-sub version
-{
- print "1.0.0\n";
-
- exit 0;
-}
-
-sub get_options_stdin
-{
- my $opt;
- my $line = 0;
- while( defined($in = <>) )
- {
- $_ = $in;
- chomp;
-
- # strip leading and trailing whitespace
- s/^\s*//;
- s/\s*$//;
-
- # skip comments
- next if /^#/;
-
- $line+=1;
- $opt=$_;
- next unless $opt;
-
- ($name,$val)=split /\s*=\s*/, $opt, 2;
-
- if ( $name eq "" )
- {
- print STDERR "parse error: illegal name in option $line\n";
- exit 2;
- }
-
- # DO NOTHING -- this field is used by fenced
- elsif ($name eq "agent" ) {}
-
- elsif ($name eq "plugin" )
- {
- $opt_t = $val;
- }
- elsif ($name eq "option" || $name eq "action" )
- {
- $opt_o = $val;
- }
- elsif ($name eq "nodename" )
- {
- $opt_n = $val;
- $ENV{$name} = $val;
- }
- elsif ($name eq "stonith" )
- {
- $opt_s = $val;
- }
- else
- {
- $ENV{$name} = $val;
- }
-
- }
-}
-
-######################################################################33
-# MAIN
-
-if (@ARGV > 0) {
- GetOptions("t=s"=>\$opt_t,
- "n=s"=>\$opt_n,
- "o=s"=>\$opt_o,
- "s=s"=>\$opt_s,
- "q" =>\$opt_q,
- "V" =>\$opt_V,
- "version" =>\$opt_V,
- "help" =>\$opt_h,
- "h" =>\$opt_h) || fail_usage;
- foreach (@ARGV) {
- print "$_\n";
- }
-# getopts("ht:n:o:s:qV") || fail_usage ;
-
- usage if defined $opt_h;
- version if defined $opt_V;
-
- fail_usage "Unknown parameter." if (@ARGV > 0);
-}
-
-get_options_stdin();
-
-if ((defined $opt_o) && ($opt_o =~ /metadata/i)) {
- print_metadata();
- exit 0;
-}
-
-$opt_o=lc($opt_o);
-fail "failed: unrecognised action: $opt_o"
- unless $opt_o =~ /^(on|off|reset|reboot|stat|status|monitor|list|hostlist|poweroff|poweron)$/;
-
-if ( $opt_o eq "hostlist"|| $opt_o eq "list" ) {
- $opt_q = "1";
-}
-
-if ( $pid=fork() == 0 )
-{
- if ( $opt_o eq "reboot" )
- {
- $opt_o="reset";
- }
- elsif ( $opt_o eq "poweron" )
- {
- $opt_o="on";
- }
- elsif ( $opt_o eq "poweroff" )
- {
- $opt_o="off";
- }
-
- if ( $opt_o eq "hostlist"|| $opt_o eq "list" )
- {
- exec "$opt_s -t $opt_t $extra_args -l" or die "failed to exec \"$opt_s\"\n";
- }
- elsif ( $opt_o eq "monitor" || $opt_o eq "stat" || $opt_o eq "status" )
- {
- print "Performing: $opt_s -t $opt_t -S\n" unless defined $opt_q;
- exec "$opt_s -t $opt_t $extra_args -S" or die "failed to exec \"$opt_s\"\n";
- }
- else
- {
- print "Performing: $opt_s -t $opt_t -T $opt_o $opt_n\n" unless defined $opt_q;
- fail "failed: no plug number" unless defined $opt_n;
- exec "$opt_s -t $opt_t $extra_args -T $opt_o $opt_n" or die "failed to exec \"$opt_s\"\n";
- }
-}
-
-wait;
-$status=$?/256;
-
-print (($status == 0 ? "success":"failed") . ": $opt_n $status\n")
- unless defined $opt_q;
-
-exit ($status == 0 ? 0 : 1 );
diff --git a/fencing/fence_legacy.in b/fencing/fence_legacy.in
new file mode 100755
index 0000000000..ae39e558a9
--- /dev/null
+++ b/fencing/fence_legacy.in
@@ -0,0 +1,275 @@
+#!@PYTHON@
+
+# Pacemaker targets compatibility with Python 2.7 and 3.2+
+from __future__ import print_function, unicode_literals, absolute_import, division
+
+__copyright__ = "Copyright 2018 Andrew Beekhof <andrew@beekhof.net>"
+__license__ = "GNU General Public License version 2 or later (GPLv2+) WITHOUT ANY WARRANTY"
+
+import os
+import sys
+import argparse
+import subprocess
+
+VERSION = "1.1.0"
+
+USAGE = """Helper that presents a Pacemaker-style interface for Linux-HA stonith plugins
+
+Should never be invoked by the user directly
+
+
+Usage: fence_legacy [options]
+
+Options:
+ -h usage
+ -t <sub agent> sub agent
+ -n <name> nodename
+ -o <string> Action: on | off | reset (default) | stat | hostlist
+ -s <stonith> stonith command
+ -q quiet mode
+ -V version"""
+
+META_DATA = """<?xml version="1.0" ?>
+<resource-agent name="fence_pcmk" shortdesc="Helper that presents a Pacemaker-style interface for Linux-HA stonith plugins">
+<longdesc>
+This agent should never be invoked by the user directly.
+</longdesc>
+<vendor-url>https://www.clusterlabs.org/</vendor-url>
+<parameters>
+ <parameter name="action" unique="1" required="1">
+ <getopt mixed="-o &lt;action&gt;" />
+ <content type="string" default="disable" />
+ <shortdesc lang="en">Fencing Action</shortdesc>
+ </parameter>
+ <parameter name="port" unique="1" required="1">
+ <getopt mixed="-n &lt;id&gt;" />
+ <content type="string" />
+ <shortdesc lang="en">Physical plug number or name of virtual machine</shortdesc>
+ </parameter>
+ <parameter name="help" unique="1" required="0">
+ <getopt mixed="-h" />
+ <content type="string" />
+ <shortdesc lang="en">Display help and exit</shortdesc>
+ </parameter>
+</parameters>
+<actions>
+ <action name="enable" />
+ <action name="disable" />
+ <action name="reboot" />
+ <action name="off" />
+ <action name="on" />
+ <action name="status" />
+ <action name="list" />
+ <action name="metadata" />
+</actions>
+</resource-agent>"""
+
+ACTIONS = [
+ "on",
+ "off",
+ "reset",
+ "reboot",
+ "stat",
+ "status",
+ "metadata",
+ "monitor",
+ "list",
+ "hostlist",
+ "poweroff",
+ "poweron"
+]
+
+# These values must be kept in sync with include/crm/crm.h
+class CrmExit:
+ OK = 0
+ ERROR = 1
+ INVALID_PARAM = 2
+
+
+def parse_cli_options():
+ """ Return parsed command-line options (as argparse namespace) """
+
+
+ # Don't add standard help option, so we can format it how we want
+ parser = argparse.ArgumentParser(add_help=False)
+
+ parser.add_argument("-t", metavar="SUBAGENT", dest="subagent",
+ nargs=1, default="none", help="sub-agent")
+
+ parser.add_argument("-n", metavar="NODE", dest="node",
+ nargs=1, default="", help="name of target node")
+
+ # The help text here is consistent with the original version, though
+ # perhaps all actions should be listed.
+ parser.add_argument("-o", metavar="ACTION", dest="action",
+ nargs=1, choices=ACTIONS, default="reset",
+ help="action: on | off | reset (default) | stat | hostlist")
+
+ parser.add_argument("-s", metavar="COMMAND", dest="command",
+ nargs=1, default="stonith", help="stonith command")
+
+ parser.add_argument("-q", dest="quiet", action="store_true",
+ help="quiet mode")
+
+ parser.add_argument("-h", "--help", action="store_true",
+ help="show usage and exit")
+
+ # Don't use action="version", because that printed to stderr before
+ # Python 3.4, and help2man doesn't like that.
+ parser.add_argument("-V", "--version", action="store_true",
+ help="show version and exit")
+
+ return parser.parse_args()
+
+
+def parse_stdin_options(options):
+ """ Update options namespace with options parsed from stdin """
+
+ nlines = 0
+ for line in sys.stdin:
+ # Remove leading and trailing whitespace
+ line = line.strip()
+
+ # Skip blank lines and comments
+ if line == "" or line[0] == "#":
+ continue
+
+ nlines = nlines + 1
+
+ # Parse option name and value (allow whitespace around equals sign)
+ try:
+ (name, value) = line.split("=", 1)
+ name = name.rstrip()
+ if name == "":
+ raise ValueError
+ except ValueError:
+ print("parse error: illegal name in option %d" % nlines,
+ file=sys.stderr)
+ sys.exit(CrmExit.INVALID_PARAM)
+ value = value.lstrip()
+
+ if name == "plugin":
+ options.subagent = value
+
+ elif name in [ "option", "action" ]:
+ options.action = value
+
+ elif name == "nodename":
+ options.node = value
+ os.environ[name] = value
+
+ elif name == "stonith":
+ options.command = value
+
+ elif name != "agent": # agent is used by fenced
+ os.environ[name] = value
+
+
+def normalize_options(options):
+ """ Use string rather than list of one string """
+
+ if not hasattr(options.subagent, "strip"):
+ options.subagent = options.subagent[0]
+
+ if not hasattr(options.node, "strip"):
+ options.node = options.node[0]
+
+ if not hasattr(options.action, "strip"):
+ options.action = options.action[0]
+
+ if not hasattr(options.command, "strip"):
+ options.command = options.command[0]
+
+
+def build_command(options):
+ """ Return command to execute (as list of arguments) """
+
+ if options.action in [ "hostlist", "list" ]:
+ extra_args = [ "-l" ]
+
+ elif options.action in [ "monitor", "stat", "status" ]:
+ extra_args = [ "-S" ]
+
+ else:
+ if options.node == "":
+ if not options.quiet:
+ print("failed: no plug number")
+ sys.exit(CrmExit.ERROR)
+ extra_args = [ "-T", options.action, options.node ]
+
+ return [ options.command, "-t", options.subagent, "-E" ] + extra_args
+
+
+def handle_local_options(options):
+ """ Handle options that don't require the fence agent """
+
+ if options.help:
+ print(USAGE)
+ sys.exit(CrmExit.OK)
+
+ if options.version:
+ print(VERSION)
+ sys.exit(CrmExit.OK)
+
+
+def remap_action(options):
+ """ Pre-process requested action """
+
+ options.action = options.action.lower()
+
+ if options.action == "metadata":
+ print(META_DATA)
+ sys.exit(CrmExit.OK)
+
+ elif options.action in [ "hostlist", "list" ]:
+ options.quiet = True
+
+ # Remap accepted aliases to their actual commands
+
+ elif options.action == "reboot":
+ options.action = "reset"
+
+ elif options.action == "poweron":
+ options.action = "on"
+
+ elif options.action == "poweroff":
+ options.action = "off"
+
+
+def execute_command(options, cmd):
+ """ Execute command and return its exit status """
+
+ if not options.quiet:
+ print("Performing: " + " ".join(cmd))
+ return subprocess.call(cmd)
+
+
+def handle_result(options, status):
+ """ Process fence agent result """
+
+ if status == 0:
+ message = "success"
+ exitcode = CrmExit.OK
+ else:
+ message = "failed"
+ exitcode = CrmExit.ERROR
+ if not options.quiet:
+ print("%s: %s %d" % (message, options.node, status))
+ sys.exit(exitcode)
+
+
+def main():
+ """ Execute an LHA-style fence agent """
+
+ options = parse_cli_options()
+ handle_local_options(options)
+ normalize_options(options)
+ parse_stdin_options(options)
+ remap_action(options)
+ cmd = build_command(options)
+ status = execute_command(options, cmd)
+ handle_result(options, status)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c
index ac5c709a1c..1d57fc0b60 100644
--- a/lrmd/lrmd.c
+++ b/lrmd/lrmd.c
@@ -1,1668 +1,1668 @@
/*
* Copyright 2012-2018 David Vossel <davidvossel@gmail.com>
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <glib.h>
#include <unistd.h>
#include <crm/crm.h>
#include <crm/services.h>
#include <crm/common/mainloop.h>
#include <crm/common/ipc.h>
#include <crm/common/ipcs.h>
#include <crm/msg_xml.h>
#include <lrmd_private.h>
#ifdef HAVE_SYS_TIMEB_H
# include <sys/timeb.h>
#endif
#define EXIT_REASON_MAX_LEN 128
GHashTable *rsc_list = NULL;
typedef struct lrmd_cmd_s {
int timeout;
guint interval_ms;
int start_delay;
int timeout_orig;
int call_id;
int exec_rc;
int lrmd_op_status;
int call_opts;
/* Timer ids, must be removed on cmd destruction. */
int delay_id;
int stonith_recurring_id;
int rsc_deleted;
int service_flags;
char *client_id;
char *origin;
char *rsc_id;
char *action;
char *real_action;
char *exit_reason;
char *output;
char *userdata_str;
#ifdef HAVE_SYS_TIMEB_H
/* recurring and systemd operations may involve more than one lrmd command
* per operation, so they need info about original and most recent
*/
struct timeb t_first_run; /* Timestamp of when op first ran */
struct timeb t_run; /* Timestamp of when op most recently ran */
struct timeb t_first_queue; /* Timestamp of when op first was queued */
struct timeb t_queue; /* Timestamp of when op most recently was queued */
struct timeb t_rcchange; /* Timestamp of last rc change */
#endif
int first_notify_sent;
int last_notify_rc;
int last_notify_op_status;
int last_pid;
GHashTable *params;
} lrmd_cmd_t;
static void cmd_finalize(lrmd_cmd_t * cmd, lrmd_rsc_t * rsc);
static gboolean lrmd_rsc_dispatch(gpointer user_data);
static void cancel_all_recurring(lrmd_rsc_t * rsc, const char *client_id);
static void
log_finished(lrmd_cmd_t * cmd, int exec_time, int queue_time)
{
char pid_str[32] = { 0, };
int log_level = LOG_INFO;
if (cmd->last_pid) {
snprintf(pid_str, 32, "%d", cmd->last_pid);
}
if (safe_str_eq(cmd->action, "monitor")) {
log_level = LOG_DEBUG;
}
#ifdef HAVE_SYS_TIMEB_H
do_crm_log(log_level,
"finished - rsc:%s action:%s call_id:%d %s%s exit-code:%d exec-time:%dms queue-time:%dms",
cmd->rsc_id, cmd->action, cmd->call_id, cmd->last_pid ? "pid:" : "", pid_str,
cmd->exec_rc, exec_time, queue_time);
#else
do_crm_log(log_level, "finished - rsc:%s action:%s call_id:%d %s%s exit-code:%d",
cmd->rsc_id,
cmd->action, cmd->call_id, cmd->last_pid ? "pid:" : "", pid_str, cmd->exec_rc);
#endif
}
static void
log_execute(lrmd_cmd_t * cmd)
{
int log_level = LOG_INFO;
if (safe_str_eq(cmd->action, "monitor")) {
log_level = LOG_DEBUG;
}
do_crm_log(log_level, "executing - rsc:%s action:%s call_id:%d",
cmd->rsc_id, cmd->action, cmd->call_id);
}
static const char *
normalize_action_name(lrmd_rsc_t * rsc, const char *action)
{
if (safe_str_eq(action, "monitor") &&
(safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_LSB) ||
safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_SERVICE)
|| safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_SYSTEMD))) {
return "status";
}
return action;
}
static lrmd_rsc_t *
build_rsc_from_xml(xmlNode * msg)
{
xmlNode *rsc_xml = get_xpath_object("//" F_LRMD_RSC, msg, LOG_ERR);
lrmd_rsc_t *rsc = NULL;
rsc = calloc(1, sizeof(lrmd_rsc_t));
crm_element_value_int(msg, F_LRMD_CALLOPTS, &rsc->call_opts);
rsc->rsc_id = crm_element_value_copy(rsc_xml, F_LRMD_RSC_ID);
rsc->class = crm_element_value_copy(rsc_xml, F_LRMD_CLASS);
rsc->provider = crm_element_value_copy(rsc_xml, F_LRMD_PROVIDER);
rsc->type = crm_element_value_copy(rsc_xml, F_LRMD_TYPE);
rsc->work = mainloop_add_trigger(G_PRIORITY_HIGH, lrmd_rsc_dispatch, rsc);
return rsc;
}
static lrmd_cmd_t *
create_lrmd_cmd(xmlNode * msg, crm_client_t * client)
{
int call_options = 0;
xmlNode *rsc_xml = get_xpath_object("//" F_LRMD_RSC, msg, LOG_ERR);
lrmd_cmd_t *cmd = NULL;
cmd = calloc(1, sizeof(lrmd_cmd_t));
crm_element_value_int(msg, F_LRMD_CALLOPTS, &call_options);
cmd->call_opts = call_options;
cmd->client_id = strdup(client->id);
crm_element_value_int(msg, F_LRMD_CALLID, &cmd->call_id);
crm_element_value_ms(rsc_xml, F_LRMD_RSC_INTERVAL, &cmd->interval_ms);
crm_element_value_int(rsc_xml, F_LRMD_TIMEOUT, &cmd->timeout);
crm_element_value_int(rsc_xml, F_LRMD_RSC_START_DELAY, &cmd->start_delay);
cmd->timeout_orig = cmd->timeout;
cmd->origin = crm_element_value_copy(rsc_xml, F_LRMD_ORIGIN);
cmd->action = crm_element_value_copy(rsc_xml, F_LRMD_RSC_ACTION);
cmd->userdata_str = crm_element_value_copy(rsc_xml, F_LRMD_RSC_USERDATA_STR);
cmd->rsc_id = crm_element_value_copy(rsc_xml, F_LRMD_RSC_ID);
cmd->params = xml2list(rsc_xml);
if (safe_str_eq(g_hash_table_lookup(cmd->params, "CRM_meta_on_fail"), "block")) {
crm_debug("Setting flag to leave pid group on timeout and only kill action pid for " CRM_OP_FMT,
cmd->rsc_id, cmd->action, cmd->interval_ms);
cmd->service_flags |= SVC_ACTION_LEAVE_GROUP;
}
return cmd;
}
static void
free_lrmd_cmd(lrmd_cmd_t * cmd)
{
if (cmd->stonith_recurring_id) {
g_source_remove(cmd->stonith_recurring_id);
}
if (cmd->delay_id) {
g_source_remove(cmd->delay_id);
}
if (cmd->params) {
g_hash_table_destroy(cmd->params);
}
free(cmd->origin);
free(cmd->action);
free(cmd->real_action);
free(cmd->userdata_str);
free(cmd->rsc_id);
free(cmd->output);
free(cmd->exit_reason);
free(cmd->client_id);
free(cmd);
}
static gboolean
stonith_recurring_op_helper(gpointer data)
{
lrmd_cmd_t *cmd = data;
lrmd_rsc_t *rsc;
cmd->stonith_recurring_id = 0;
if (!cmd->rsc_id) {
return FALSE;
}
rsc = g_hash_table_lookup(rsc_list, cmd->rsc_id);
CRM_ASSERT(rsc != NULL);
/* take it out of recurring_ops list, and put it in the pending ops
* to be executed */
rsc->recurring_ops = g_list_remove(rsc->recurring_ops, cmd);
rsc->pending_ops = g_list_append(rsc->pending_ops, cmd);
#ifdef HAVE_SYS_TIMEB_H
ftime(&cmd->t_queue);
if (cmd->t_first_queue.time == 0) {
cmd->t_first_queue = cmd->t_queue;
}
#endif
mainloop_set_trigger(rsc->work);
return FALSE;
}
static gboolean
start_delay_helper(gpointer data)
{
lrmd_cmd_t *cmd = data;
lrmd_rsc_t *rsc = NULL;
cmd->delay_id = 0;
rsc = cmd->rsc_id ? g_hash_table_lookup(rsc_list, cmd->rsc_id) : NULL;
if (rsc) {
mainloop_set_trigger(rsc->work);
}
return FALSE;
}
static gboolean
merge_recurring_duplicate(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
{
GListPtr gIter = NULL;
lrmd_cmd_t * dup = NULL;
gboolean dup_pending = FALSE;
if (cmd->interval_ms == 0) {
return 0;
}
for (gIter = rsc->pending_ops; gIter != NULL; gIter = gIter->next) {
dup = gIter->data;
if (safe_str_eq(cmd->action, dup->action)
&& (cmd->interval_ms == dup->interval_ms)) {
dup_pending = TRUE;
goto merge_dup;
}
}
/* if dup is in recurring_ops list, that means it has already executed
* and is in the interval loop. we can't just remove it in this case. */
for (gIter = rsc->recurring_ops; gIter != NULL; gIter = gIter->next) {
dup = gIter->data;
if (safe_str_eq(cmd->action, dup->action)
&& (cmd->interval_ms == dup->interval_ms)) {
goto merge_dup;
}
}
return FALSE;
merge_dup:
/* This should not occur, if it does we need to investigate in the crmd
* how something like this is possible */
crm_warn("Duplicate recurring op entry detected (" CRM_OP_FMT "), merging with previous op entry",
rsc->rsc_id,
normalize_action_name(rsc, dup->action),
dup->interval_ms);
/* merge */
dup->first_notify_sent = 0;
free(dup->userdata_str);
dup->userdata_str = cmd->userdata_str;
cmd->userdata_str = NULL;
dup->call_id = cmd->call_id;
if (safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH)) {
/* if we are waiting for the next interval, kick it off now */
if (dup_pending == TRUE) {
g_source_remove(cmd->stonith_recurring_id);
cmd->stonith_recurring_id = 0;
stonith_recurring_op_helper(cmd);
}
} else if (dup_pending == FALSE) {
/* if we've already handed this to the service lib, kick off an early execution */
services_action_kick(rsc->rsc_id,
normalize_action_name(rsc, dup->action),
dup->interval_ms);
}
free_lrmd_cmd(cmd);
return TRUE;
}
static void
schedule_lrmd_cmd(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
{
gboolean dup_processed = FALSE;
CRM_CHECK(cmd != NULL, return);
CRM_CHECK(rsc != NULL, return);
crm_trace("Scheduling %s on %s", cmd->action, rsc->rsc_id);
dup_processed = merge_recurring_duplicate(rsc, cmd);
if (dup_processed) {
/* duplicate recurring cmd found, cmds merged */
return;
}
/* crmd expects lrmd to automatically cancel recurring ops before rsc stops. */
if (rsc && safe_str_eq(cmd->action, "stop")) {
cancel_all_recurring(rsc, NULL);
}
rsc->pending_ops = g_list_append(rsc->pending_ops, cmd);
#ifdef HAVE_SYS_TIMEB_H
ftime(&cmd->t_queue);
if (cmd->t_first_queue.time == 0) {
cmd->t_first_queue = cmd->t_queue;
}
#endif
mainloop_set_trigger(rsc->work);
if (cmd->start_delay) {
cmd->delay_id = g_timeout_add(cmd->start_delay, start_delay_helper, cmd);
}
}
static xmlNode *
create_lrmd_reply(const char *origin, int rc, int call_id)
{
xmlNode *reply = create_xml_node(NULL, T_LRMD_REPLY);
crm_xml_add(reply, F_LRMD_ORIGIN, origin);
crm_xml_add_int(reply, F_LRMD_RC, rc);
crm_xml_add_int(reply, F_LRMD_CALLID, call_id);
return reply;
}
static void
send_client_notify(gpointer key, gpointer value, gpointer user_data)
{
xmlNode *update_msg = user_data;
crm_client_t *client = value;
int rc;
if (client == NULL) {
crm_err("Asked to send event to NULL client");
return;
} else if (client->name == NULL) {
crm_trace("Asked to send event to client with no name");
return;
}
rc = lrmd_server_send_notify(client, update_msg);
if ((rc <= 0) && (rc != -ENOTCONN)) {
crm_warn("Could not notify client %s/%s: %s " CRM_XS " rc=%d",
client->name, client->id,
(rc? pcmk_strerror(rc) : "no data sent"), rc);
}
}
#ifdef HAVE_SYS_TIMEB_H
/*!
* \internal
* \brief Return difference between two times in milliseconds
*
* \param[in] now More recent time (or NULL to use current time)
* \param[in] old Earlier time
*
* \return milliseconds difference (or 0 if old is NULL or has time zero)
*/
static int
time_diff_ms(struct timeb *now, struct timeb *old)
{
struct timeb local_now = { 0, };
if (now == NULL) {
ftime(&local_now);
now = &local_now;
}
if ((old == NULL) || (old->time == 0)) {
return 0;
}
return difftime(now->time, old->time) * 1000 + now->millitm - old->millitm;
}
/*!
* \internal
* \brief Reset a command's operation times to their original values.
*
* Reset a command's run and queued timestamps to the timestamps of the original
* command, so we report the entire time since then and not just the time since
* the most recent command (for recurring and systemd operations).
*
* /param[in] cmd LRMD command object to reset
*
* /note It's not obvious what the queued time should be for a systemd
* start/stop operation, which might go like this:
* initial command queued 5ms, runs 3s
* monitor command queued 10ms, runs 10s
* monitor command queued 10ms, runs 10s
* Is the queued time for that operation 5ms, 10ms or 25ms? The current
* implementation will report 5ms. If it's 25ms, then we need to
* subtract 20ms from the total exec time so as not to count it twice.
* We can implement that later if it matters to anyone ...
*/
static void
cmd_original_times(lrmd_cmd_t * cmd)
{
cmd->t_run = cmd->t_first_run;
cmd->t_queue = cmd->t_first_queue;
}
#endif
static void
send_cmd_complete_notify(lrmd_cmd_t * cmd)
{
int exec_time = 0;
int queue_time = 0;
xmlNode *notify = NULL;
#ifdef HAVE_SYS_TIMEB_H
exec_time = time_diff_ms(NULL, &cmd->t_run);
queue_time = time_diff_ms(&cmd->t_run, &cmd->t_queue);
#endif
log_finished(cmd, exec_time, queue_time);
/* if the first notify result for a cmd has already been sent earlier, and the
* the option to only send notifies on result changes is set. Check to see
* if the last result is the same as the new one. If so, suppress this update */
if (cmd->first_notify_sent && (cmd->call_opts & lrmd_opt_notify_changes_only)) {
if (cmd->last_notify_rc == cmd->exec_rc &&
cmd->last_notify_op_status == cmd->lrmd_op_status) {
/* only send changes */
return;
}
}
cmd->first_notify_sent = 1;
cmd->last_notify_rc = cmd->exec_rc;
cmd->last_notify_op_status = cmd->lrmd_op_status;
notify = create_xml_node(NULL, T_LRMD_NOTIFY);
crm_xml_add(notify, F_LRMD_ORIGIN, __FUNCTION__);
crm_xml_add_int(notify, F_LRMD_TIMEOUT, cmd->timeout);
crm_xml_add_ms(notify, F_LRMD_RSC_INTERVAL, cmd->interval_ms);
crm_xml_add_int(notify, F_LRMD_RSC_START_DELAY, cmd->start_delay);
crm_xml_add_int(notify, F_LRMD_EXEC_RC, cmd->exec_rc);
crm_xml_add_int(notify, F_LRMD_OP_STATUS, cmd->lrmd_op_status);
crm_xml_add_int(notify, F_LRMD_CALLID, cmd->call_id);
crm_xml_add_int(notify, F_LRMD_RSC_DELETED, cmd->rsc_deleted);
#ifdef HAVE_SYS_TIMEB_H
crm_xml_add_int(notify, F_LRMD_RSC_RUN_TIME, cmd->t_run.time);
crm_xml_add_int(notify, F_LRMD_RSC_RCCHANGE_TIME, cmd->t_rcchange.time);
crm_xml_add_int(notify, F_LRMD_RSC_EXEC_TIME, exec_time);
crm_xml_add_int(notify, F_LRMD_RSC_QUEUE_TIME, queue_time);
#endif
crm_xml_add(notify, F_LRMD_OPERATION, LRMD_OP_RSC_EXEC);
crm_xml_add(notify, F_LRMD_RSC_ID, cmd->rsc_id);
if(cmd->real_action) {
crm_xml_add(notify, F_LRMD_RSC_ACTION, cmd->real_action);
} else {
crm_xml_add(notify, F_LRMD_RSC_ACTION, cmd->action);
}
crm_xml_add(notify, F_LRMD_RSC_USERDATA_STR, cmd->userdata_str);
crm_xml_add(notify, F_LRMD_RSC_OUTPUT, cmd->output);
crm_xml_add(notify, F_LRMD_RSC_EXIT_REASON, cmd->exit_reason);
if (cmd->params) {
char *key = NULL;
char *value = NULL;
GHashTableIter iter;
xmlNode *args = create_xml_node(notify, XML_TAG_ATTRS);
g_hash_table_iter_init(&iter, cmd->params);
while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
hash2smartfield((gpointer) key, (gpointer) value, args);
}
}
if (cmd->client_id && (cmd->call_opts & lrmd_opt_notify_orig_only)) {
crm_client_t *client = crm_client_get_by_id(cmd->client_id);
if (client) {
send_client_notify(client->id, client, notify);
}
} else if (client_connections != NULL) {
g_hash_table_foreach(client_connections, send_client_notify, notify);
}
free_xml(notify);
}
static void
send_generic_notify(int rc, xmlNode * request)
{
if (client_connections != NULL) {
int call_id = 0;
xmlNode *notify = NULL;
xmlNode *rsc_xml = get_xpath_object("//" F_LRMD_RSC, request, LOG_ERR);
const char *rsc_id = crm_element_value(rsc_xml, F_LRMD_RSC_ID);
const char *op = crm_element_value(request, F_LRMD_OPERATION);
crm_element_value_int(request, F_LRMD_CALLID, &call_id);
notify = create_xml_node(NULL, T_LRMD_NOTIFY);
crm_xml_add(notify, F_LRMD_ORIGIN, __FUNCTION__);
crm_xml_add_int(notify, F_LRMD_RC, rc);
crm_xml_add_int(notify, F_LRMD_CALLID, call_id);
crm_xml_add(notify, F_LRMD_OPERATION, op);
crm_xml_add(notify, F_LRMD_RSC_ID, rsc_id);
g_hash_table_foreach(client_connections, send_client_notify, notify);
free_xml(notify);
}
}
static void
cmd_reset(lrmd_cmd_t * cmd)
{
cmd->lrmd_op_status = 0;
cmd->last_pid = 0;
#ifdef HAVE_SYS_TIMEB_H
memset(&cmd->t_run, 0, sizeof(cmd->t_run));
memset(&cmd->t_queue, 0, sizeof(cmd->t_queue));
#endif
free(cmd->exit_reason);
cmd->exit_reason = NULL;
free(cmd->output);
cmd->output = NULL;
}
static void
cmd_finalize(lrmd_cmd_t * cmd, lrmd_rsc_t * rsc)
{
crm_trace("Resource operation rsc:%s action:%s completed (%p %p)", cmd->rsc_id, cmd->action,
rsc ? rsc->active : NULL, cmd);
if (rsc && (rsc->active == cmd)) {
rsc->active = NULL;
mainloop_set_trigger(rsc->work);
}
if (!rsc) {
cmd->rsc_deleted = 1;
}
/* reset original timeout so client notification has correct information */
cmd->timeout = cmd->timeout_orig;
send_cmd_complete_notify(cmd);
if (cmd->interval_ms && (cmd->lrmd_op_status == PCMK_LRM_OP_CANCELLED)) {
if (rsc) {
rsc->recurring_ops = g_list_remove(rsc->recurring_ops, cmd);
rsc->pending_ops = g_list_remove(rsc->pending_ops, cmd);
}
free_lrmd_cmd(cmd);
} else if (cmd->interval_ms == 0) {
if (rsc) {
rsc->pending_ops = g_list_remove(rsc->pending_ops, cmd);
}
free_lrmd_cmd(cmd);
} else {
/* Clear all the values pertaining just to the last iteration of a recurring op. */
cmd_reset(cmd);
}
}
static int
ocf2uniform_rc(int rc)
{
if (rc < 0 || rc > PCMK_OCF_FAILED_MASTER) {
return PCMK_OCF_UNKNOWN_ERROR;
}
return rc;
}
static int
stonith2uniform_rc(const char *action, int rc)
{
if (rc == -ENODEV) {
if (safe_str_eq(action, "stop")) {
rc = PCMK_OCF_OK;
} else if (safe_str_eq(action, "start")) {
rc = PCMK_OCF_NOT_INSTALLED;
} else {
rc = PCMK_OCF_NOT_RUNNING;
}
} else if (rc != 0) {
rc = PCMK_OCF_UNKNOWN_ERROR;
}
return rc;
}
#if SUPPORT_NAGIOS
static int
nagios2uniform_rc(const char *action, int rc)
{
if (rc < 0) {
return PCMK_OCF_UNKNOWN_ERROR;
}
switch (rc) {
case NAGIOS_STATE_OK:
return PCMK_OCF_OK;
case NAGIOS_INSUFFICIENT_PRIV:
return PCMK_OCF_INSUFFICIENT_PRIV;
case NAGIOS_NOT_INSTALLED:
return PCMK_OCF_NOT_INSTALLED;
case NAGIOS_STATE_WARNING:
case NAGIOS_STATE_CRITICAL:
case NAGIOS_STATE_UNKNOWN:
case NAGIOS_STATE_DEPENDENT:
default:
return PCMK_OCF_UNKNOWN_ERROR;
}
return PCMK_OCF_UNKNOWN_ERROR;
}
#endif
static int
get_uniform_rc(const char *standard, const char *action, int rc)
{
if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_OCF)) {
return ocf2uniform_rc(rc);
} else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_STONITH)) {
return stonith2uniform_rc(action, rc);
} else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_SYSTEMD)) {
return rc;
} else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_UPSTART)) {
return rc;
#if SUPPORT_NAGIOS
} else if (safe_str_eq(standard, PCMK_RESOURCE_CLASS_NAGIOS)) {
return nagios2uniform_rc(action, rc);
#endif
} else {
return services_get_ocf_exitcode(action, rc);
}
}
static int
action_get_uniform_rc(svc_action_t * action)
{
lrmd_cmd_t *cmd = action->cb_data;
return get_uniform_rc(action->standard, cmd->action, action->rc);
}
void
notify_of_new_client(crm_client_t *new_client)
{
crm_client_t *client = NULL;
GHashTableIter iter;
xmlNode *notify = NULL;
char *key = NULL;
notify = create_xml_node(NULL, T_LRMD_NOTIFY);
crm_xml_add(notify, F_LRMD_ORIGIN, __FUNCTION__);
crm_xml_add(notify, F_LRMD_OPERATION, LRMD_OP_NEW_CLIENT);
g_hash_table_iter_init(&iter, client_connections);
while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & client)) {
if (safe_str_eq(client->id, new_client->id)) {
continue;
}
send_client_notify((gpointer) key, (gpointer) client, (gpointer) notify);
}
free_xml(notify);
}
static char *
parse_exit_reason(const char *output)
{
const char *cur = NULL;
const char *last = NULL;
static int cookie_len = 0;
char *eol = NULL;
size_t reason_len = EXIT_REASON_MAX_LEN;
if (output == NULL) {
return NULL;
}
if (!cookie_len) {
cookie_len = strlen(PCMK_OCF_REASON_PREFIX);
}
cur = strstr(output, PCMK_OCF_REASON_PREFIX);
for (; cur != NULL; cur = strstr(cur, PCMK_OCF_REASON_PREFIX)) {
/* skip over the cookie delimiter string */
cur += cookie_len;
last = cur;
}
if (last == NULL) {
return NULL;
}
// Truncate everything after a new line, and limit reason string size
eol = strchr(last, '\n');
if (eol) {
reason_len = QB_MIN(reason_len, eol - last);
}
return strndup(last, reason_len);
}
void
client_disconnect_cleanup(const char *client_id)
{
GHashTableIter iter;
lrmd_rsc_t *rsc = NULL;
char *key = NULL;
g_hash_table_iter_init(&iter, rsc_list);
while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & rsc)) {
if (rsc->call_opts & lrmd_opt_drop_recurring) {
/* This client is disconnecting, drop any recurring operations
* it may have initiated on the resource */
cancel_all_recurring(rsc, client_id);
}
}
}
static void
action_complete(svc_action_t * action)
{
lrmd_rsc_t *rsc;
lrmd_cmd_t *cmd = action->cb_data;
const char *rclass = NULL;
bool goagain = false;
if (!cmd) {
crm_err("LRMD action (%s) completed does not match any known operations.", action->id);
return;
}
#ifdef HAVE_SYS_TIMEB_H
if (cmd->exec_rc != action->rc) {
ftime(&cmd->t_rcchange);
}
#endif
cmd->last_pid = action->pid;
cmd->exec_rc = action_get_uniform_rc(action);
cmd->lrmd_op_status = action->status;
rsc = cmd->rsc_id ? g_hash_table_lookup(rsc_list, cmd->rsc_id) : NULL;
if (rsc && safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_SERVICE)) {
rclass = resources_find_service_class(rsc->class);
} else if(rsc) {
rclass = rsc->class;
}
if (safe_str_eq(rclass, PCMK_RESOURCE_CLASS_SYSTEMD)) {
if(cmd->exec_rc == PCMK_OCF_OK && safe_str_eq(cmd->action, "start")) {
/* systemd I curse thee!
*
* systemd returns from start actions after the start _begins_
* not after it completes.
*
* So we have to jump through a few hoops so that we don't
* report 'complete' to the rest of pacemaker until, you know,
* it's actually done.
*/
goagain = true;
cmd->real_action = cmd->action;
cmd->action = strdup("monitor");
} else if(cmd->exec_rc == PCMK_OCF_OK && safe_str_eq(cmd->action, "stop")) {
goagain = true;
cmd->real_action = cmd->action;
cmd->action = strdup("monitor");
} else if(cmd->real_action) {
/* Ok, so this is the follow up monitor action to check if start actually completed */
if(cmd->lrmd_op_status == PCMK_LRM_OP_DONE && cmd->exec_rc == PCMK_OCF_PENDING) {
goagain = true;
} else if(cmd->exec_rc == PCMK_OCF_OK && safe_str_eq(cmd->real_action, "stop")) {
goagain = true;
} else {
#ifdef HAVE_SYS_TIMEB_H
int time_sum = time_diff_ms(NULL, &cmd->t_first_run);
int timeout_left = cmd->timeout_orig - time_sum;
crm_debug("%s %s is now complete (elapsed=%dms, remaining=%dms): %s (%d)",
cmd->rsc_id, cmd->real_action, time_sum, timeout_left, services_ocf_exitcode_str(cmd->exec_rc), cmd->exec_rc);
cmd_original_times(cmd);
#endif
if(cmd->lrmd_op_status == PCMK_LRM_OP_DONE && cmd->exec_rc == PCMK_OCF_NOT_RUNNING && safe_str_eq(cmd->real_action, "stop")) {
cmd->exec_rc = PCMK_OCF_OK;
}
}
}
}
#if SUPPORT_NAGIOS
if (rsc && safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_NAGIOS)) {
if (safe_str_eq(cmd->action, "monitor") &&
(cmd->interval_ms == 0) && cmd->exec_rc == PCMK_OCF_OK) {
/* Successfully executed --version for the nagios plugin */
cmd->exec_rc = PCMK_OCF_NOT_RUNNING;
} else if (safe_str_eq(cmd->action, "start") && cmd->exec_rc != PCMK_OCF_OK) {
goagain = true;
}
}
#endif
/* Wrapping this section in ifdef implies that systemd resources are not
* fully supported on platforms without sys/timeb.h. Since timeb is
* obsolete, we should eventually prefer a clock_gettime() implementation
* (wrapped in its own ifdef) with timeb as a fallback.
*/
-#ifdef HAVE_SYS_TIMEB_H
if(goagain) {
+#ifdef HAVE_SYS_TIMEB_H
int time_sum = time_diff_ms(NULL, &cmd->t_first_run);
int timeout_left = cmd->timeout_orig - time_sum;
int delay = cmd->timeout_orig / 10;
if(delay >= timeout_left && timeout_left > 20) {
delay = timeout_left/2;
}
delay = QB_MIN(2000, delay);
if (delay < timeout_left) {
cmd->start_delay = delay;
cmd->timeout = timeout_left;
if(cmd->exec_rc == PCMK_OCF_OK) {
crm_debug("%s %s may still be in progress: re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
cmd->rsc_id, cmd->real_action, time_sum, timeout_left, delay);
} else if(cmd->exec_rc == PCMK_OCF_PENDING) {
crm_info("%s %s is still in progress: re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
cmd->rsc_id, cmd->action, time_sum, timeout_left, delay);
} else {
crm_notice("%s %s failed '%s' (%d): re-scheduling (elapsed=%dms, remaining=%dms, start_delay=%dms)",
cmd->rsc_id, cmd->action, services_ocf_exitcode_str(cmd->exec_rc), cmd->exec_rc, time_sum, timeout_left, delay);
}
cmd_reset(cmd);
if(rsc) {
rsc->active = NULL;
}
schedule_lrmd_cmd(rsc, cmd);
/* Don't finalize cmd, we're not done with it yet */
return;
} else {
crm_notice("Giving up on %s %s (rc=%d): timeout (elapsed=%dms, remaining=%dms)",
cmd->rsc_id, cmd->real_action?cmd->real_action:cmd->action, cmd->exec_rc, time_sum, timeout_left);
cmd->lrmd_op_status = PCMK_LRM_OP_TIMEOUT;
cmd->exec_rc = PCMK_OCF_TIMEOUT;
cmd_original_times(cmd);
}
- }
#endif
+ }
if (action->stderr_data) {
cmd->output = strdup(action->stderr_data);
cmd->exit_reason = parse_exit_reason(action->stderr_data);
} else if (action->stdout_data) {
cmd->output = strdup(action->stdout_data);
}
cmd_finalize(cmd, rsc);
}
static void
stonith_action_complete(lrmd_cmd_t * cmd, int rc)
{
bool recurring = (cmd->interval_ms > 0);
lrmd_rsc_t *rsc = NULL;
cmd->exec_rc = get_uniform_rc(PCMK_RESOURCE_CLASS_STONITH, cmd->action, rc);
rsc = g_hash_table_lookup(rsc_list, cmd->rsc_id);
if (cmd->lrmd_op_status == PCMK_LRM_OP_CANCELLED) {
recurring = FALSE;
/* do nothing */
} else if (rc == -ENODEV && safe_str_eq(cmd->action, "monitor")) {
/* Not registered == inactive */
cmd->lrmd_op_status = PCMK_LRM_OP_DONE;
cmd->exec_rc = PCMK_OCF_NOT_RUNNING;
} else if (rc) {
/* Attempt to map return codes to op status if possible */
switch (rc) {
case -EPROTONOSUPPORT:
cmd->lrmd_op_status = PCMK_LRM_OP_NOTSUPPORTED;
break;
case -ETIME:
cmd->lrmd_op_status = PCMK_LRM_OP_TIMEOUT;
break;
default:
/* TODO: This looks wrong. Status should be _DONE and exec_rc set to an error */
cmd->lrmd_op_status = PCMK_LRM_OP_ERROR;
}
} else {
/* command successful */
cmd->lrmd_op_status = PCMK_LRM_OP_DONE;
if (safe_str_eq(cmd->action, "start") && rsc) {
rsc->stonith_started = 1;
}
}
if (recurring && rsc) {
if (cmd->stonith_recurring_id) {
g_source_remove(cmd->stonith_recurring_id);
}
cmd->stonith_recurring_id = g_timeout_add(cmd->interval_ms,
stonith_recurring_op_helper,
cmd);
}
cmd_finalize(cmd, rsc);
}
static void
lrmd_stonith_callback(stonith_t * stonith, stonith_callback_data_t * data)
{
stonith_action_complete(data->userdata, data->rc);
}
void
stonith_connection_failed(void)
{
GHashTableIter iter;
GList *cmd_list = NULL;
GList *cmd_iter = NULL;
lrmd_rsc_t *rsc = NULL;
char *key = NULL;
g_hash_table_iter_init(&iter, rsc_list);
while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & rsc)) {
if (safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH)) {
if (rsc->active) {
cmd_list = g_list_append(cmd_list, rsc->active);
}
if (rsc->recurring_ops) {
cmd_list = g_list_concat(cmd_list, rsc->recurring_ops);
}
if (rsc->pending_ops) {
cmd_list = g_list_concat(cmd_list, rsc->pending_ops);
}
rsc->pending_ops = rsc->recurring_ops = NULL;
}
}
if (!cmd_list) {
return;
}
crm_err("STONITH connection failed, finalizing %d pending operations.",
g_list_length(cmd_list));
for (cmd_iter = cmd_list; cmd_iter; cmd_iter = cmd_iter->next) {
stonith_action_complete(cmd_iter->data, -ENOTCONN);
}
g_list_free(cmd_list);
}
static int
lrmd_rsc_execute_stonith(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
{
int rc = 0;
int do_monitor = 0;
stonith_t *stonith_api = get_stonith_connection();
if (!stonith_api) {
cmd->exec_rc = get_uniform_rc(PCMK_RESOURCE_CLASS_STONITH, cmd->action,
-ENOTCONN);
cmd->lrmd_op_status = PCMK_LRM_OP_ERROR;
cmd_finalize(cmd, rsc);
return -EUNATCH;
}
if (safe_str_eq(cmd->action, "start")) {
char *key = NULL;
char *value = NULL;
stonith_key_value_t *device_params = NULL;
if (cmd->params) {
GHashTableIter iter;
g_hash_table_iter_init(&iter, cmd->params);
while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
device_params = stonith_key_value_add(device_params, key, value);
}
}
/* Stonith automatically registers devices from the IPC when changes occur,
* but to avoid a possible race condition between stonith receiving the IPC update
* and the lrmd requesting that resource, the lrmd still registers the device as well.
* Stonith knows how to handle duplicate device registrations correctly. */
rc = stonith_api->cmds->register_device(stonith_api,
st_opt_sync_call,
cmd->rsc_id,
rsc->provider, rsc->type, device_params);
stonith_key_value_freeall(device_params, 1, 1);
if (rc == 0) {
do_monitor = 1;
}
} else if (safe_str_eq(cmd->action, "stop")) {
rc = stonith_api->cmds->remove_device(stonith_api, st_opt_sync_call, cmd->rsc_id);
rsc->stonith_started = 0;
} else if (safe_str_eq(cmd->action, "monitor")) {
if (cmd->interval_ms > 0) {
do_monitor = 1;
} else {
rc = rsc->stonith_started ? 0 : -ENODEV;
}
}
if (!do_monitor) {
goto cleanup_stonith_exec;
}
rc = stonith_api->cmds->monitor(stonith_api, 0, cmd->rsc_id, cmd->timeout / 1000);
rc = stonith_api->cmds->register_callback(stonith_api,
rc,
0,
0,
cmd, "lrmd_stonith_callback", lrmd_stonith_callback);
/* don't cleanup yet, we will find out the result of the monitor later */
if (rc > 0) {
rsc->active = cmd;
return rc;
} else if (rc == 0) {
rc = -1;
}
cleanup_stonith_exec:
stonith_action_complete(cmd, rc);
return rc;
}
static int
lrmd_rsc_execute_service_lib(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
{
svc_action_t *action = NULL;
GHashTable *params_copy = NULL;
CRM_ASSERT(rsc);
CRM_ASSERT(cmd);
crm_trace("Creating action, resource:%s action:%s class:%s provider:%s agent:%s",
rsc->rsc_id, cmd->action, rsc->class, rsc->provider, rsc->type);
#if SUPPORT_NAGIOS
/* Recurring operations are cancelled anyway for a stop operation */
if (safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_NAGIOS)
&& safe_str_eq(cmd->action, "stop")) {
cmd->exec_rc = PCMK_OCF_OK;
goto exec_done;
}
#endif
params_copy = crm_str_table_dup(cmd->params);
action = resources_action_create(rsc->rsc_id, rsc->class, rsc->provider,
rsc->type,
normalize_action_name(rsc, cmd->action),
cmd->interval_ms, cmd->timeout,
params_copy, cmd->service_flags);
if (!action) {
crm_err("Failed to create action, action:%s on resource %s", cmd->action, rsc->rsc_id);
cmd->lrmd_op_status = PCMK_LRM_OP_ERROR;
goto exec_done;
}
action->cb_data = cmd;
/* 'cmd' may not be valid after this point if
* services_action_async() returned TRUE
*
* Upstart and systemd both synchronously determine monitor/status
* results and call action_complete (which may free 'cmd') if necessary.
*/
if (services_action_async(action, action_complete)) {
return TRUE;
}
cmd->exec_rc = action->rc;
if(action->status != PCMK_LRM_OP_DONE) {
cmd->lrmd_op_status = action->status;
} else {
cmd->lrmd_op_status = PCMK_LRM_OP_ERROR;
}
services_action_free(action);
action = NULL;
exec_done:
cmd_finalize(cmd, rsc);
return TRUE;
}
static gboolean
lrmd_rsc_execute(lrmd_rsc_t * rsc)
{
lrmd_cmd_t *cmd = NULL;
CRM_CHECK(rsc != NULL, return FALSE);
if (rsc->active) {
crm_trace("%s is still active", rsc->rsc_id);
return TRUE;
}
if (rsc->pending_ops) {
GList *first = rsc->pending_ops;
cmd = first->data;
if (cmd->delay_id) {
crm_trace
("Command %s %s was asked to run too early, waiting for start_delay timeout of %dms",
cmd->rsc_id, cmd->action, cmd->start_delay);
return TRUE;
}
rsc->pending_ops = g_list_remove_link(rsc->pending_ops, first);
g_list_free_1(first);
#ifdef HAVE_SYS_TIMEB_H
if (cmd->t_first_run.time == 0) {
ftime(&cmd->t_first_run);
}
ftime(&cmd->t_run);
#endif
}
if (!cmd) {
crm_trace("Nothing further to do for %s", rsc->rsc_id);
return TRUE;
}
rsc->active = cmd; /* only one op at a time for a rsc */
if (cmd->interval_ms) {
rsc->recurring_ops = g_list_append(rsc->recurring_ops, cmd);
}
log_execute(cmd);
if (safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH)) {
lrmd_rsc_execute_stonith(rsc, cmd);
} else {
lrmd_rsc_execute_service_lib(rsc, cmd);
}
return TRUE;
}
static gboolean
lrmd_rsc_dispatch(gpointer user_data)
{
return lrmd_rsc_execute(user_data);
}
void
free_rsc(gpointer data)
{
GListPtr gIter = NULL;
lrmd_rsc_t *rsc = data;
int is_stonith = safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH);
gIter = rsc->pending_ops;
while (gIter != NULL) {
GListPtr next = gIter->next;
lrmd_cmd_t *cmd = gIter->data;
/* command was never executed */
cmd->lrmd_op_status = PCMK_LRM_OP_CANCELLED;
cmd_finalize(cmd, NULL);
gIter = next;
}
/* frees list, but not list elements. */
g_list_free(rsc->pending_ops);
gIter = rsc->recurring_ops;
while (gIter != NULL) {
GListPtr next = gIter->next;
lrmd_cmd_t *cmd = gIter->data;
if (is_stonith) {
cmd->lrmd_op_status = PCMK_LRM_OP_CANCELLED;
/* If a stonith command is in-flight, just mark it as cancelled;
* it is not safe to finalize/free the cmd until the stonith api
* says it has either completed or timed out.
*/
if (rsc->active != cmd) {
cmd_finalize(cmd, NULL);
}
} else {
/* This command is already handed off to service library,
* let service library cancel it and tell us via the callback
* when it is cancelled. The rsc can be safely destroyed
* even if we are waiting for the cancel result */
services_action_cancel(rsc->rsc_id,
normalize_action_name(rsc, cmd->action),
cmd->interval_ms);
}
gIter = next;
}
/* frees list, but not list elements. */
g_list_free(rsc->recurring_ops);
free(rsc->rsc_id);
free(rsc->class);
free(rsc->provider);
free(rsc->type);
mainloop_destroy_trigger(rsc->work);
free(rsc);
}
static xmlNode *
process_lrmd_signon(crm_client_t *client, xmlNode *request, int call_id)
{
xmlNode *reply = NULL;
int rc = pcmk_ok;
const char *is_ipc_provider = crm_element_value(request, F_LRMD_IS_IPC_PROVIDER);
const char *protocol_version = crm_element_value(request, F_LRMD_PROTOCOL_VERSION);
if (compare_version(protocol_version, LRMD_MIN_PROTOCOL_VERSION) < 0) {
crm_err("Cluster API version must be greater than or equal to %s, not %s",
LRMD_MIN_PROTOCOL_VERSION, protocol_version);
rc = -EPROTO;
}
reply = create_lrmd_reply(__FUNCTION__, rc, call_id);
crm_xml_add(reply, F_LRMD_OPERATION, CRM_OP_REGISTER);
crm_xml_add(reply, F_LRMD_CLIENTID, client->id);
crm_xml_add(reply, F_LRMD_PROTOCOL_VERSION, LRMD_PROTOCOL_VERSION);
if (crm_is_true(is_ipc_provider)) {
/* this is a remote connection from a cluster nodes crmd */
#ifdef SUPPORT_REMOTE
ipc_proxy_add_provider(client);
#endif
}
return reply;
}
static int
process_lrmd_rsc_register(crm_client_t * client, uint32_t id, xmlNode * request)
{
int rc = pcmk_ok;
lrmd_rsc_t *rsc = build_rsc_from_xml(request);
lrmd_rsc_t *dup = g_hash_table_lookup(rsc_list, rsc->rsc_id);
if (dup &&
safe_str_eq(rsc->class, dup->class) &&
safe_str_eq(rsc->provider, dup->provider) && safe_str_eq(rsc->type, dup->type)) {
crm_warn("Can't add, RSC '%s' already present in the rsc list (%d active resources)",
rsc->rsc_id, g_hash_table_size(rsc_list));
free_rsc(rsc);
return rc;
}
g_hash_table_replace(rsc_list, rsc->rsc_id, rsc);
crm_info("Added '%s' to the rsc list (%d active resources)",
rsc->rsc_id, g_hash_table_size(rsc_list));
return rc;
}
static xmlNode *
process_lrmd_get_rsc_info(xmlNode *request, int call_id)
{
int rc = pcmk_ok;
xmlNode *rsc_xml = get_xpath_object("//" F_LRMD_RSC, request, LOG_ERR);
const char *rsc_id = crm_element_value(rsc_xml, F_LRMD_RSC_ID);
xmlNode *reply = NULL;
lrmd_rsc_t *rsc = NULL;
if (rsc_id == NULL) {
rc = -ENODEV;
} else {
rsc = g_hash_table_lookup(rsc_list, rsc_id);
if (rsc == NULL) {
crm_info("Resource '%s' not found (%d active resources)",
rsc_id, g_hash_table_size(rsc_list));
rc = -ENODEV;
}
}
reply = create_lrmd_reply(__FUNCTION__, rc, call_id);
if (rsc) {
crm_xml_add(reply, F_LRMD_RSC_ID, rsc->rsc_id);
crm_xml_add(reply, F_LRMD_CLASS, rsc->class);
crm_xml_add(reply, F_LRMD_PROVIDER, rsc->provider);
crm_xml_add(reply, F_LRMD_TYPE, rsc->type);
}
return reply;
}
static int
process_lrmd_rsc_unregister(crm_client_t * client, uint32_t id, xmlNode * request)
{
int rc = pcmk_ok;
lrmd_rsc_t *rsc = NULL;
xmlNode *rsc_xml = get_xpath_object("//" F_LRMD_RSC, request, LOG_ERR);
const char *rsc_id = crm_element_value(rsc_xml, F_LRMD_RSC_ID);
if (!rsc_id) {
return -ENODEV;
}
if (!(rsc = g_hash_table_lookup(rsc_list, rsc_id))) {
crm_info("Resource '%s' not found (%d active resources)",
rsc_id, g_hash_table_size(rsc_list));
return pcmk_ok;
}
if (rsc->active) {
/* let the caller know there are still active ops on this rsc to watch for */
crm_trace("Operation still in progress: %p", rsc->active);
rc = -EINPROGRESS;
}
g_hash_table_remove(rsc_list, rsc_id);
return rc;
}
static int
process_lrmd_rsc_exec(crm_client_t * client, uint32_t id, xmlNode * request)
{
lrmd_rsc_t *rsc = NULL;
lrmd_cmd_t *cmd = NULL;
xmlNode *rsc_xml = get_xpath_object("//" F_LRMD_RSC, request, LOG_ERR);
const char *rsc_id = crm_element_value(rsc_xml, F_LRMD_RSC_ID);
int call_id;
if (!rsc_id) {
return -EINVAL;
}
if (!(rsc = g_hash_table_lookup(rsc_list, rsc_id))) {
crm_info("Resource '%s' not found (%d active resources)",
rsc_id, g_hash_table_size(rsc_list));
return -ENODEV;
}
cmd = create_lrmd_cmd(request, client);
call_id = cmd->call_id;
/* Don't reference cmd after handing it off to be scheduled.
* The cmd could get merged and freed. */
schedule_lrmd_cmd(rsc, cmd);
return call_id;
}
static int
cancel_op(const char *rsc_id, const char *action, guint interval_ms)
{
GListPtr gIter = NULL;
lrmd_rsc_t *rsc = g_hash_table_lookup(rsc_list, rsc_id);
/* How to cancel an action.
* 1. Check pending ops list, if it hasn't been handed off
* to the service library or stonith recurring list remove
* it there and that will stop it.
* 2. If it isn't in the pending ops list, then it's either a
* recurring op in the stonith recurring list, or the service
* library's recurring list. Stop it there
* 3. If not found in any lists, then this operation has either
* been executed already and is not a recurring operation, or
* never existed.
*/
if (!rsc) {
return -ENODEV;
}
for (gIter = rsc->pending_ops; gIter != NULL; gIter = gIter->next) {
lrmd_cmd_t *cmd = gIter->data;
if (safe_str_eq(cmd->action, action)
&& (cmd->interval_ms == interval_ms)) {
cmd->lrmd_op_status = PCMK_LRM_OP_CANCELLED;
cmd_finalize(cmd, rsc);
return pcmk_ok;
}
}
if (safe_str_eq(rsc->class, PCMK_RESOURCE_CLASS_STONITH)) {
/* The service library does not handle stonith operations.
* We have to handle recurring stonith operations ourselves. */
for (gIter = rsc->recurring_ops; gIter != NULL; gIter = gIter->next) {
lrmd_cmd_t *cmd = gIter->data;
if (safe_str_eq(cmd->action, action)
&& (cmd->interval_ms == interval_ms)) {
cmd->lrmd_op_status = PCMK_LRM_OP_CANCELLED;
if (rsc->active != cmd) {
cmd_finalize(cmd, rsc);
}
return pcmk_ok;
}
}
} else if (services_action_cancel(rsc_id,
normalize_action_name(rsc, action),
interval_ms) == TRUE) {
/* The service library will tell the action_complete callback function
* this action was cancelled, which will destroy the cmd and remove
* it from the recurring_op list. Do not do that in this function
* if the service library says it cancelled it. */
return pcmk_ok;
}
return -EOPNOTSUPP;
}
static void
cancel_all_recurring(lrmd_rsc_t * rsc, const char *client_id)
{
GList *cmd_list = NULL;
GList *cmd_iter = NULL;
/* Notice a copy of each list is created when concat is called.
* This prevents odd behavior from occurring when the cmd_list
* is iterated through later on. It is possible the cancel_op
* function may end up modifying the recurring_ops and pending_ops
* lists. If we did not copy those lists, our cmd_list iteration
* could get messed up.*/
if (rsc->recurring_ops) {
cmd_list = g_list_concat(cmd_list, g_list_copy(rsc->recurring_ops));
}
if (rsc->pending_ops) {
cmd_list = g_list_concat(cmd_list, g_list_copy(rsc->pending_ops));
}
if (!cmd_list) {
return;
}
for (cmd_iter = cmd_list; cmd_iter; cmd_iter = cmd_iter->next) {
lrmd_cmd_t *cmd = cmd_iter->data;
if (cmd->interval_ms == 0) {
continue;
}
if (client_id && safe_str_neq(cmd->client_id, client_id)) {
continue;
}
cancel_op(rsc->rsc_id, cmd->action, cmd->interval_ms);
}
/* frees only the copied list data, not the cmds */
g_list_free(cmd_list);
}
static int
process_lrmd_rsc_cancel(crm_client_t * client, uint32_t id, xmlNode * request)
{
xmlNode *rsc_xml = get_xpath_object("//" F_LRMD_RSC, request, LOG_ERR);
const char *rsc_id = crm_element_value(rsc_xml, F_LRMD_RSC_ID);
const char *action = crm_element_value(rsc_xml, F_LRMD_RSC_ACTION);
guint interval_ms = 0;
crm_element_value_ms(rsc_xml, F_LRMD_RSC_INTERVAL, &interval_ms);
if (!rsc_id || !action) {
return -EINVAL;
}
return cancel_op(rsc_id, action, interval_ms);
}
static void
add_recurring_op_xml(xmlNode *reply, lrmd_rsc_t *rsc)
{
xmlNode *rsc_xml = create_xml_node(reply, F_LRMD_RSC);
crm_xml_add(rsc_xml, F_LRMD_RSC_ID, rsc->rsc_id);
for (GList *item = rsc->recurring_ops; item != NULL; item = item->next) {
lrmd_cmd_t *cmd = item->data;
xmlNode *op_xml = create_xml_node(rsc_xml, T_LRMD_RSC_OP);
crm_xml_add(op_xml, F_LRMD_RSC_ACTION,
(cmd->real_action? cmd->real_action : cmd->action));
crm_xml_add_ms(op_xml, F_LRMD_RSC_INTERVAL, cmd->interval_ms);
crm_xml_add_int(op_xml, F_LRMD_TIMEOUT, cmd->timeout_orig);
}
}
static xmlNode *
process_lrmd_get_recurring(xmlNode *request, int call_id)
{
int rc = pcmk_ok;
const char *rsc_id = NULL;
lrmd_rsc_t *rsc = NULL;
xmlNode *reply = NULL;
xmlNode *rsc_xml = NULL;
// Resource ID is optional
rsc_xml = first_named_child(request, F_LRMD_CALLDATA);
if (rsc_xml) {
rsc_xml = first_named_child(rsc_xml, F_LRMD_RSC);
}
if (rsc_xml) {
rsc_id = crm_element_value(rsc_xml, F_LRMD_RSC_ID);
}
// If resource ID is specified, resource must exist
if (rsc_id != NULL) {
rsc = g_hash_table_lookup(rsc_list, rsc_id);
if (rsc == NULL) {
crm_info("Resource '%s' not found (%d active resources)",
rsc_id, g_hash_table_size(rsc_list));
rc = -ENODEV;
}
}
reply = create_lrmd_reply(__FUNCTION__, rc, call_id);
// If resource ID is not specified, check all resources
if (rsc_id == NULL) {
GHashTableIter iter;
char *key = NULL;
g_hash_table_iter_init(&iter, rsc_list);
while (g_hash_table_iter_next(&iter, (gpointer *) &key,
(gpointer *) &rsc)) {
add_recurring_op_xml(reply, rsc);
}
} else if (rsc) {
add_recurring_op_xml(reply, rsc);
}
return reply;
}
void
process_lrmd_message(crm_client_t * client, uint32_t id, xmlNode * request)
{
int rc = pcmk_ok;
int call_id = 0;
const char *op = crm_element_value(request, F_LRMD_OPERATION);
int do_reply = 0;
int do_notify = 0;
xmlNode *reply = NULL;
crm_trace("Processing %s operation from %s", op, client->id);
crm_element_value_int(request, F_LRMD_CALLID, &call_id);
if (crm_str_eq(op, CRM_OP_IPC_FWD, TRUE)) {
#ifdef SUPPORT_REMOTE
ipc_proxy_forward_client(client, request);
#endif
do_reply = 1;
} else if (crm_str_eq(op, CRM_OP_REGISTER, TRUE)) {
reply = process_lrmd_signon(client, request, call_id);
do_reply = 1;
} else if (crm_str_eq(op, LRMD_OP_RSC_REG, TRUE)) {
rc = process_lrmd_rsc_register(client, id, request);
do_notify = 1;
do_reply = 1;
} else if (crm_str_eq(op, LRMD_OP_RSC_INFO, TRUE)) {
reply = process_lrmd_get_rsc_info(request, call_id);
do_reply = 1;
} else if (crm_str_eq(op, LRMD_OP_RSC_UNREG, TRUE)) {
rc = process_lrmd_rsc_unregister(client, id, request);
/* don't notify anyone about failed un-registers */
if (rc == pcmk_ok || rc == -EINPROGRESS) {
do_notify = 1;
}
do_reply = 1;
} else if (crm_str_eq(op, LRMD_OP_RSC_EXEC, TRUE)) {
rc = process_lrmd_rsc_exec(client, id, request);
do_reply = 1;
} else if (crm_str_eq(op, LRMD_OP_RSC_CANCEL, TRUE)) {
rc = process_lrmd_rsc_cancel(client, id, request);
do_reply = 1;
} else if (crm_str_eq(op, LRMD_OP_POKE, TRUE)) {
do_notify = 1;
do_reply = 1;
} else if (crm_str_eq(op, LRMD_OP_CHECK, TRUE)) {
xmlNode *data = get_message_xml(request, F_LRMD_CALLDATA);
const char *timeout = crm_element_value(data, F_LRMD_WATCHDOG);
CRM_LOG_ASSERT(data != NULL);
check_sbd_timeout(timeout);
} else if (crm_str_eq(op, LRMD_OP_ALERT_EXEC, TRUE)) {
rc = process_lrmd_alert_exec(client, id, request);
do_reply = 1;
} else if (crm_str_eq(op, LRMD_OP_GET_RECURRING, TRUE)) {
reply = process_lrmd_get_recurring(request, call_id);
do_reply = 1;
} else {
rc = -EOPNOTSUPP;
do_reply = 1;
crm_err("Unknown %s from %s", op, client->name);
crm_log_xml_warn(request, "UnknownOp");
}
crm_debug("Processed %s operation from %s: rc=%d, reply=%d, notify=%d",
op, client->id, rc, do_reply, do_notify);
if (do_reply) {
int send_rc = pcmk_ok;
if (reply == NULL) {
reply = create_lrmd_reply(__FUNCTION__, rc, call_id);
}
send_rc = lrmd_server_send_reply(client, id, reply);
free_xml(reply);
if (send_rc < 0) {
crm_warn("Reply to client %s failed: %s " CRM_XS " %d",
client->name, pcmk_strerror(send_rc), send_rc);
}
}
if (do_notify) {
send_generic_notify(rc, request);
}
}
diff --git a/lrmd/pacemaker_remote.in b/lrmd/pacemaker_remote.in
index c52b6f8217..e07e1b9671 100644
--- a/lrmd/pacemaker_remote.in
+++ b/lrmd/pacemaker_remote.in
@@ -1,176 +1,176 @@
-#!/bin/bash
+#!@BASH_PATH@
# Authors:
# Andrew Beekhof <abeekhof@redhat.com>
#
# License: Revised BSD
# chkconfig: - 99 01
# description: Pacemaker Cluster Manager
# processname: pacemaker_remoted
#
### BEGIN INIT INFO
# Provides: pacemaker_remote
# Required-Start: $network $remote_fs
# Should-Start: $syslog
# Required-Stop: $network $remote_fs
# Default-Start:
# Default-Stop:
# Short-Description: Starts and stops the Pacemaker remote agent for non-cluster nodes
# Description: Starts and stops the Pacemaker remote agent for non-cluster nodes
### END INIT INFO
desc="Pacemaker Remote Agent"
prog="pacemaker_remoted"
# set secure PATH
PATH="/sbin:/bin:/usr/sbin:/usr/bin:@sbindir@"
checkrc() {
if [ $? = 0 ]; then
success
else
failure
fi
}
success()
{
echo -ne "[ OK ]\r"
}
failure()
{
echo -ne "[FAILED]\r"
}
status()
{
pid=$(pidof $1 2>/dev/null)
local rtrn=$?
if [ $rtrn -ne 0 ]; then
echo "$1 is stopped"
if [ -f "@localstatedir@/run/$prog.pid" ]; then
rtrn=1
else
rtrn=3
fi
else
echo "$1 (pid $pid) is running..."
fi
return $rtrn
}
if [ -d @CONFIGDIR@ ]; then
[ -f @INITDIR@/functions ] && . @INITDIR@/functions
set -a
[ -f @CONFIGDIR@/pacemaker ] && . @CONFIGDIR@/pacemaker
[ -f @CONFIGDIR@/sbd ] && . @CONFIGDIR@/sbd
set +a
fi
LOCK_DIR="."
if [ -d "@localstatedir@/lock/subsys" ]; then
LOCK_DIR="@localstatedir@/lock/subsys"
elif [ -d "@localstatedir@/lock" ]; then
LOCK_DIR="@localstatedir@/lock"
fi
[ -z "$LOCK_FILE" ] && LOCK_FILE="$LOCK_DIR/pacemaker_remote"
# Check if there is a valid watchdog-device configured in sbd config
if [ x != "x$SBD_WATCHDOG_DEV" -a "/dev/null" != "$SBD_WATCHDOG_DEV" -a -c "$SBD_WATCHDOG_DEV" ]; then
# enhance for unavailable chkconfig - don't touch sbd for now
if chkconfig --list sbd_remote_helper 2>/dev/null | grep -q ":on"; then
SBD_SERVICE=sbd_remote_helper
fi
fi
start()
{
echo -n "Starting $desc: "
# most recent distributions use tmpfs for $@localstatedir@/run
# to avoid to clean it up on every boot.
# they also assume that init scripts will create
# required subdirectories for proper operations
mkdir -p "@localstatedir@/run"
if status $prog > /dev/null 2>&1; then
success
else
$prog > /dev/null 2>&1 &
# Time to connect to corosync and fail
sleep 5
if status $prog > /dev/null 2>&1; then
touch "$LOCK_FILE"
pidof $prog > "@localstatedir@/run/$prog.pid"
success
else
failure
rtrn=1
fi
fi
echo
[ "x$SBD_SERVICE" = "x" ] || service $SBD_SERVICE start
}
stop()
{
if status $prog > /dev/null 2>&1; then
echo -n "Signaling $desc to terminate: "
kill -TERM $(pidof $prog) > /dev/null 2>&1
success
echo
echo -n "Waiting for $desc to unload:"
while status $prog > /dev/null 2>&1; do
sleep 1
echo -n "."
done
else
echo -n "$desc is already stopped"
fi
rm -f "$LOCK_FILE"
rm -f "@localstatedir@/run/$prog.pid"
success
echo
[ "x$SBD_SERVICE" = "x" ] || service $SBD_SERVICE stop
}
rtrn=0
case "$1" in
start)
start
;;
restart|reload|force-reload)
stop
start
;;
condrestart|try-restart)
if status $prog > /dev/null 2>&1; then
stop
start
rtrn=$?
fi
;;
status)
status $prog
rtrn=$?
;;
stop)
stop
rtrn=$?
;;
*)
echo "usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}"
rtrn=2
;;
esac
exit $rtrn
diff --git a/mcp/pacemaker.in b/mcp/pacemaker.in
index 4be41fd1bb..8f5ca1905b 100644
--- a/mcp/pacemaker.in
+++ b/mcp/pacemaker.in
@@ -1,189 +1,189 @@
-#!/bin/bash
+#!@BASH_PATH@
# Authors:
# Andrew Beekhof <abeekhof@redhat.com>
# Fabio M. Di Nitto <fdinitto@redhat.com>
#
# License: Revised BSD
# chkconfig: - 99 01
# description: Pacemaker Cluster Manager
# processname: pacemakerd
#
### BEGIN INIT INFO
# Provides: pacemaker
# Required-Start: $network $remote_fs corosync
# Should-Start: $syslog
# Required-Stop: $network $remote_fs corosync
# Default-Start:
# Default-Stop:
# Short-Description: Starts and stops Pacemaker Cluster Manager.
# Description: Starts and stops Pacemaker Cluster Manager.
### END INIT INFO
desc="Pacemaker Cluster Manager"
prog="pacemakerd"
# set secure PATH
PATH="/sbin:/bin:/usr/sbin:/usr/bin:@sbindir@"
checkrc() {
if [ $? = 0 ]; then
success
else
failure
fi
}
success()
{
echo -ne "[ OK ]\r"
}
failure()
{
echo -ne "[FAILED]\r"
}
log()
{
logger -t pacemaker -p daemon.notice "$*"
}
notify()
{
log "$*"
echo -n "$*"
}
status()
{
pid=$(pidof $1 2>/dev/null)
local rtrn=$?
if [ $rtrn -ne 0 ]; then
echo "$1 is stopped"
if [ -f "@localstatedir@/run/$prog.pid" ]; then
rtrn=1
else
rtrn=3
fi
else
echo "$1 (pid $pid) is running..."
fi
return $rtrn
}
if [ -d @CONFIGDIR@ ]; then
[ -f @INITDIR@/functions ] && . @INITDIR@/functions
set -a
[ -f @CONFIGDIR@/pacemaker ] && . @CONFIGDIR@/pacemaker
[ -f @CONFIGDIR@/sbd ] && . @CONFIGDIR@/sbd
set +a
fi
LOCK_DIR="."
if [ -d "@localstatedir@/lock/subsys" ]; then
LOCK_DIR="@localstatedir@/lock/subsys"
elif [ -d "@localstatedir@/lock" ]; then
LOCK_DIR="@localstatedir@/lock"
fi
[ -z "$LOCK_FILE" ] && LOCK_FILE="$LOCK_DIR/pacemaker"
# Check if there is a valid watchdog-device configured in sbd config
if [ x != "x$SBD_WATCHDOG_DEV" -a "/dev/null" != "$SBD_WATCHDOG_DEV" -a -c "$SBD_WATCHDOG_DEV" ]; then
# enhance for unavailable chkconfig - don't touch sbd for now
if chkconfig --list sbd_helper 2>/dev/null | grep -q ":on"; then
SBD_SERVICE=sbd_helper
fi
fi
start()
{
notify "Starting $desc"
# most recent distributions use tmpfs for $@localstatedir@/run
# to avoid to clean it up on every boot.
# they also assume that init scripts will create
# required subdirectories for proper operations
mkdir -p "@localstatedir@/run"
if status $prog > /dev/null 2>&1; then
success
else
$prog > /dev/null 2>&1 &
# Time to connect to corosync and fail
sleep 5
if status $prog > /dev/null 2>&1; then
touch "$LOCK_FILE"
pidof $prog > "@localstatedir@/run/$prog.pid"
success
else
failure
rtrn=1
fi
fi
echo
}
stop()
{
shutdown_prog=$prog
if ! status $prog > /dev/null 2>&1; then
shutdown_prog="crmd"
fi
if status $shutdown_prog > /dev/null 2>&1; then
notify "Signaling $desc to terminate"
kill -TERM $(pidof $prog) > /dev/null 2>&1
checkrc
echo
notify "Waiting for cluster services to unload"
while status $prog > /dev/null 2>&1; do
sleep 1
echo -n "."
done
else
echo -n "$desc is already stopped"
fi
rm -f "$LOCK_FILE"
rm -f "@localstatedir@/run/$prog.pid"
killall -q -9 'crmd stonithd attrd cib lrmd pacemakerd'
success
echo
}
rtrn=0
case "$1" in
start)
start
;;
restart|reload|force-reload)
stop
start
;;
condrestart|try-restart)
if status $prog > /dev/null 2>&1; then
stop
start
fi
;;
status)
status $prog
rtrn=$?
;;
stop)
stop
[ "x$SBD_SERVICE" != x ] && service $SBD_SERVICE stop
;;
*)
echo "usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}"
rtrn=2
;;
esac
exit $rtrn
diff --git a/tools/crm_failcount b/tools/crm_failcount.in
similarity index 98%
rename from tools/crm_failcount
rename to tools/crm_failcount.in
index 9682344db0..c1c61b4ade 100755
--- a/tools/crm_failcount
+++ b/tools/crm_failcount.in
@@ -1,273 +1,273 @@
-#!/bin/bash
+#!@BASH_PATH@
USAGE_TEXT="Usage: crm_failcount <command> [<options>]
Common options:
--help Display this text, then exit
--version Display version information, then exit
-V, --verbose Specify multiple times to increase debug output
-q, --quiet Print only the value (if querying)
Commands:
-G, --query Query the current value of the resource's fail count
-D, --delete Delete resource's recorded failures
Additional Options:
-r, --resource=value Name of the resource to use (required)
-n, --operation=value Name of operation to use (instead of all operations)
-I, --interval=value If operation is specified, its interval
-N, --node=value Use failcount on named node (instead of local node)"
HELP_TEXT="crm_failcount - Query or delete resource fail counts
$USAGE_TEXT"
# These constants must track crm_exit_t values
CRM_EX_OK=0
CRM_EX_ERROR=1
CRM_EX_USAGE=64
CRM_EX_NOSUCH=105
exit_usage() {
if [ $# -gt 0 ]; then
echo "error: $@" >&2
fi
echo
echo "$USAGE_TEXT"
exit $CRM_EX_USAGE
}
warn() {
echo "warning: $@" >&2
}
interval_re() {
echo "^[[:blank:]]*([0-9]+)[[:blank:]]*(${1})[[:blank:]]*$"
}
# This function should follow crm_get_interval() as closely as possible
parse_interval() {
INT_S="$1"
INT_8601RE="^P(([0-9]+)Y)?(([0-9]+)M)?(([0-9]+)D)?T?(([0-9]+)H)?(([0-9]+)M)?(([0-9]+)S)?$"
if [[ $INT_S =~ $(interval_re "s|sec|") ]]; then
echo $(( ${BASH_REMATCH[1]} * 1000 ))
elif [[ $INT_S =~ $(interval_re "ms|msec") ]]; then
echo "${BASH_REMATCH[1]}"
elif [[ $INT_S =~ $(interval_re "m|min") ]]; then
echo $(( ${BASH_REMATCH[1]} * 60000 ))
elif [[ $INT_S =~ $(interval_re "h|hr") ]]; then
echo $(( ${BASH_REMATCH[1]} * 3600000 ))
elif [[ $INT_S =~ $(interval_re "us|usec") ]]; then
echo $(( ${BASH_REMATCH[1]} / 1000 ))
elif [[ $INT_S =~ ^P([0-9]+)W$ ]]; then
echo $(( ${BASH_REMATCH[1]} * 604800000 ))
elif [[ $INT_S =~ $INT_8601RE ]]; then
echo $(( ( ${BASH_REMATCH[2]:-0} * 31536000000 ) \
+ ( ${BASH_REMATCH[4]:-0} * 2592000000 ) \
+ ( ${BASH_REMATCH[6]:-0} * 86400000 ) \
+ ( ${BASH_REMATCH[8]:-0} * 3600000 ) \
+ ( ${BASH_REMATCH[10]:-0} * 60000 ) \
+ ( ${BASH_REMATCH[12]:-0} * 1000 ) ))
else
warn "Unrecognized interval, using 0"
echo "0"
fi
}
query_single_attr() {
QSR_TARGET="$1"
QSR_ATTR="$2"
crm_attribute $VERBOSE --quiet --query -t status -d 0 \
-N "$QSR_TARGET" -n "$QSR_ATTR"
}
query_attr_sum() {
QAS_TARGET="$1"
QAS_PREFIX="$2"
# Build xpath to match all transient node attributes with prefix
QAS_XPATH="/cib/status/node_state[@uname='${QAS_TARGET}']"
QAS_XPATH="${QAS_XPATH}/transient_attributes/instance_attributes"
QAS_XPATH="${QAS_XPATH}/nvpair[starts-with(@name,'$QAS_PREFIX')]"
# Query attributes that match xpath
# @TODO We ignore stderr because we don't want "no results" to look
# like an error, but that also makes $VERBOSE pointless.
QAS_ALL=$(cibadmin --query --sync-call --local \
--xpath="$QAS_XPATH" 2>/dev/null)
QAS_EX=$?
# "No results" is not an error
if [ $QAS_EX -ne $CRM_EX_OK ] && [ $QAS_EX -ne $CRM_EX_NOSUCH ]; then
echo "error: could not query CIB for fail counts" >&2
exit $QAS_EX
fi
# Extract the attribute values (one per line) from the output
QAS_VALUE=$(echo "$QAS_ALL" | sed -n -e \
's/.*<nvpair.*value="\([0-9][0-9]*\)".*>.*/\1/p')
# Sum the values
QAS_SUM=0
for i in 0 $QAS_VALUE; do
QAS_SUM=$(($QAS_SUM + $i))
done
echo $QAS_SUM
}
query_failcount() {
QF_TARGET="$1"
QF_RESOURCE="$2"
QF_OPERATION="$3"
QF_INTERVAL="$4"
QF_ATTR_RSC="fail-count-${QF_RESOURCE}"
if [ -n "$QF_OPERATION" ]; then
QF_ATTR_DISPLAY="${QF_ATTR_RSC}#${QF_OPERATION}_${QF_INTERVAL}"
QF_COUNT=$(query_single_attr "$QF_TARGET" "$QF_ATTR_DISPLAY")
else
QF_ATTR_DISPLAY="$QF_ATTR_RSC"
QF_COUNT=$(query_attr_sum "$QF_TARGET" "${QF_ATTR_RSC}#")
fi
# @COMPAT attributes set < 1.1.17:
# If we didn't find any per-operation failcount,
# check whether there is a legacy per-resource failcount.
if [ "$QF_COUNT" = "0" ]; then
QF_COUNT=$(query_single_attr "$QF_TARGET" "$QF_ATTR_RSC")
if [ "$QF_COUNT" != "0" ]; then
QF_ATTR_DISPLAY="$QF_ATTR_RSC"
fi
fi
# Echo result (comparable to crm_attribute, for backward compatibility)
if [ -n "$QUIET" ]; then
echo $QF_COUNT
else
echo "scope=status name=$QF_ATTR_DISPLAY value=$QF_COUNT"
fi
}
clear_failcount() {
CF_TARGET="$1"
CF_RESOURCE="$2"
CF_OPERATION="$3"
CF_INTERVAL="$4"
if [ -n "$CF_OPERATION" ]; then
CF_OPERATION="-n $CF_OPERATION -I ${CF_INTERVAL}ms"
fi
crm_resource $QUIET $VERBOSE --cleanup \
-N "$CF_TARGET" -r "$CF_RESOURCE" $CF_OPERATION
}
QUIET=""
VERBOSE=""
command=""
resource=""
operation=""
interval="0"
target=$(crm_node -n 2>/dev/null)
SHORTOPTS="qDGQVN:U:v:i:l:r:n:I:"
LONGOPTS_COMMON="help,version,verbose,quiet"
LONGOPTS_COMMANDS="query,delete"
LONGOPTS_OTHER="resource:,node:,operation:,interval:"
LONGOPTS_COMPAT="delete-attr,get-value,resource-id:,uname:,lifetime:,attr-value:,attr-id:"
LONGOPTS="$LONGOPTS_COMMON,$LONGOPTS_COMMANDS,$LONGOPTS_OTHER,$LONGOPTS_COMPAT"
-TEMP=$(getopt -o $SHORTOPTS --long $LONGOPTS -n crm_failcount -- "$@")
+TEMP=$(@GETOPT_PATH@ -o $SHORTOPTS --long $LONGOPTS -n crm_failcount -- "$@")
if [ $? -ne 0 ]; then
exit_usage
fi
eval set -- "$TEMP" # Quotes around $TEMP are essential
while true ; do
case "$1" in
--help)
echo "$HELP_TEXT"
exit $CRM_EX_OK
;;
--version)
crm_attribute --version
exit $?
;;
-q|-Q|--quiet)
QUIET="--quiet"
shift
;;
-V|--verbose)
VERBOSE="$VERBOSE $1"
shift
;;
-G|--query|--get-value)
command="--query"
shift
;;
-D|--delete|--delete-attr)
command="--delete"
shift
;;
-r|--resource|--resource-id)
resource="$2"
shift 2
;;
-n|--operation)
operation="$2"
shift 2
;;
-I|--interval)
interval="$2"
shift 2
;;
-N|--node|-U|--uname)
target="$2"
shift 2
;;
-v|--attr-value)
if [ "$2" = "0" ]; then
command="--delete"
else
warn "ignoring deprecated option '$1' with nonzero value"
fi
shift 2
;;
-i|--attr-id|-l|--lifetime)
warn "ignoring deprecated option '$1'"
shift 2
;;
--)
shift
break
;;
*)
exit_usage "unknown option '$1'"
;;
esac
done
[ -n "$command" ] || exit_usage "must specify a command"
[ -n "$resource" ] || exit_usage "resource name required"
[ -n "$target" ] || exit_usage "node name required"
interval=$(parse_interval $interval)
if [ "$command" = "--query" ]; then
query_failcount "$target" "$resource" "$operation" "$interval"
else
clear_failcount "$target" "$resource" "$operation" "$interval"
fi
diff --git a/tools/crm_master b/tools/crm_master.in
similarity index 97%
rename from tools/crm_master
rename to tools/crm_master.in
index fbc8205ef5..5177c4f26c 100755
--- a/tools/crm_master
+++ b/tools/crm_master.in
@@ -1,103 +1,103 @@
-#!/bin/bash
+#!@BASH_PATH@
USAGE_TEXT="Usage: crm_master <command> [<options>]
Common options:
--help Display this text, then exit
--version Display version information, then exit
-V, --verbose Specify multiple times to increase debug output
-q, --quiet Print only the value (if querying)
Commands:
-G, --query Query the current value of the promotion score
-v, --update=VALUE Update the value of the promotion score
-D, --delete Delete the promotion score
Additional Options:
-N, --node=NODE Use promotion score on named node (instead of local node)
-l, --lifetime=VALUE Until when should the setting take effect
(valid values: reboot, forever)
-i, --id=VALUE (Advanced) XML ID used to identify promotion score attribute"
HELP_TEXT="crm_master - Query, update, or delete a resource's promotion score
This program should normally be invoked only from inside an OCF resource agent.
$USAGE_TEXT"
exit_usage() {
if [ $# -gt 0 ]; then
echo "error: $@" >&2
fi
echo
echo "$USAGE_TEXT"
exit 1
}
SHORTOPTS_DEPRECATED="U:Q"
LONGOPTS_DEPRECATED="uname:,get-value,delete-attr,attr-value:,attr-id:"
SHORTOPTS="VqGv:DN:l:i:r:"
LONGOPTS="help,version,verbose,quiet,query,update:,delete,node:,lifetime:,id:,resource:"
-TEMP=$(getopt -o ${SHORTOPTS}${SHORTOPTS_DEPRECATED} \
+TEMP=$(@GETOPT_PATH@ -o ${SHORTOPTS}${SHORTOPTS_DEPRECATED} \
--long ${LONGOPTS},${LONGOPTS_DEPRECATED} \
-n crm_master -- "$@")
if [ $? -ne 0 ]; then
exit_usage
fi
eval set -- "$TEMP" # Quotes around $TEMP are essential
# Explicitly set the (usual default) lifetime, so the attribute gets set as a
# node attribute and not a cluster property.
options="--lifetime forever"
while true ; do
case "$1" in
--help)
echo "$HELP_TEXT"
exit 0
;;
--version)
crm_attribute --version
exit 0
;;
--verbose|-V|--quiet|-q|--query|-G|--delete|-D)
options="$options $1"
shift
;;
--update|-v|--node|-N|--lifetime|-l|--id|-i)
options="$options $1 $2"
shift
shift
;;
-r|--resource)
OCF_RESOURCE_INSTANCE=$2;
shift
shift
;;
--get-value|--delete-attr|-Q) # deprecated
options="$options $1"
shift
;;
--uname|-U|--attr-value|--attr-id) # deprecated
options="$options $1 $2"
shift
shift
;;
--)
shift
break
;;
*)
exit_usage "unknown option '$1'"
;;
esac
done
if [ -z "$OCF_RESOURCE_INSTANCE" ]; then
echo "This program should normally only be invoked from inside an OCF resource agent."
echo "To set a promotion score from the command line, please specify resource with -r."
exit 1
fi
crm_attribute -n master-$OCF_RESOURCE_INSTANCE $options
diff --git a/tools/crm_report.in b/tools/crm_report.in
index 9f2e883f0c..3a3e91b2de 100644
--- a/tools/crm_report.in
+++ b/tools/crm_report.in
@@ -1,477 +1,477 @@
#!/bin/sh
# Copyright (C) 2010 Andrew Beekhof <andrew@beekhof.net>
#
# 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.1 of the License, or (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
-TEMP=`getopt \
+TEMP=`@GETOPT_PATH@ \
-o hv?xl:f:t:n:T:L:p:c:dSCu:D:MVse: \
--long help,cts:,cts-log:,dest:,node:,nodes:,from:,to:,sos-mode,logfile:,as-directory,single-node,cluster:,user:,max-depth:,version,features,rsh: \
-n 'crm_report' -- "$@"`
# The quotes around $TEMP are essential
eval set -- "$TEMP"
progname=$(basename "$0")
rsh="ssh -T"
times=""
tests=""
nodes=""
compress=1
cluster="any"
ssh_user="root"
search_logs=1
report_data=`dirname $0`
maxdepth=5
extra_logs=""
sanitize_patterns="passw.*"
log_patterns="CRIT: ERROR:"
usage() {
cat<<EOF
$progname - Create archive of everything needed when reporting cluster problems
Usage: $progname [options] [DEST]
Required option:
-f, --from TIME time prior to problems beginning
(as "YYYY-M-D H:M:S" including the quotes)
Options:
-V increase verbosity (may be specified multiple times)
-v, --version display software version
--features display software features
-t, --to TIME time at which all problems were resolved
(as "YYYY-M-D H:M:S" including the quotes; default "now")
-T, --cts TEST CTS test or set of tests to extract
--cts-log CTS master logfile
-n, --nodes NODES node names for this cluster (only needed if cluster is
not active on this host; accepts -n "a b" or -n a -n b)
-M do not search for cluster logs
-l, --logfile FILE log file to collect (in addition to detected logs if -M
is not specified; may be specified multiple times)
-p PATT additional regular expression to match variables to be
masked in output (default: "passw.*")
-L PATT additional regular expression to match in log files for
analysis (default: $log_patterns)
-S, --single-node don't attempt to collect data from other nodes
-c, --cluster TYPE force the cluster type instead of detecting
(currently only corosync is supported)
-C, --corosync force the cluster type to be corosync
-u, --user USER username to use when collecting data from other nodes
(default root)
-D, --depth search depth to use when attempting to locate files
-e, --rsh command to use to run commands on other nodes
(default ssh -T)
--sos-mode use defaults suitable for being called by sosreport tool
(behavior subject to change and not useful to end users)
DEST, --dest DEST custom destination directory or file name
$progname works best when run from a cluster node on a running cluster,
but can be run from a stopped cluster node or a Pacemaker Remote node.
If neither --nodes nor --single-node is given, $progname will guess the
node list, but may have trouble detecting Pacemaker Remote nodes.
Unless --single-node is given, the node names (whether specified by --nodes
or detected automatically) must be resolvable and reachable via the command
specified by -e/--rsh using the user specified by -u/--user.
Examples:
$progname -f "2011-12-14 13:05:00" unexplained-apache-failure
$progname -f 2011-12-14 -t 2011-12-15 something-that-took-multiple-days
$progname -f 13:05:00 -t 13:12:00 brief-outage
EOF
}
case "$1" in
-v|--version) echo "$progname @VERSION@-@BUILD_VERSION@"; exit 0;;
--features) echo "@VERSION@-@BUILD_VERSION@: @PCMK_FEATURES@"; exit 0;;
--|-h|--help) usage; exit 0;;
esac
# Prefer helpers in the same directory if they exist, to simplify development
if [ ! -f $report_data/report.common ]; then
report_data=@datadir@/@PACKAGE@
else
echo "Using local helpers"
fi
. $report_data/report.common
while true; do
case "$1" in
-x) set -x; shift;;
-V) verbose=`expr $verbose + 1`; shift;;
-T|--cts-test) tests="$tests $2"; shift; shift;;
--cts-log) ctslog="$2"; shift; shift;;
-f|--from) start_time=`get_time "$2"`; shift; shift;;
-t|--to) end_time=`get_time "$2"`; shift; shift;;
-n|--node|--nodes) nodes="$nodes $2"; shift; shift;;
-S|--single-node) nodes="$host"; shift;;
-E|-l|--logfile) extra_logs="$extra_logs $2"; shift; shift;;
-p) sanitize_patterns="$sanitize_patterns $2"; shift; shift;;
-L) log_patterns="$log_patterns `echo $2 | sed 's/ /\\\W/g'`"; shift; shift;;
-d|--as-directory) compress=0; shift;;
-C|--corosync) cluster="corosync"; shift;;
-c|--cluster) cluster="$2"; shift; shift;;
-e|--rsh) rsh="$2"; shift; shift;;
-u|--user) ssh_user="$2"; shift; shift;;
-D|--max-depth) maxdepth="$2"; shift; shift;;
-M) search_logs=0; shift;;
--sos-mode) search_logs=0; nodes="$host"; shift;;
--dest) DESTDIR=$2; shift; shift;;
--) if [ ! -z $2 ]; then DESTDIR=$2; fi; break;;
-h|--help) usage; exit 0;;
# Options for compatibility with hb_report
-s) shift;;
*) echo "Unknown argument: $1"; usage; exit 1;;
esac
done
collect_data() {
label="$1"
start=`expr $2 - 10`
end=`expr $3 + 10`
masterlog=$4
if [ "x$DESTDIR" != x ]; then
echo $DESTDIR | grep -e "^/" -qs
if [ $? = 0 ]; then
l_base=$DESTDIR
else
l_base="`pwd`/$DESTDIR"
fi
debug "Using custom scratch dir: $l_base"
r_base=`basename $l_base`
else
l_base=$HOME/$label
r_base=$label
fi
if [ -e $l_base ]; then
fatal "Output directory $l_base already exists, specify an alternate name with --dest"
fi
mkdir -p $l_base
if [ "x$masterlog" != "x" ]; then
dumplogset "$masterlog" $start $end > "$l_base/$HALOG_F"
fi
for node in $nodes; do
cat <<EOF >$l_base/.env
LABEL="$label"
REPORT_HOME="$r_base"
REPORT_MASTER="$host"
REPORT_TARGET="$node"
LOG_START=$start
LOG_END=$end
REMOVE=1
SANITIZE="$sanitize_patterns"
CLUSTER=$cluster
LOG_PATTERNS="$log_patterns"
EXTRA_LOGS="$extra_logs"
SEARCH_LOGS=$search_logs
verbose=$verbose
maxdepth=$maxdepth
EOF
if [ $host = $node ]; then
cat <<EOF >>$l_base/.env
REPORT_HOME="$l_base"
EOF
cat $l_base/.env $report_data/report.common $report_data/report.collector > $l_base/collector
bash $l_base/collector
else
cat $l_base/.env $report_data/report.common $report_data/report.collector \
| $rsh -l $ssh_user $node -- "mkdir -p $r_base; cat > $r_base/collector; bash $r_base/collector" | (cd $l_base && tar mxf -)
fi
done
analyze $l_base > $l_base/$ANALYSIS_F
if [ -f $l_base/$HALOG_F ]; then
node_events $l_base/$HALOG_F > $l_base/$EVENTS_F
fi
for node in $nodes; do
cat $l_base/$node/$ANALYSIS_F >> $l_base/$ANALYSIS_F
if [ -s $l_base/$node/$EVENTS_F ]; then
cat $l_base/$node/$EVENTS_F >> $l_base/$EVENTS_F
elif [ -s $l_base/$HALOG_F ]; then
awk "\$4==\"$nodes\"" $l_base/$EVENTS_F >> $l_base/$n/$EVENTS_F
fi
done
log " "
if [ $compress = 1 ]; then
fname=`shrink $l_base`
rm -rf $l_base
log "Collected results are available in $fname"
log " "
log "Please create a bug entry at"
log " http://bugs.clusterlabs.org/enter_bug.cgi?product=Pacemaker"
log "Include a description of your problem and attach this tarball"
log " "
log "Thank you for taking time to create this report."
else
log "Collected results are available in $l_base"
fi
log " "
}
#
# check if files have same content in the cluster
#
cibdiff() {
d1=`dirname $1`
d2=`dirname $2`
if [ -f $d1/RUNNING -a -f $d2/RUNNING ] ||
[ -f $d1/STOPPED -a -f $d2/STOPPED ]; then
if which crm_diff > /dev/null 2>&1; then
crm_diff -c -n $1 -o $2
else
info "crm_diff(8) not found, cannot diff CIBs"
fi
else
echo "can't compare cibs from running and stopped systems"
fi
}
diffcheck() {
[ -f "$1" ] || {
echo "$1 does not exist"
return 1
}
[ -f "$2" ] || {
echo "$2 does not exist"
return 1
}
case `basename $1` in
$CIB_F) cibdiff $1 $2;;
$B_CONF) diff -u $1 $2;; # confdiff?
*) diff -u $1 $2;;
esac
}
#
# remove duplicates if files are same, make links instead
#
consolidate() {
for n in $NODES; do
if [ -f $1/$2 ]; then
rm $1/$n/$2
else
mv $1/$n/$2 $1
fi
ln -s ../$2 $1/$n
done
}
analyze_one() {
rc=0
node0=""
for n in $NODES; do
if [ "$node0" ]; then
diffcheck $1/$node0/$2 $1/$n/$2
rc=$(($rc+$?))
else
node0=$n
fi
done
return $rc
}
analyze() {
flist="$MEMBERSHIP_F $CIB_F $CRM_MON_F $B_CONF $SYSINFO_F"
for f in $flist; do
printf "Diff $f... "
ls $1/*/$f >/dev/null 2>&1 || {
echo "no $1/*/$f :/"
continue
}
if analyze_one $1 $f; then
echo "OK"
[ "$f" != $CIB_F ] && consolidate $1 $f
else
echo ""
fi
done
}
do_cts() {
test_sets=`echo $tests | tr ',' ' '`
for test_set in $test_sets; do
start_time=0
start_test=`echo $test_set | tr '-' ' ' | awk '{print $1}'`
end_time=0
end_test=`echo $test_set | tr '-' ' ' | awk '{print $2}'`
if [ x$end_test = x ]; then
msg="Extracting test $start_test"
label="CTS-$start_test-`date +"%b-%d-%Y"`"
end_test=`expr $start_test + 1`
else
msg="Extracting tests $start_test to $end_test"
label="CTS-$start_test-$end_test-`date +"%b-%d-%Y"`"
end_test=`expr $end_test + 1`
fi
if [ $start_test = 0 ]; then
start_pat="BEGINNING [0-9].* TESTS"
else
start_pat="Running test.*\[ *$start_test\]"
fi
if [ x$ctslog = x ]; then
ctslog=`findmsg 1 "$start_pat"`
if [ x$ctslog = x ]; then
fatal "No CTS control file detected"
else
log "Using CTS control file: $ctslog"
fi
fi
line=`grep -n "$start_pat" $ctslog | tail -1 | sed 's/:.*//'`
if [ ! -z "$line" ]; then
start_time=`linetime $ctslog $line`
fi
line=`grep -n "Running test.*\[ *$end_test\]" $ctslog | tail -1 | sed 's/:.*//'`
if [ ! -z "$line" ]; then
end_time=`linetime $ctslog $line`
fi
if [ -z "$nodes" ]; then
nodes=`grep CTS: $ctslog | grep -v debug: | grep " \* " | sed s:.*\\\*::g | sort -u | tr '\\n' ' '`
log "Calculated node list: $nodes"
fi
if [ $end_time -lt $start_time ]; then
debug "Test didn't complete, grabbing everything up to now"
end_time=`date +%s`
fi
if [ $start_time != 0 ];then
log "$msg (`time2str $start_time` to `time2str $end_time`)"
collect_data $label $start_time $end_time $ctslog
else
fatal "$msg failed: not found"
fi
done
}
node_names_from_xml() {
awk '
/uname/ {
for( i=1; i<=NF; i++ )
if( $i~/^uname=/ ) {
sub("uname=.","",$i);
sub("\".*","",$i);
print $i;
next;
}
}
' | tr '\n' ' '
}
getnodes() {
cluster="$1"
# 1. Live (cluster nodes or Pacemaker Remote nodes)
# TODO: This will not detect Pacemaker Remote nodes unless they
# have ever had a permanent node attribute set, because it only
# searches the nodes section. It should also search the config
# for resources that create Pacemaker Remote nodes.
cib_nodes=$(cibadmin -Ql -o nodes 2>/dev/null)
if [ $? -eq 0 ]; then
debug "Querying CIB for nodes"
echo "$cib_nodes" | node_names_from_xml
return
fi
# 2. Saved
if [ -f "@CRM_CONFIG_DIR@/cib.xml" ]; then
debug "Querying on-disk CIB for nodes"
grep "node " "@CRM_CONFIG_DIR@/cib.xml" | node_names_from_xml
return
fi
# 3. logs
# TODO: Look for something like crm_update_peer
}
if [ "x$tests" != "x" ]; then
do_cts
elif [ "x$start_time" != "x" ]; then
masterlog=""
if [ -z "$sanitize_patterns" ]; then
log "WARNING: The tarball produced by this program may contain"
log " sensitive information such as passwords."
log ""
log "We will attempt to remove such information if you use the"
log "-p option. For example: -p \"pass.*\" -p \"user.*\""
log ""
log "However, doing this may reduce the ability for the recipients"
log "to diagnose issues and generally provide assistance."
log ""
log "IT IS YOUR RESPONSIBILITY TO PROTECT SENSITIVE DATA FROM EXPOSURE"
log ""
fi
# If user didn't specify a cluster stack, make a best guess if possible.
if [ -z "$cluster" ] || [ "$cluster" = "any" ]; then
cluster=$(get_cluster_type)
fi
# If user didn't specify node(s), make a best guess if possible.
if [ -z "$nodes" ]; then
nodes=`getnodes $cluster`
if [ -n "$nodes" ]; then
log "Calculated node list: $nodes"
else
fatal "Cannot determine nodes; specify --nodes or --single-node"
fi
fi
if
echo $nodes | grep -qs $host
then
debug "We are a cluster node"
else
debug "We are a log master"
masterlog=`findmsg 1 "crmd\\|CTS"`
fi
if [ -z $end_time ]; then
end_time=`perl -e 'print time()'`
fi
label="pcmk-`date +"%a-%d-%b-%Y"`"
log "Collecting data from $nodes (`time2str $start_time` to `time2str $end_time`)"
collect_data $label $start_time $end_time $masterlog
else
fatal "Not sure what to do, no tests or time ranges to extract"
fi
# vim: set expandtab tabstop=8 softtabstop=4 shiftwidth=4 textwidth=80:
diff --git a/tools/crm_standby b/tools/crm_standby.in
similarity index 98%
rename from tools/crm_standby
rename to tools/crm_standby.in
index 59e16f8232..b8222aede6 100755
--- a/tools/crm_standby
+++ b/tools/crm_standby.in
@@ -1,150 +1,150 @@
-#!/bin/bash
+#!@BASH_PATH@
USAGE_TEXT="Usage: crm_standby <command> [options]
Common options:
--help Display this text, then exit
--version Display version information, then exit
-V, --verbose Specify multiple times to increase debug output
-q, --quiet Print only the standby status (if querying)
Commands:
-G, --query Query the current value of standby mode (on/off)
-v, --update=VALUE Update the value of standby mode (on/off)
-D, --delete Let standby mode use default value
Additional Options:
-N, --node=NODE Operate on the named node instead of the current one
-l, --lifetime=VALUE Until when should the setting take effect
(valid values: reboot, forever)
-i, --id=VALUE (Advanced) XML ID used to identify standby attribute"
HELP_TEXT="crm_standby - Query, enable, or disable standby mode for a node
Nodes in standby mode may not host cluster resources.
$USAGE_TEXT
"
exit_usage() {
if [ $# -gt 0 ]; then
echo "error: $@" >&2
fi
echo
echo "$USAGE_TEXT"
exit 1
}
op=""
options=""
lifetime=0
target=""
SHORTOPTS_DEPRECATED="U:Q"
LONGOPTS_DEPRECATED="uname:,get-value,delete-attr,attr-value:,attr-id:"
SHORTOPTS="VqGv:DN:l:i:"
LONGOPTS="help,version,verbose,quiet,query,update:,delete,node:,lifetime:,id:"
-TEMP=$(getopt -o ${SHORTOPTS}${SHORTOPTS_DEPRECATED} \
+TEMP=$(@GETOPT_PATH@ -o ${SHORTOPTS}${SHORTOPTS_DEPRECATED} \
--long ${LONGOPTS},${LONGOPTS_DEPRECATED} \
-n crm_standby -- "$@")
if [ $? -ne 0 ]; then
exit_usage
fi
eval set -- "$TEMP" # Quotes around $TEMP are essential
while true ; do
case "$1" in
--help)
echo "$HELP_TEXT"
exit 0
;;
--version)
crm_attribute --version
exit 0
;;
-q|--quiet|-V|--verbose|-Q)
options="$options $1"
shift
;;
-N|--node|-U|--uname)
target="$2"
shift
shift
;;
-G|--query|--get-value)
options="$options --query"
op=g
shift
;;
-v|--update|--attr-value)
options="$options --update $2"
op=u
shift
shift
;;
-D|--delete|--delete-attr)
options="$options --delete"
op=d
shift
;;
-l|--lifetime)
options="$options --lifetime $2"
lifetime=1
shift
shift
;;
-i|--id|--attr-id)
options="$options --id $2"
shift
shift
;;
--)
shift
break
;;
*)
exit_usage "unknown option '$1'"
;;
esac
done
# It's important to call cluster commands only after arguments are processed,
# so --version and --help work without problems even if those commands don't.
if [ "$target" = "" ]; then
target=$(crm_node -n)
fi
options="-N $target -n standby $options"
if [ x$op = x ]; then
options="$options -G"; op=g
fi
# If the user didn't explicitly specify a lifetime ...
if [ $lifetime -eq 0 ]; then
case $op in
g)
# For query, report the forever entry if one exists, otherwise
# report the reboot entry if one exists, otherwise report off.
crm_attribute $options -l forever 2>&1 > /dev/null
if [ $? -eq 0 ]; then
options="$options -l forever"
else
options="$options -l reboot -d off"
fi
;;
u)
# For update, default to updating the forever entry.
options="$options -l forever"
;;
d)
# For delete, default to deleting both forever and reboot entries.
crm_attribute $options -l forever
crm_attribute $options -l reboot
exit 0
;;
esac
fi
crm_attribute $options

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jul 8, 6:27 PM (12 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2002647
Default Alt Text
(268 KB)

Event Timeline