Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/configure.ac b/configure.ac
index b867da44da..015ccd518f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,1939 +1,1980 @@
dnl
dnl autoconf for Pacemaker
dnl
dnl License: GNU General Public License (GPL)
dnl ===============================================
dnl Bootstrap
dnl ===============================================
AC_PREREQ(2.59)
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, [pacemaker@oss.clusterlabs.org],
[pacemaker], PCMK_URL)
dnl Workaround autoconf < 2.64
if test x"${PACKAGE_URL}" = x""; then
AC_SUBST([PACKAGE_URL], PCMK_URL)
fi
PCMK_FEATURES=""
HB_PKG=heartbeat
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 lha_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)
ALL_LINGUAS="en fr"
AC_ARG_WITH(version,
[ --with-version=version Override package version (if you're a packager needing to pretend) ],
[ PACKAGE_VERSION="$withval" ])
AC_ARG_WITH(pkg-name,
[ --with-pkg-name=name Override package name (if you're a packager needing to pretend) ],
[ PACKAGE_NAME="$withval" ])
dnl Older distros may need: AM_INIT_AUTOMAKE($PACKAGE_NAME, $PACKAGE_VERSION)
AM_INIT_AUTOMAKE([foreign])
AC_DEFINE_UNQUOTED(PACEMAKER_VERSION, "$PACKAGE_VERSION", Current pacemaker version)
PACKAGE_SERIES=`echo $PACKAGE_VERSION | awk -F. '{ print $1"."$2 }'`
AC_SUBST(PACKAGE_SERIES)
AC_SUBST(PACKAGE_VERSION)
dnl automake >= 1.11 offers --enable-silent-rules for suppressing the output from
dnl normal compilation. When a failure occurs, it will then display the full
dnl command line
dnl Wrap in m4_ifdef to avoid breaking on older platforms
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
dnl Example 2.4. Silent Custom Rule to Generate a File
dnl %-bar.pc: %.pc
dnl $(AM_V_GEN)$(LN_S) $(notdir $^) $@
CC_IN_CONFIGURE=yes
export CC_IN_CONFIGURE
LDD=ldd
BUILD_ATOMIC_ATTRD=1
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
AC_LIBTOOL_DLOPEN dnl Enable dlopen support...
AC_LIBLTDL_CONVENIENCE dnl make libltdl a convenience lib
AC_PROG_LIBTOOL
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
}
try_extract_header_define() {
AC_MSG_CHECKING(if $2 in $1 exists)
Cfile=$srcdir/extract_define.$2.${$}
printf "#include <stdio.h>\n" > ${Cfile}.c
printf "#include <%s>\n" $1 >> ${Cfile}.c
printf "int main(int argc, char **argv) {\n" >> ${Cfile}.c
printf "#ifdef %s\n" $2 >> ${Cfile}.c
printf "printf(\"%%s\", %s);\n" $2 >> ${Cfile}.c
printf "#endif \n return 0; }\n" >> ${Cfile}.c
$CC $CFLAGS ${Cfile}.c -o ${Cfile} 2>/dev/null
value=
if test -x ${Cfile}; then
value=`${Cfile} 2>/dev/null`
fi
if test x"${value}" == x""; then
value=$3
AC_MSG_RESULT(default: $value)
else
AC_MSG_RESULT($value)
fi
printf $value
rm -rf ${Cfile}.c ${Cfile} ${Cfile}.dSYM ${Cfile}.gcno
}
extract_header_define() {
AC_MSG_CHECKING(for $2 in $1)
Cfile=$srcdir/extract_define.$2.${$}
printf "#include <stdio.h>\n" > ${Cfile}.c
printf "#include <%s>\n" $1 >> ${Cfile}.c
printf "int main(int argc, char **argv) { printf(\"%%s\", %s); return 0; }\n" $2 >> ${Cfile}.c
$CC $CFLAGS ${Cfile}.c -o ${Cfile}
value=`${Cfile}`
AC_MSG_RESULT($value)
printf $value
rm -rf ${Cfile}.c ${Cfile} ${Cfile}.dSYM ${Cfile}.gcno
}
dnl ===============================================
dnl Configure Options
dnl ===============================================
dnl Some systems, like Solaris require a custom package name
AC_ARG_WITH(pkgname,
[ --with-pkgname=name name for pkg (typically for Solaris) ],
[ PKGNAME="$withval" ],
[ PKGNAME="LXHAhb" ],
)
AC_SUBST(PKGNAME)
AC_ARG_ENABLE([ansi],
[ --enable-ansi force GCC to compile to ANSI/ANSI standard for older compilers.
[default=no]])
AC_ARG_ENABLE([fatal-warnings],
[ --enable-fatal-warnings very pedantic and fatal warnings for gcc
[default=yes]])
AC_ARG_ENABLE([quiet],
[ --enable-quiet
Supress make output unless there is an error
[default=no]])
AC_ARG_ENABLE([thread-safe],
[ --enable-thread-safe Enable some client libraries to be thread safe.
[default=no]])
AC_ARG_ENABLE([bundled-ltdl],
[ --enable-bundled-ltdl Configure, build and install the standalone ltdl library bundled with ${PACKAGE} [default=no]])
LTDL_LIBS=""
AC_ARG_ENABLE([no-stack],
[ --enable-no-stack
Only build the Policy Engine and pieces needed to support it [default=no]])
AC_ARG_ENABLE([upstart],
[ --enable-upstart
Do not build support for the Upstart init system [default=yes]])
AC_ARG_ENABLE([systemd],
[ --enable-systemd
Do not build support for the Systemd init system [default=yes]])
AC_ARG_WITH(ais,
[ --with-ais
Support the Corosync messaging and membership layer ],
[ SUPPORT_CS=$withval ],
[ SUPPORT_CS=try ],
)
AC_ARG_WITH(corosync,
[ --with-corosync
Support the Corosync messaging and membership layer ],
[ SUPPORT_CS=$withval ]
dnl initialized in AC_ARG_WITH(ais...) already,
dnl don't reset to try if it was given as --without-ais
)
AC_ARG_WITH(heartbeat,
[ --with-heartbeat
Support the Heartbeat messaging and membership layer ],
[ SUPPORT_HEARTBEAT=$withval ],
[ SUPPORT_HEARTBEAT=try ],
)
AC_ARG_WITH(cman,
[ --with-cman
Support the consumption of membership and quorum from cman ],
[ SUPPORT_CMAN=$withval ],
[ SUPPORT_CMAN=try ],
)
AC_ARG_WITH(cpg,
[ --with-cs-quorum
Support the consumption of membership and quorum from corosync ],
[ SUPPORT_CS_QUORUM=$withval ],
[ SUPPORT_CS_QUORUM=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(snmp,
[ --with-snmp
Support the SNMP protocol ],
[ SUPPORT_SNMP=$withval ],
[ SUPPORT_SNMP=try ],
)
AC_ARG_WITH(esmtp,
[ --with-esmtp
Support the sending mail notifications with the esmtp library ],
[ SUPPORT_ESMTP=$withval ],
[ SUPPORT_ESMTP=try ],
)
AC_ARG_WITH(acl,
[ --with-acl
Support CIB ACL ],
[ SUPPORT_ACL=$withval ],
[ SUPPORT_ACL=yes ],
)
AC_ARG_WITH(cibsecrets,
[ --with-cibsecrets
Support CIB secrets ],
[ SUPPORT_CIBSECRETS=$withval ],
[ SUPPORT_CIBSECRETS=no ],
)
CSPREFIX=""
AC_ARG_WITH(ais-prefix,
[ --with-ais-prefix=DIR Prefix used when Corosync was installed [$prefix]],
[ CSPREFIX=$withval ],
[ CSPREFIX=$prefix ])
LCRSODIR=""
AC_ARG_WITH(lcrso-dir,
[ --with-lcrso-dir=DIR Corosync lcrso files. ],
[ LCRSODIR="$withval" ])
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 [$PUBLICAN_BRAND]],
[ PUBLICAN_BRAND="$withval" ])
AC_SUBST(PUBLICAN_BRAND)
ASCIIDOC_CLI_TYPE="pcs"
AC_ARG_WITH(doc-cli,
[ --with-doc-cli=cli_type CLI type to use for generated documentation. [$ASCIIDOC_CLI_TYPE]],
[ ASCIIDOC_CLI_TYPE="$withval" ])
AC_SUBST(ASCIIDOC_CLI_TYPE)
dnl ===============================================
dnl General Processing
dnl ===============================================
AC_SUBST(HB_PKG)
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
dnl For consistency with Heartbeat, map NONE->$prefix
NONE) exec_prefix=$prefix;;
prefix) exec_prefix=$prefix;;
esac
AC_MSG_NOTICE(Sanitizing ais_prefix: ${CSPREFIX})
case $CSPREFIX in
dnl For consistency with Heartbeat, map NONE->$prefix
NONE) CSPREFIX=$prefix;;
prefix) CSPREFIX=$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
dnl For consistency with Heartbeat, map NONE->$prefix
prefix|NONE)
AC_MSG_CHECKING(which lib directory to use)
for aDir in lib64 lib
do
trydir="${exec_prefix}/${aDir}"
if
test -d ${trydir}
then
libdir=${trydir}
break
fi
done
AC_MSG_RESULT($libdir);
;;
esac
dnl Expand autoconf variables so that we dont end up with '${prefix}'
dnl in #defines and python scripts
dnl NOTE: Autoconf deliberately leaves them unexpanded to allow
dnl make exec_prefix=/foo install
dnl No longer being able to do this seems like no great loss to me...
eval prefix="`eval echo ${prefix}`"
eval exec_prefix="`eval echo ${exec_prefix}`"
eval bindir="`eval echo ${bindir}`"
eval sbindir="`eval echo ${sbindir}`"
eval libexecdir="`eval echo ${libexecdir}`"
eval datadir="`eval echo ${datadir}`"
eval sysconfdir="`eval echo ${sysconfdir}`"
eval sharedstatedir="`eval echo ${sharedstatedir}`"
eval localstatedir="`eval echo ${localstatedir}`"
eval libdir="`eval echo ${libdir}`"
eval includedir="`eval echo ${includedir}`"
eval oldincludedir="`eval echo ${oldincludedir}`"
eval infodir="`eval echo ${infodir}`"
eval mandir="`eval echo ${mandir}`"
dnl Home-grown variables
eval INITDIR="${INITDIR}"
eval docdir="`eval echo ${docdir}`"
if test x"${docdir}" = x""; then
docdir=${datadir}/doc/${PACKAGE}-${VERSION}
#docdir=${datadir}/doc/packages/${PACKAGE}
fi
AC_SUBST(docdir)
for j in prefix exec_prefix bindir sbindir libexecdir datadir sysconfdir \
sharedstatedir localstatedir libdir includedir oldincludedir infodir \
mandir INITDIR docdir
do
dirname=`eval echo '${'${j}'}'`
if
test ! -d "$dirname"
then
AC_MSG_WARN([$j directory ($dirname) does not exist!])
fi
done
dnl This OS-based decision-making is poor autotools practice;
dnl feature-based mechanisms are strongly preferred.
dnl
dnl So keep this section to a bare minimum; regard as a "necessary evil".
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
dnl Eventually remove this
if test "$cross_compiling" != "yes"; then
CPPFLAGS="$CPPFLAGS -I${prefix}/include/heartbeat"
fi
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"
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
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)
AM_PATH_PYTHON
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)
AC_PATH_PROGS(TEST, test)
AC_PATH_PROGS(PKGCONFIG, pkg-config)
AC_PATH_PROGS(XML2CONFIG, xml2-config)
AC_PATH_PROGS(VALGRIND_BIN, valgrind, /usr/bin/valgrind)
AC_DEFINE_UNQUOTED(VALGRIND_BIN, "$VALGRIND_BIN", Valgrind command)
dnl Disable these until we decide if the stonith config file should be supported
dnl AC_PATH_PROGS(BISON, bison)
dnl AC_PATH_PROGS(FLEX, flex)
dnl AC_PATH_PROGS(HAVE_YACC, $YACC)
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
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
SUPPORT_STONITH_CONFIG=0
if test x"${HAVE_YACC}" != x"" -a x"${FLEX}" != x"" -a x"${BISON}" != x""; then
SUPPORT_STONITH_CONFIG=1
PCMK_FEATURES="$PCMK_FEATURES st-conf"
fi
AM_CONDITIONAL(BUILD_STONITH_CONFIG, test $SUPPORT_STONITH_CONFIG = 1)
AC_DEFINE_UNQUOTED(SUPPORT_STONITH_CONFIG, $SUPPORT_STONITH_CONFIG, Support a stand-alone stonith config file in addition to the CIB)
AM_CONDITIONAL(BUILD_DOCBOOK, test x"${PUBLICAN}" != x"" -a x"${INKSCAPE}" != x"")
if test x"${PUBLICAN}" != x"" -a x"${INKSCAPE}" != x""; then
AC_MSG_NOTICE(Enabling publican)
PCMK_FEATURES="$PCMK_FEATURES publican-docs"
fi
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"${PKGCONFIG}" = x""; then
AC_MSG_ERROR(You need pkgconfig installed in order to build ${PACKAGE})
fi
if test "x${enable_thread_safe}" = "xyes"; then
GPKGNAME="gthread-2.0"
else
GPKGNAME="glib-2.0"
fi
if
$PKGCONFIG --exists $GPKGNAME
then
GLIBCONFIG="$PKGCONFIG $GPKGNAME"
else
set -x
echo PKG_CONFIG_PATH=$PKG_CONFIG_PATH
$PKGCONFIG --exists $GPKGNAME; echo $?
$PKGCONFIG --cflags $GPKGNAME; echo $?
$PKGCONFIG $GPKGNAME; 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
dnl
dnl Check for location of gettext
dnl
dnl On at least Solaris 2.x, where it is in libc, specifying lintl causes
dnl grief. Ensure minimal result, not the sum of all possibilities.
dnl And do libc first.
dnl Known examples:
dnl c: Linux, Solaris 2.6+
dnl intl: BSD, AIX
AC_CHECK_LIB(c, gettext)
if test x$ac_cv_lib_c_gettext != xyes; then
AC_CHECK_LIB(intl, gettext)
fi
if test x$ac_cv_lib_c_gettext != xyes -a x$ac_cv_lib_intl_gettext != xyes; then
AC_MSG_ERROR(You need gettext installed in order to build ${PACKAGE})
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
AC_CHECK_HEADERS(arpa/inet.h)
AC_CHECK_HEADERS(asm/types.h)
AC_CHECK_HEADERS(assert.h)
AC_CHECK_HEADERS(auth-client.h)
AC_CHECK_HEADERS(ctype.h)
AC_CHECK_HEADERS(dirent.h)
AC_CHECK_HEADERS(errno.h)
AC_CHECK_HEADERS(fcntl.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/errqueue.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(pam/pam_appl.h)
AC_CHECK_HEADERS(pthread.h)
AC_CHECK_HEADERS(pwd.h)
AC_CHECK_HEADERS(security/pam_appl.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/poll.h)
AC_CHECK_HEADERS(sys/reboot.h)
AC_CHECK_HEADERS(sys/resource.h)
AC_CHECK_HEADERS(sys/select.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/uio.h)
AC_CHECK_HEADERS(sys/un.h)
AC_CHECK_HEADERS(sys/utsname.h)
AC_CHECK_HEADERS(sys/wait.h)
AC_CHECK_HEADERS(time.h)
AC_CHECK_HEADERS(unistd.h)
AC_CHECK_HEADERS(winsock.h)
dnl These headers need prerequisits before the tests will pass
dnl AC_CHECK_HEADERS(net/if.h)
dnl AC_CHECK_HEADERS(netinet/icmp6.h)
dnl AC_CHECK_HEADERS(netinet/ip6.h)
dnl AC_CHECK_HEADERS(netinet/ip_icmp.h)
AC_MSG_CHECKING(for special libxml2 includes)
if test "x$XML2CONFIG" = "x"; then
AC_MSG_ERROR(libxml2 config not found)
else
XML2HEAD="`$XML2CONFIG --cflags`"
AC_MSG_RESULT($XML2HEAD)
AC_CHECK_LIB(xml2, xmlReadMemory)
AC_CHECK_LIB(xslt, xsltApplyStylesheet)
fi
CPPFLAGS="$CPPFLAGS $XML2HEAD"
AC_CHECK_HEADERS(libxml/xpath.h)
AC_CHECK_HEADERS(libxslt/xslt.h)
if test "$ac_cv_header_libxml_xpath_h" != "yes"; then
AC_MSG_ERROR(The libxml developement headers were not found)
fi
if test "$ac_cv_header_libxslt_xslt_h" != "yes"; then
AC_MSG_ERROR(The libxslt developement headers were not found)
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(g_log_set_default_handler)
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 ltdl
dnl ========================================================================
AC_CHECK_LIB(ltdl, lt_dlopen, [LTDL_foo=1])
if test "x${enable_bundled_ltdl}" = "xyes"; then
if test $ac_cv_lib_ltdl_lt_dlopen = yes; then
AC_MSG_NOTICE([Disabling usage of installed ltdl])
fi
ac_cv_lib_ltdl_lt_dlopen=no
fi
LIBLTDL_DIR=""
if test $ac_cv_lib_ltdl_lt_dlopen != yes ; then
AC_MSG_NOTICE([Installing local ltdl])
LIBLTDL_DIR=libltdl
( cd $srcdir ; $TAR -xvf libltdl.tar )
if test "$?" -ne 0; then
AC_MSG_ERROR([$TAR of libltdl.tar in $srcdir failed])
fi
AC_CONFIG_SUBDIRS(libltdl)
else
LIBS="$LIBS -lltdl"
AC_MSG_NOTICE([Using installed ltdl])
INCLTDL=""
LIBLTDL=""
fi
AC_SUBST(INCLTDL)
AC_SUBST(LIBLTDL)
AC_SUBST(LIBLTDL_DIR)
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=`$PKGCONFIG --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=`$PKGCONFIG --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
ac_save_LIBS=$LIBS
LIBS="$CURSESLIBS"
ac_save_CFLAGS=$CFLAGS
CFLAGS="-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
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
dnl Enable gprof
#LIBS="$LIBS -pg"
#CFLAGS="$CFLAGS -pg"
;;
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 - Heartbeat / LibQB
dnl ========================================================================
dnl Compatability checks
AC_CHECK_MEMBERS([struct lrm_ops.fail_rsc],,,[[#include <lrm/lrm_api.h>]])
if test x${enable_no_stack} = xyes; then
SUPPORT_HEARTBEAT=no
SUPPORT_CS=no
fi
PKG_CHECK_MODULES(libqb, libqb >= 0.13, HAVE_libqb=1)
CPPFLAGS="$libqb_CFLAGS $CPPFLAGS"
LIBS="$libqb_LIBS $LIBS"
AC_CHECK_HEADERS(qb/qbipc_common.h)
AC_CHECK_LIB(qb, qb_ipcs_connection_auth_set)
PCMK_FEATURES="$PCMK_FEATURES libqb-logging libqb-ipc"
AC_CHECK_FUNCS(qb_ipcs_connection_get_buffer_size, AC_DEFINE(HAVE_IPCS_GET_BUFFER_SIZE, 1, [Have qb_ipcc_get_buffer_size function]))
AC_CHECK_HEADERS(heartbeat/hb_config.h)
AC_CHECK_HEADERS(heartbeat/glue_config.h)
AC_CHECK_HEADERS(stonith/stonith.h)
AC_CHECK_HEADERS(agent_config.h)
GLUE_HEADER=none
HAVE_GLUE=0
if test "$ac_cv_header_heartbeat_glue_config_h" = "yes"; then
GLUE_HEADER=glue_config.h
HAVE_GLUE=1
elif test "$ac_cv_header_heartbeat_hb_config_h" = "yes"; then
GLUE_HEADER=hb_config.h
HAVE_GLUE=1
else
AC_MSG_WARN(cluster-glue development headers were not found)
fi
if test "$ac_cv_header_stonith_stonith_h" = "yes"; then
PCMK_FEATURES="$PCMK_FEATURES lha-fencing"
fi
if test $HAVE_GLUE = 1; 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)
fi
dnl ===============================================
dnl Variables needed for substitution
dnl ===============================================
CRM_DTD_DIRECTORY="${datadir}/pacemaker"
AC_DEFINE_UNQUOTED(CRM_DTD_DIRECTORY,"$CRM_DTD_DIRECTORY", Location for the Pacemaker Relax-NG Schema)
AC_SUBST(CRM_DTD_DIRECTORY)
CRM_CORE_DIR=`try_extract_header_define $GLUE_HEADER HA_COREDIR ${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=`try_extract_header_define $GLUE_HEADER HA_CCMUSER hacluster`
AC_DEFINE_UNQUOTED(CRM_DAEMON_USER,"$CRM_DAEMON_USER", User to run Pacemaker daemons as)
AC_SUBST(CRM_DAEMON_USER)
CRM_DAEMON_GROUP=`try_extract_header_define $GLUE_HEADER HA_APIGROUP 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_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_LEGACY_CONFIG_DIR="${localstatedir}/lib/heartbeat/crm"
AC_DEFINE_UNQUOTED(CRM_LEGACY_CONFIG_DIR,"$CRM_LEGACY_CONFIG_DIR", Where Pacemaker used to keep configuration files)
AC_SUBST(CRM_LEGACY_CONFIG_DIR)
CRM_DAEMON_DIR="${libexecdir}/pacemaker"
AC_DEFINE_UNQUOTED(CRM_DAEMON_DIR,"$CRM_DAEMON_DIR", Location for Pacemaker daemons)
AC_SUBST(CRM_DAEMON_DIR)
HB_DAEMON_DIR=`try_extract_header_define $GLUE_HEADER HA_LIBHBDIR $libdir/heartbeat`
AC_DEFINE_UNQUOTED(HB_DAEMON_DIR,"$HB_DAEMON_DIR", Location Heartbeat expects Pacemaker daemons to be in)
AC_SUBST(HB_DAEMON_DIR)
dnl Needed so that the Corosync plugin can clear out the directory as Heartbeat does
HA_STATE_DIR=`try_extract_header_define $GLUE_HEADER HA_VARRUNDIR ${localstatedir}/run`
AC_DEFINE_UNQUOTED(HA_STATE_DIR,"$HA_STATE_DIR", Where Heartbeat keeps state files and sockets)
AC_SUBST(HA_STATE_DIR)
CRM_RSCTMP_DIR=`try_extract_header_define agent_config.h HA_RSCTMPDIR $HA_STATE_DIR/resource-agents`
AC_MSG_CHECKING(Scratch dir for resource agents)
AC_MSG_RESULT($CRM_RSCTMP_DIR)
AC_DEFINE_UNQUOTED(CRM_RSCTMP_DIR,"$CRM_RSCTMP_DIR", Where resource agents should keep state files)
AC_SUBST(CRM_RSCTMP_DIR)
dnl Needed for the location of hostcache in CTS.py
HA_VARLIBHBDIR=`try_extract_header_define $GLUE_HEADER HA_VARLIBHBDIR ${localstatedir}/lib/heartbeat`
AC_SUBST(HA_VARLIBHBDIR)
AC_DEFINE_UNQUOTED(UUID_FILE,"$localstatedir/lib/heartbeat/hb_uuid", Location of Heartbeat's UUID file)
OCF_ROOT_DIR=`try_extract_header_define $GLUE_HEADER 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=`try_extract_header_define $GLUE_HEADER 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)
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 `$PKGCONFIG --cflags dbus-1`"
fi
DBUS_LIBS="$CFLAGS `$PKGCONFIG --libs dbus-1`"
AC_SUBST(DBUS_LIBS)
AC_CHECK_TYPES([DBusBasicValue],,,[[#include <dbus/dbus.h>]])
if test $HAVE_dbus = 1 -a "x${enable_upstart}" != xno; 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)
if
$PKGCONFIG --exists systemd
then
systemdunitdir=`$PKGCONFIG --variable=systemdsystemunitdir systemd`
AC_SUBST(systemdunitdir)
else
enable_systemd=no
fi
if test $HAVE_dbus = 1 -a "x${enable_systemd}" != xno; then
if test -n "$systemdunitdir" -a "x$systemdunitdir" != xno; then
HAVE_systemd=1
PCMK_FEATURES="$PCMK_FEATURES systemd"
fi
fi
AC_DEFINE_UNQUOTED(SUPPORT_SYSTEMD, $HAVE_systemd, Support systemd based system services)
AM_CONDITIONAL(BUILD_SYSTEMD, test $HAVE_systemd = 1)
AC_SUBST(SUPPORT_SYSTEMD)
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 - Heartbeat
dnl ========================================================================
case $SUPPORT_HEARTBEAT in
1|yes|true|try)
AC_MSG_CHECKING(for heartbeat support)
AC_CHECK_LIB(hbclient, ll_cluster_new, [SUPPORT_HEARTBEAT=1],
[if test $SUPPORT_HEARTBEAT != try; then
AC_MSG_FAILURE(Unable to support Heartbeat: client libraries not found)
fi])
if test $SUPPORT_HEARTBEAT = 1 ; then
STACKS="$STACKS heartbeat"
dnl objdump -x ${libdir}/libccmclient.so | grep SONAME | awk '{print $2}'
AC_DEFINE_UNQUOTED(CCM_LIBRARY, "libccmclient.so.1", Library to load for ccm support)
AC_DEFINE_UNQUOTED(HEARTBEAT_LIBRARY, "libhbclient.so.1", Library to load for heartbeat support)
BUILD_ATOMIC_ATTRD=0
else
SUPPORT_HEARTBEAT=0
fi
;;
*) SUPPORT_HEARTBEAT=0;;
esac
AM_CONDITIONAL(BUILD_HEARTBEAT_SUPPORT, test $SUPPORT_HEARTBEAT = 1)
AC_DEFINE_UNQUOTED(SUPPORT_HEARTBEAT, $SUPPORT_HEARTBEAT, Support the Heartbeat messaging and membership layer)
AC_SUBST(SUPPORT_HEARTBEAT)
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=""
CS_USES_LIBQB=0
PCMK_SERVICE_ID=9
LCRSODIR="$libdir"
if test $SUPPORT_CS = no; then
AC_MSG_RESULT(no (disabled))
SUPPORT_CS=0
else
AC_MSG_RESULT($SUPPORT_CS, with '$CSPREFIX')
PKG_CHECK_MODULES(cpg, libcpg) dnl Fatal
PKG_CHECK_MODULES(cfg, libcfg) dnl Fatal
PKG_CHECK_MODULES(cmap, libcmap, HAVE_cmap=1, HAVE_cmap=0)
PKG_CHECK_MODULES(cman, libcman, HAVE_cman=1, HAVE_cman=0)
PKG_CHECK_MODULES(confdb, libconfdb, HAVE_confdb=1, HAVE_confdb=0)
PKG_CHECK_MODULES(fenced, libfenced, HAVE_fenced=1, HAVE_fenced=0)
PKG_CHECK_MODULES(quorum, libquorum, HAVE_quorum=1, HAVE_quorum=0)
PKG_CHECK_MODULES(oldipc, libcoroipcc, HAVE_oldipc=1, HAVE_oldipc=0)
if test $HAVE_oldipc = 1; then
SUPPORT_CS=1
CFLAGS="$CFLAGS $oldipc_FLAGS $cpg_FLAGS $cfg_FLAGS"
COROSYNC_LIBS="$COROSYNC_LIBS $oldipc_LIBS $cpg_LIBS $cfg_LIBS"
elif test $HAVE_libqb = 1; then
SUPPORT_CS=1
CS_USES_LIBQB=1
CFLAGS="$CFLAGS $libqb_FLAGS $cpg_FLAGS $cfg_FLAGS"
COROSYNC_LIBS="$COROSYNC_LIBS $libqb_LIBS $cpg_LIBS $cfg_LIBS"
AC_CHECK_LIB(corosync_common, cs_strerror)
else
aisreason="corosync/libqb IPC libraries not found by pkg_config"
fi
AC_DEFINE_UNQUOTED(HAVE_CONFDB, $HAVE_confdb, Have the old herarchial Corosync config API)
AC_DEFINE_UNQUOTED(HAVE_CMAP, $HAVE_cmap, Have the new non-herarchial Corosync config API)
fi
if test $SUPPORT_CS = 1 -a x$HAVE_oldipc = x0 ; then
dnl Support for plugins was removed about the time the IPC was
dnl moved to libqb.
dnl The only option now is the built-in quorum API
CFLAGS="$CFLAGS $cmap_CFLAGS $quorum_CFLAGS"
COROSYNC_LIBS="$COROSYNC_LIBS $cmap_LIBS $quorum_LIBS"
STACKS="$STACKS corosync-native"
AC_DEFINE_UNQUOTED(SUPPORT_CS_QUORUM, 1, Support the consumption of membership and quorum from corosync)
fi
SUPPORT_PLUGIN=0
if test $SUPPORT_CS = 1 -a x$HAVE_confdb = x1; then
dnl Need confdb to support cman and the plugins
SUPPORT_PLUGIN=1
BUILD_ATOMIC_ATTRD=0
LCRSODIR=`$PKGCONFIG corosync --variable=lcrsodir`
STACKS="$STACKS corosync-plugin"
COROSYNC_LIBS="$COROSYNC_LIBS $confdb_LIBS"
if test $SUPPORT_CMAN != no; then
if test $HAVE_cman = 1 -a $HAVE_fenced = 1; then
SUPPORT_CMAN=1
STACKS="$STACKS cman"
CFLAGS="$CFLAGS $cman_FLAGS $fenced_FLAGS"
COROSYNC_LIBS="$COROSYNC_LIBS $cman_LIBS $fenced_LIBS"
fi
fi
fi
dnl Normalize SUPPORT_CS and SUPPORT_CMAN for use with #if directives
if test $SUPPORT_CMAN != 1; then
SUPPORT_CMAN=0
fi
if test $SUPPORT_CS = 1; then
CLUSTERLIBS="$CLUSTERLIBS $COROSYNC_LIBS"
elif test $SUPPORT_CS != 0; then
SUPPORT_CS=0
if test $missingisfatal = 0; then
AC_MSG_WARN(Unable to support Corosync: $aisreason)
else
AC_MSG_FAILURE(Unable to support Corosync: $aisreason)
fi
fi
AC_DEFINE_UNQUOTED(SUPPORT_COROSYNC, $SUPPORT_CS, Support the Corosync messaging and membership layer)
AC_DEFINE_UNQUOTED(SUPPORT_CMAN, $SUPPORT_CMAN, Support the consumption of membership and quorum from cman)
AC_DEFINE_UNQUOTED(CS_USES_LIBQB, $CS_USES_LIBQB, Does corosync use libqb for its ipc)
AC_DEFINE_UNQUOTED(PCMK_SERVICE_ID, $PCMK_SERVICE_ID, Corosync service number)
AC_DEFINE_UNQUOTED(SUPPORT_PLUGIN, $SUPPORT_PLUGIN, Support the Pacemaker plugin for Corosync)
AM_CONDITIONAL(BUILD_CS_SUPPORT, test $SUPPORT_CS = 1)
AM_CONDITIONAL(BUILD_CS_PLUGIN, test $SUPPORT_PLUGIN = 1)
AM_CONDITIONAL(BUILD_CMAN, test $SUPPORT_CMAN = 1)
AM_CONDITIONAL(BUILD_ATOMIC_ATTRD, test $BUILD_ATOMIC_ATTRD = 1)
AC_DEFINE_UNQUOTED(HAVE_ATOMIC_ATTRD, $BUILD_ATOMIC_ATTRD, Support the new atomic attrd)
AC_SUBST(SUPPORT_CMAN)
AC_SUBST(SUPPORT_CS)
AC_SUBST(SUPPORT_PLUGIN)
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 (heartbeat or corosync) )
fi
AC_MSG_RESULT($STACKS)
PCMK_FEATURES="$PCMK_FEATURES $STACKS"
fi
if test ${BUILD_ATOMIC_ATTRD} = 1; then
PCMK_FEATURES="$PCMK_FEATURES atomic-attrd"
fi
AC_SUBST(CLUSTERLIBS)
AC_SUBST(LCRSODIR)
dnl ========================================================================
dnl SNMP
dnl ========================================================================
case $SUPPORT_SNMP in
1|yes|true) missingisfatal=1;;
try) missingisfatal=0;;
*) SUPPORT_SNMP=no;;
esac
SNMPLIBS=""
AC_MSG_CHECKING(for snmp support)
if test $SUPPORT_SNMP = no; then
AC_MSG_RESULT(no (disabled))
SUPPORT_SNMP=0
else
SNMPCONFIG=""
AC_MSG_RESULT($SUPPORT_SNMP)
AC_CHECK_HEADERS(net-snmp/net-snmp-config.h)
if test "x${ac_cv_header_net_snmp_net_snmp_config_h}" != "xyes"; then
SUPPORT_SNMP="no"
fi
if test $SUPPORT_SNMP != no; then
AC_PATH_PROGS(SNMPCONFIG, net-snmp-config)
if test "X${SNMPCONFIG}" = "X"; then
AC_MSG_RESULT(You need the net_snmp development package to continue.)
SUPPORT_SNMP=no
fi
fi
if test $SUPPORT_SNMP != no; then
AC_MSG_CHECKING(for special snmp libraries)
SNMPLIBS=`$SNMPCONFIG --agent-libs`
AC_MSG_RESULT($SNMPLIBS)
fi
if test $SUPPORT_SNMP != no; then
savedLibs=$LIBS
LIBS="$LIBS $SNMPLIBS"
dnl On many systems libcrypto is needed when linking against libsnmp.
dnl Check to see if it exists, and if so use it.
dnl AC_CHECK_LIB(crypto, CRYPTO_free, CRYPTOLIB="-lcrypto",)
dnl AC_SUBST(CRYPTOLIB)
AC_CHECK_FUNCS(netsnmp_transport_open_client)
if test $ac_cv_func_netsnmp_transport_open_client != yes; then
AC_CHECK_FUNCS(netsnmp_tdomain_transport)
if test $ac_cv_func_netsnmp_tdomain_transport != yes; then
SUPPORT_SNMP=no
else
AC_DEFINE_UNQUOTED(NETSNMPV53, 1, [Use the older 5.3 version of the net-snmp API])
fi
fi
LIBS=$savedLibs
fi
if test $SUPPORT_SNMP = no; then
SNMPLIBS=""
SUPPORT_SNMP=0
if test $missingisfatal = 0; then
AC_MSG_WARN(Unable to support SNMP)
else
AC_MSG_FAILURE(Unable to support SNMP)
fi
else
SUPPORT_SNMP=1
fi
fi
if test $SUPPORT_SNMP = 1; then
PCMK_FEATURES="$PCMK_FEATURES snmp"
fi
AC_SUBST(SNMPLIBS)
AM_CONDITIONAL(ENABLE_SNMP, test "$SUPPORT_SNMP" = "1")
AC_DEFINE_UNQUOTED(ENABLE_SNMP, $SUPPORT_SNMP, Build in support for sending SNMP traps)
dnl ========================================================================
dnl ESMTP
dnl ========================================================================
case $SUPPORT_ESMTP in
1|yes|true) missingisfatal=1;;
try) missingisfatal=0;;
*) SUPPORT_ESMTP=no;;
esac
ESMTPLIB=""
AC_MSG_CHECKING(for esmtp support)
if test $SUPPORT_ESMTP = no; then
AC_MSG_RESULT(no (disabled))
SUPPORT_ESMTP=0
else
ESMTPCONFIG=""
AC_MSG_RESULT($SUPPORT_ESMTP)
AC_CHECK_HEADERS(libesmtp.h)
if test "x${ac_cv_header_libesmtp_h}" != "xyes"; then
ENABLE_ESMTP="no"
fi
if test $SUPPORT_ESMTP != no; then
AC_PATH_PROGS(ESMTPCONFIG, libesmtp-config)
if test "X${ESMTPCONFIG}" = "X"; then
AC_MSG_RESULT(You need the libesmtp development package to continue.)
SUPPORT_ESMTP=no
fi
fi
if test $SUPPORT_ESMTP != no; then
AC_MSG_CHECKING(for special esmtp libraries)
ESMTPLIBS=`$ESMTPCONFIG --libs | tr '\n' ' '`
AC_MSG_RESULT($ESMTPLIBS)
fi
if test $SUPPORT_ESMTP = no; then
SUPPORT_ESMTP=0
if test $missingisfatal = 0; then
AC_MSG_WARN(Unable to support ESMTP)
else
AC_MSG_FAILURE(Unable to support ESMTP)
fi
else
SUPPORT_ESMTP=1
PCMK_FEATURES="$PCMK_FEATURES libesmtp"
fi
fi
AC_SUBST(ESMTPLIBS)
AM_CONDITIONAL(ENABLE_ESMTP, test "$SUPPORT_ESMTP" = "1")
AC_DEFINE_UNQUOTED(ENABLE_ESMTP, $SUPPORT_ESMTP, Build in support for sending mail notifications with ESMTP)
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)
LRM_LEGACY_CIBSECRETS_DIR="${localstatedir}/lib/heartbeat/lrm/secrets"
AC_DEFINE_UNQUOTED(LRM_LEGACY_CIBSECRETS_DIR,"$LRM_LEGACY_CIBSECRETS_DIR", Legacy location for CIB secrets)
AC_SUBST(LRM_LEGACY_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
$PKGCONFIG --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
$PKGCONFIG --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.
CC_ERRORS=""
CC_EXTRAS=""
if export | fgrep " CFLAGS=" > /dev/null; then
SAVED_CFLAGS="$CFLAGS"
unset CFLAGS
CFLAGS="$SAVED_CFLAGS"
unset SAVED_CFLAGS
fi
if test "$GCC" != yes; then
CFLAGS="$CFLAGS -g"
enable_fatal_warnings=no
else
CFLAGS="$CFLAGS -ggdb"
+dnl when we don't have diagnostic push / pull we can't explicitely 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"
+ 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"
+
+ 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
EXTRA_FLAGS="-fgnu89-inline
-Wall
-Waggregate-return
-Wbad-function-cast
-Wcast-align
-Wdeclaration-after-statement
-Wendif-labels
-Wfloat-equal
- -Wformat=2
-Wformat-security
- -Wformat-nonliteral
-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
case "$host_os" in
*solaris*) ;;
*) EXTRA_FLAGS="$EXTRA_FLAGS
-fstack-protector-all"
;;
esac
for j in $EXTRA_FLAGS
do
if
cc_supports_flag $j
then
CC_EXTRAS="$CC_EXTRAS $j"
fi
done
dnl In lib/ais/Makefile.am there's a gcc option available as of v4.x
GCC_MAJOR=`gcc -v 2>&1 | awk 'END{print $3}' | sed 's/[.].*//'`
AM_CONDITIONAL(GCC_4, test "${GCC_MAJOR}" = 4)
dnl System specific options
case "$host_os" in
*linux*|*bsd*)
if test "${enable_fatal_warnings}" = "unknown"; then
enable_fatal_warnings=yes
fi
;;
esac
if test "x${enable_fatal_warnings}" != xno && cc_supports_flag -Werror ; then
enable_fatal_warnings=yes
else
enable_fatal_warnings=no
fi
if test "x${enable_ansi}" = 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
CFLAGS="$CFLAGS $CC_EXTRAS"
NON_FATAL_CFLAGS="$CFLAGS"
AC_SUBST(NON_FATAL_CFLAGS)
dnl
dnl We reset CFLAGS to include our warnings *after* all function
dnl checking goes on, so that our warning flags don't keep the
dnl AC_*FUNCS() calls above from working. In particular, -Werror will
dnl *always* cause us troubles if we set it before here.
dnl
dnl
if test "x${enable_fatal_warnings}" = xyes ; then
AC_MSG_NOTICE(Enabling Fatal Warnings)
CFLAGS="$CFLAGS -Werror"
fi
AC_SUBST(CFLAGS)
dnl This is useful for use in Makefiles that need to remove one specific flag
CFLAGS_COPY="$CFLAGS"
AC_SUBST(CFLAGS_COPY)
AC_SUBST(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 The Makefiles and shell scripts we output
AC_CONFIG_FILES(Makefile \
Doxyfile \
coverage.sh \
cts/Makefile \
cts/CTSvars.py \
cts/LSBDummy \
cts/HBDummy \
cts/benchmark/Makefile \
cts/benchmark/clubench \
cts/lxc_autogen.sh \
cib/Makefile \
attrd/Makefile \
crmd/Makefile \
pengine/Makefile \
pengine/regression.core.sh \
doc/Makefile \
doc/Pacemaker_Explained/publican.cfg \
doc/Clusters_from_Scratch/publican.cfg \
doc/Pacemaker_Remote/publican.cfg \
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/ais/Makefile \
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 \
fencing/Makefile \
fencing/regression.py \
lrmd/Makefile \
lrmd/regression.py \
lrmd/pacemaker_remote.service \
lrmd/pacemaker_remote \
extra/Makefile \
extra/resources/Makefile \
extra/logrotate/Makefile \
extra/logrotate/pacemaker \
tools/Makefile \
tools/crm_report \
tools/report.common \
tools/cibsecret \
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([ Corosync Plugins = ${LCRSODIR}])
AC_MSG_RESULT([])
AC_MSG_RESULT([ Use system LTDL = ${ac_cv_lib_ltdl_lt_dlopen}])
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([ Libraries = ${LIBS}])
AC_MSG_RESULT([ Stack Libraries = ${CLUSTERLIBS}])
diff --git a/crmd/cib.c b/crmd/cib.c
index 2590ab6f33..189b359198 100644
--- a/crmd/cib.c
+++ b/crmd/cib.c
@@ -1,258 +1,278 @@
/*
* 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
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crmd_fsa.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> /* for access */
#include <sys/types.h> /* for calls to open */
#include <sys/stat.h> /* for calls to open */
#include <fcntl.h> /* for calls to open */
#include <pwd.h> /* for getpwuid */
#include <grp.h> /* for initgroups */
#include <sys/time.h> /* for getrlimit */
#include <sys/resource.h> /* for getrlimit */
#include <errno.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd_messages.h>
#include <crmd_callbacks.h>
#include <crmd.h>
#include <tengine.h>
struct crm_subsystem_s *cib_subsystem = NULL;
int cib_retries = 0;
static void
do_cib_updated(const char *event, xmlNode * msg)
{
int rc = -1;
int format= 1;
xmlNode *patchset = get_message_xml(msg, F_CIB_UPDATE_RESULT);
xmlNode *change = NULL;
+ xmlXPathObject *xpathObj = NULL;
CRM_CHECK(msg != NULL, return);
crm_element_value_int(msg, F_CIB_RC, &rc);
if (rc < pcmk_ok) {
crm_trace("Filter rc=%d (%s)", rc, pcmk_strerror(rc));
return;
}
crm_element_value_int(patchset, "format", &format);
if (format == 1) {
- if (get_xpath_object
- ("//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_CRMCONFIG, msg,
- LOG_TRACE) != NULL) {
+ if ((xpathObj = xpath_search(
+ msg,
+ "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_CRMCONFIG " | " \
+ "//" F_CIB_UPDATE_RESULT "//" XML_TAG_DIFF_ADDED "//" XML_CIB_TAG_NOTIFICATIONS
+ )) != NULL) {
+ freeXpathObject(xpathObj);
mainloop_set_trigger(config_read);
}
-
} else if (format == 2) {
for (change = __xml_first_child(patchset); change != NULL; change = __xml_next(change)) {
const char *xpath = crm_element_value(change, XML_DIFF_PATH);
- if (xpath != NULL
- && strstr(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_CRMCONFIG "/")) {
- mainloop_set_trigger(config_read);
- break;
+
+ if (xpath == NULL) {
+ continue;
}
+
+ /* modifying properties */
+ if (!strstr(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_CRMCONFIG "/") &&
+ !strstr(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION "/" XML_CIB_TAG_NOTIFICATIONS)) {
+ xmlNode *section = NULL;
+ const char *name = NULL;
+
+ /* adding notifications section */
+ if ((strcmp(xpath, "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION) != 0) ||
+ ((section = __xml_first_child(change)) == NULL) ||
+ ((name = crm_element_name(section)) == NULL) ||
+ (strcmp(name, XML_CIB_TAG_NOTIFICATIONS) != 0)) {
+ continue;
+ }
+ }
+
+ mainloop_set_trigger(config_read);
+ break;
}
} else {
crm_warn("Unknown patch format: %d", format);
}
}
static void
revision_check_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
{
int cmp = -1;
xmlNode *generation = NULL;
const char *revision = NULL;
if (rc != pcmk_ok) {
fsa_data_t *msg_data = NULL;
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
return;
}
generation = output;
CRM_CHECK(safe_str_eq(crm_element_name(generation), XML_TAG_CIB),
crm_log_xml_err(output, __FUNCTION__); return);
crm_trace("Checking our feature revision is allowed: %s", CIB_FEATURE_SET);
revision = crm_element_value(generation, XML_ATTR_CRM_VERSION);
cmp = compare_version(revision, CRM_FEATURE_SET);
if (cmp > 0) {
crm_err("This build (%s) does not support the current resource configuration", PACEMAKER_VERSION);
crm_err("We can only support up to CRM feature set %s (current=%s)",
CRM_FEATURE_SET, revision);
crm_err("Shutting down the CRM");
/* go into a stall state */
register_fsa_error_adv(C_FSA_INTERNAL, I_SHUTDOWN, NULL, NULL, __FUNCTION__);
return;
}
}
static void
do_cib_replaced(const char *event, xmlNode * msg)
{
crm_debug("Updating the CIB after a replace: DC=%s", AM_I_DC ? "true" : "false");
if (AM_I_DC == FALSE) {
return;
} else if (fsa_state == S_FINALIZE_JOIN && is_set(fsa_input_register, R_CIB_ASKED)) {
/* no need to restart the join - we asked for this replace op */
return;
}
/* start the join process again so we get everyone's LRM status */
populate_cib_nodes(node_update_quick|node_update_all, __FUNCTION__);
register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL);
}
/* A_CIB_STOP, A_CIB_START, A_CIB_RESTART, */
void
do_cib_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input, fsa_data_t * msg_data)
{
struct crm_subsystem_s *this_subsys = cib_subsystem;
long long stop_actions = A_CIB_STOP;
long long start_actions = A_CIB_START;
if (action & stop_actions) {
if (fsa_cib_conn->state != cib_disconnected && last_resource_update != 0) {
crm_info("Waiting for resource update %d to complete", last_resource_update);
crmd_fsa_stall(FALSE);
return;
}
crm_info("Disconnecting CIB");
clear_bit(fsa_input_register, R_CIB_CONNECTED);
CRM_ASSERT(fsa_cib_conn != NULL);
fsa_cib_conn->cmds->del_notify_callback(fsa_cib_conn, T_CIB_DIFF_NOTIFY, do_cib_updated);
if (fsa_cib_conn->state != cib_disconnected) {
fsa_cib_conn->cmds->set_slave(fsa_cib_conn, cib_scope_local);
fsa_cib_conn->cmds->signoff(fsa_cib_conn);
}
}
if (action & start_actions) {
int rc = pcmk_ok;
CRM_ASSERT(fsa_cib_conn != NULL);
if (cur_state == S_STOPPING) {
crm_err("Ignoring request to start %s after shutdown", this_subsys->name);
return;
}
rc = fsa_cib_conn->cmds->signon(fsa_cib_conn, CRM_SYSTEM_CRMD, cib_command_nonblocking);
if (rc != pcmk_ok) {
/* a short wait that usually avoids stalling the FSA */
sleep(1);
rc = fsa_cib_conn->cmds->signon(fsa_cib_conn, CRM_SYSTEM_CRMD, cib_command_nonblocking);
}
if (rc != pcmk_ok) {
crm_info("Could not connect to the CIB service: %s", pcmk_strerror(rc));
} else if (pcmk_ok !=
fsa_cib_conn->cmds->set_connection_dnotify(fsa_cib_conn,
crmd_cib_connection_destroy)) {
crm_err("Could not set dnotify callback");
} else if (pcmk_ok !=
fsa_cib_conn->cmds->add_notify_callback(fsa_cib_conn, T_CIB_REPLACE_NOTIFY,
do_cib_replaced)) {
crm_err("Could not set CIB notification callback (replace)");
} else if (pcmk_ok !=
fsa_cib_conn->cmds->add_notify_callback(fsa_cib_conn, T_CIB_DIFF_NOTIFY,
do_cib_updated)) {
crm_err("Could not set CIB notification callback (update)");
} else {
set_bit(fsa_input_register, R_CIB_CONNECTED);
}
if (is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) {
cib_retries++;
crm_warn("Couldn't complete CIB registration %d"
" times... pause and retry", cib_retries);
if (cib_retries < 30) {
crm_timer_start(wait_timer);
crmd_fsa_stall(FALSE);
} else {
crm_err("Could not complete CIB"
" registration %d times..." " hard error", cib_retries);
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
}
} else {
int call_id = 0;
crm_info("CIB connection established");
call_id = fsa_cib_conn->cmds->query(fsa_cib_conn, NULL, NULL, cib_scope_local);
fsa_register_cib_callback(call_id, FALSE, NULL, revision_check_callback);
cib_retries = 0;
}
}
}
/*!
* \internal
* \brief Get CIB call options to use local scope if master unavailable
*
* \return CIB call options
*/
int crmd_cib_smart_opt()
{
int call_opt = cib_quorum_override;
if (fsa_state == S_ELECTION || fsa_state == S_PENDING) {
crm_info("Sending update to local CIB in state: %s", fsa_state2string(fsa_state));
call_opt |= cib_scope_local;
}
return call_opt;
}
diff --git a/crmd/control.c b/crmd/control.c
index 53d850e0ab..ac8bb1162a 100644
--- a/crmd/control.c
+++ b/crmd/control.c
@@ -1,1125 +1,1154 @@
/*
* 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
*/
#include <crm_internal.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/pengine/rules.h>
#include <crm/cluster/internal.h>
#include <crm/cluster/election.h>
#include <crm/common/ipcs.h>
#include <crmd.h>
#include <crmd_fsa.h>
#include <fsa_proto.h>
#include <crmd_messages.h>
#include <crmd_callbacks.h>
#include <crmd_lrm.h>
#include <tengine.h>
#include <throttle.h>
#include <sys/types.h>
#include <sys/stat.h>
/* Enable support for built-in notifications
*
* The interface is expected to change significantly, and this will be defined
* in the upstream master branch only until a new design is finalized.
*/
#define RHEL7_COMPAT
qb_ipcs_service_t *ipcs = NULL;
extern gboolean crm_connect_corosync(crm_cluster_t * cluster);
extern void crmd_ha_connection_destroy(gpointer user_data);
void crm_shutdown(int nsig);
gboolean crm_read_options(gpointer user_data);
gboolean fsa_has_quorum = FALSE;
crm_trigger_t *fsa_source = NULL;
crm_trigger_t *config_read = NULL;
bool no_quorum_suicide_escalation = FALSE;
static gboolean
election_timeout_popped(gpointer data)
{
/* Not everyone voted */
crm_info("Election failed: Declaring ourselves the winner");
register_fsa_input(C_TIMER_POPPED, I_ELECTION_DC, NULL);
return FALSE;
}
/* A_HA_CONNECT */
void
do_ha_control(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input, fsa_data_t * msg_data)
{
gboolean registered = FALSE;
static crm_cluster_t *cluster = NULL;
if (cluster == NULL) {
cluster = calloc(1, sizeof(crm_cluster_t));
}
if (action & A_HA_DISCONNECT) {
crm_cluster_disconnect(cluster);
crm_info("Disconnected from the cluster");
set_bit(fsa_input_register, R_HA_DISCONNECTED);
}
if (action & A_HA_CONNECT) {
crm_set_status_callback(&peer_update_callback);
crm_set_autoreap(FALSE);
if (is_openais_cluster()) {
#if SUPPORT_COROSYNC
registered = crm_connect_corosync(cluster);
#endif
} else if (is_heartbeat_cluster()) {
#if SUPPORT_HEARTBEAT
cluster->destroy = crmd_ha_connection_destroy;
cluster->hb_dispatch = crmd_ha_msg_callback;
registered = crm_cluster_connect(cluster);
fsa_cluster_conn = cluster->hb_conn;
crm_trace("Be informed of Node Status changes");
if (registered &&
fsa_cluster_conn->llc_ops->set_nstatus_callback(fsa_cluster_conn,
crmd_ha_status_callback,
fsa_cluster_conn) != HA_OK) {
crm_err("Cannot set nstatus callback: %s",
fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn));
registered = FALSE;
}
crm_trace("Be informed of CRM Client Status changes");
if (registered &&
fsa_cluster_conn->llc_ops->set_cstatus_callback(fsa_cluster_conn,
crmd_client_status_callback,
fsa_cluster_conn) != HA_OK) {
crm_err("Cannot set cstatus callback: %s",
fsa_cluster_conn->llc_ops->errmsg(fsa_cluster_conn));
registered = FALSE;
}
if (registered) {
crm_trace("Requesting an initial dump of CRMD client_status");
fsa_cluster_conn->llc_ops->client_status(fsa_cluster_conn, NULL, CRM_SYSTEM_CRMD,
-1);
}
#endif
}
fsa_election = election_init(NULL, cluster->uname, 60000/*60s*/, election_timeout_popped);
fsa_our_uname = cluster->uname;
fsa_our_uuid = cluster->uuid;
if(cluster->uuid == NULL) {
crm_err("Could not obtain local uuid");
registered = FALSE;
}
if (registered == FALSE) {
set_bit(fsa_input_register, R_HA_DISCONNECTED);
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
return;
}
populate_cib_nodes(node_update_none, __FUNCTION__);
clear_bit(fsa_input_register, R_HA_DISCONNECTED);
crm_info("Connected to the cluster");
}
if (action & ~(A_HA_CONNECT | A_HA_DISCONNECT)) {
crm_err("Unexpected action %s in %s", fsa_action2string(action), __FUNCTION__);
}
}
static bool
need_spawn_pengine_from_crmd(void)
{
static int result = -1;
if (result != -1)
return result;
if (!is_heartbeat_cluster()) {
result = 0;
return result;
}
/* NULL, or "strange" value: rather spawn from here. */
result = TRUE;
crm_str_to_boolean(daemon_option("crmd_spawns_pengine"), &result);
return result;
}
/* A_SHUTDOWN */
void
do_shutdown(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
{
/* just in case */
set_bit(fsa_input_register, R_SHUTDOWN);
if (need_spawn_pengine_from_crmd()) {
if (is_set(fsa_input_register, pe_subsystem->flag_connected)) {
crm_info("Terminating the %s", pe_subsystem->name);
if (stop_subsystem(pe_subsystem, TRUE) == FALSE) {
/* its gone... */
crm_err("Faking %s exit", pe_subsystem->name);
clear_bit(fsa_input_register, pe_subsystem->flag_connected);
} else {
crm_info("Waiting for subsystems to exit");
crmd_fsa_stall(FALSE);
}
}
crm_info("All subsystems stopped, continuing");
}
if (stonith_api) {
/* Prevent it from coming up again */
clear_bit(fsa_input_register, R_ST_REQUIRED);
crm_info("Disconnecting STONITH...");
stonith_api->cmds->disconnect(stonith_api);
}
}
/* A_SHUTDOWN_REQ */
void
do_shutdown_req(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input, fsa_data_t * msg_data)
{
xmlNode *msg = NULL;
crm_info("Sending shutdown request to %s", crm_str(fsa_our_dc));
msg = create_request(CRM_OP_SHUTDOWN_REQ, NULL, NULL, CRM_SYSTEM_CRMD, CRM_SYSTEM_CRMD, NULL);
/* set_bit(fsa_input_register, R_STAYDOWN); */
if (send_cluster_message(NULL, crm_msg_crmd, msg, TRUE) == FALSE) {
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
}
free_xml(msg);
}
extern crm_ipc_t *attrd_ipc;
extern char *max_generation_from;
extern xmlNode *max_generation_xml;
extern GHashTable *resource_history;
extern GHashTable *voted;
extern GHashTable *metadata_hash;
extern char *te_client_id;
void log_connected_client(gpointer key, gpointer value, gpointer user_data);
void
log_connected_client(gpointer key, gpointer value, gpointer user_data)
{
crm_client_t *client = value;
crm_err("%s is still connected at exit", crm_client_name(client));
}
int
crmd_fast_exit(int rc)
{
if (is_set(fsa_input_register, R_STAYDOWN)) {
crm_warn("Inhibiting respawn: %d -> %d", rc, 100);
rc = 100;
}
if (rc == pcmk_ok && is_set(fsa_input_register, R_IN_RECOVERY)) {
crm_err("Could not recover from internal error");
rc = pcmk_err_generic;
}
return crm_exit(rc);
}
int
crmd_exit(int rc)
{
GListPtr gIter = NULL;
GMainLoop *mloop = crmd_mainloop;
static bool in_progress = FALSE;
if(in_progress && rc == 0) {
crm_debug("Exit is already in progress");
return rc;
} else if(in_progress) {
crm_notice("Error during shutdown process, terminating now: %s (%d)", pcmk_strerror(rc), rc);
crm_write_blackbox(SIGTRAP, NULL);
crmd_fast_exit(rc);
}
in_progress = TRUE;
crm_trace("Preparing to exit: %d", rc);
/* Suppress secondary errors resulting from us disconnecting everything */
set_bit(fsa_input_register, R_HA_DISCONNECTED);
/* Close all IPC servers and clients to ensure any and all shared memory files are cleaned up */
if(ipcs) {
crm_trace("Closing IPC server");
mainloop_del_ipc_server(ipcs);
ipcs = NULL;
}
if (attrd_ipc) {
crm_trace("Closing attrd connection");
crm_ipc_close(attrd_ipc);
crm_ipc_destroy(attrd_ipc);
attrd_ipc = NULL;
}
if (pe_subsystem && pe_subsystem->client && pe_subsystem->client->ipcs) {
crm_trace("Disconnecting Policy Engine");
qb_ipcs_disconnect(pe_subsystem->client->ipcs);
}
if(stonith_api) {
crm_trace("Disconnecting fencing API");
clear_bit(fsa_input_register, R_ST_REQUIRED);
stonith_api->cmds->free(stonith_api); stonith_api = NULL;
}
if (rc == pcmk_ok && crmd_mainloop == NULL) {
crm_debug("No mainloop detected");
rc = EPROTO;
}
/* On an error, just get out.
*
* Otherwise, make the effort to have mainloop exit gracefully so
* that it (mostly) cleans up after itself and valgrind has less
* to report on - allowing real errors stand out
*/
if(rc != pcmk_ok) {
crm_notice("Forcing immediate exit: %s (%d)", pcmk_strerror(rc), rc);
crm_write_blackbox(SIGTRAP, NULL);
return crmd_fast_exit(rc);
}
/* Clean up as much memory as possible for valgrind */
for (gIter = fsa_message_queue; gIter != NULL; gIter = gIter->next) {
fsa_data_t *fsa_data = gIter->data;
crm_info("Dropping %s: [ state=%s cause=%s origin=%s ]",
fsa_input2string(fsa_data->fsa_input),
fsa_state2string(fsa_state),
fsa_cause2string(fsa_data->fsa_cause), fsa_data->origin);
delete_fsa_input(fsa_data);
}
clear_bit(fsa_input_register, R_MEMBERSHIP);
g_list_free(fsa_message_queue); fsa_message_queue = NULL;
free(pe_subsystem); pe_subsystem = NULL;
free(te_subsystem); te_subsystem = NULL;
free(cib_subsystem); cib_subsystem = NULL;
if (metadata_hash) {
crm_trace("Destroying reload cache with %d members", g_hash_table_size(metadata_hash));
g_hash_table_destroy(metadata_hash); metadata_hash = NULL;
}
election_fini(fsa_election);
fsa_election = NULL;
cib_delete(fsa_cib_conn);
fsa_cib_conn = NULL;
verify_stopped(fsa_state, LOG_WARNING);
clear_bit(fsa_input_register, R_LRM_CONNECTED);
lrm_state_destroy_all();
/* This basically will not work, since mainloop has a reference to it */
mainloop_destroy_trigger(fsa_source); fsa_source = NULL;
mainloop_destroy_trigger(config_read); config_read = NULL;
mainloop_destroy_trigger(stonith_reconnect); stonith_reconnect = NULL;
mainloop_destroy_trigger(transition_trigger); transition_trigger = NULL;
crm_client_cleanup();
crm_peer_destroy();
crm_timer_stop(transition_timer);
crm_timer_stop(integration_timer);
crm_timer_stop(finalization_timer);
crm_timer_stop(election_trigger);
election_timeout_stop(fsa_election);
crm_timer_stop(shutdown_escalation_timer);
crm_timer_stop(wait_timer);
crm_timer_stop(recheck_timer);
free(transition_timer); transition_timer = NULL;
free(integration_timer); integration_timer = NULL;
free(finalization_timer); finalization_timer = NULL;
free(election_trigger); election_trigger = NULL;
election_fini(fsa_election);
free(shutdown_escalation_timer); shutdown_escalation_timer = NULL;
free(wait_timer); wait_timer = NULL;
free(recheck_timer); recheck_timer = NULL;
free(fsa_our_dc_version); fsa_our_dc_version = NULL;
free(fsa_our_uname); fsa_our_uname = NULL;
free(fsa_our_uuid); fsa_our_uuid = NULL;
free(fsa_our_dc); fsa_our_dc = NULL;
free(fsa_cluster_name); fsa_cluster_name = NULL;
free(te_uuid); te_uuid = NULL;
free(te_client_id); te_client_id = NULL;
free(fsa_pe_ref); fsa_pe_ref = NULL;
free(failed_stop_offset); failed_stop_offset = NULL;
free(failed_start_offset); failed_start_offset = NULL;
free(max_generation_from); max_generation_from = NULL;
free_xml(max_generation_xml); max_generation_xml = NULL;
mainloop_destroy_signal(SIGPIPE);
mainloop_destroy_signal(SIGUSR1);
mainloop_destroy_signal(SIGTERM);
mainloop_destroy_signal(SIGTRAP);
mainloop_destroy_signal(SIGCHLD);
if (mloop) {
int lpc = 0;
GMainContext *ctx = g_main_loop_get_context(crmd_mainloop);
/* Don't re-enter this block */
crmd_mainloop = NULL;
crm_trace("Draining mainloop %d %d", g_main_loop_is_running(mloop), g_main_context_pending(ctx));
while(g_main_context_pending(ctx) && lpc < 10) {
lpc++;
crm_trace("Iteration %d", lpc);
g_main_context_dispatch(ctx);
}
crm_trace("Closing mainloop %d %d", g_main_loop_is_running(mloop), g_main_context_pending(ctx));
g_main_loop_quit(mloop);
#if SUPPORT_HEARTBEAT
/* Do this only after g_main_loop_quit().
*
* This interface was broken (incomplete) since it was introduced.
* ->delete() does cleanup and free most of it, but it does not
* actually remove and destroy the corresponding GSource, so the next
* prepare/check iteratioin would find a corrupt (because partially
* freed) GSource, and segfault.
*
* Apparently one was supposed to store the GSource as returned by
* G_main_add_ll_cluster(), and g_source_destroy() that "by hand".
*
* But no-one ever did this, not even in the old hb code when this was
* introduced.
*
* Note that fsa_cluster_conn was set as an "alias" to cluster->hb_conn
* in do_ha_control() right after crm_cluster_connect(), and only
* happens to still point at that object, because do_ha_control() does
* not reset it to NULL after crm_cluster_disconnect() above does
* reset cluster->hb_conn to NULL.
* Not sure if that's something to cleanup, too.
*
* I'll try to fix this up in heartbeat proper, so ->delete
* will actually remove, and destroy, and unref, and free this thing.
* Doing so after g_main_loop_quit() is valid with both old,
* and eventually fixed heartbeat.
*
* If we introduce the "by hand" destroy/remove/unref,
* this may break again once heartbeat is fixed :-(
*
* -- Lars Ellenberg
*/
if (fsa_cluster_conn) {
crm_trace("Deleting heartbeat api object");
fsa_cluster_conn->llc_ops->delete(fsa_cluster_conn);
fsa_cluster_conn = NULL;
}
#endif
/* Won't do anything yet, since we're inside it now */
g_main_loop_unref(mloop);
crm_trace("Done %d", rc);
}
/* Graceful */
return rc;
}
/* A_EXIT_0, A_EXIT_1 */
void
do_exit(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
{
int exit_code = pcmk_ok;
int log_level = LOG_INFO;
const char *exit_type = "gracefully";
if (action & A_EXIT_1) {
/* exit_code = pcmk_err_generic; */
log_level = LOG_ERR;
exit_type = "forcefully";
exit_code = pcmk_err_generic;
}
verify_stopped(cur_state, LOG_ERR);
do_crm_log(log_level, "Performing %s - %s exiting the CRMd",
fsa_action2string(action), exit_type);
crm_info("[%s] stopped (%d)", crm_system_name, exit_code);
crmd_exit(exit_code);
}
static void sigpipe_ignore(int nsig) { return; }
/* A_STARTUP */
void
do_startup(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
{
int was_error = 0;
crm_debug("Registering Signal Handlers");
mainloop_add_signal(SIGTERM, crm_shutdown);
mainloop_add_signal(SIGPIPE, sigpipe_ignore);
fsa_source = mainloop_add_trigger(G_PRIORITY_HIGH, crm_fsa_trigger, NULL);
config_read = mainloop_add_trigger(G_PRIORITY_HIGH, crm_read_options, NULL);
transition_trigger = mainloop_add_trigger(G_PRIORITY_LOW, te_graph_trigger, NULL);
crm_debug("Creating CIB and LRM objects");
fsa_cib_conn = cib_new();
lrm_state_init_local();
/* set up the timers */
transition_timer = calloc(1, sizeof(fsa_timer_t));
integration_timer = calloc(1, sizeof(fsa_timer_t));
finalization_timer = calloc(1, sizeof(fsa_timer_t));
election_trigger = calloc(1, sizeof(fsa_timer_t));
shutdown_escalation_timer = calloc(1, sizeof(fsa_timer_t));
wait_timer = calloc(1, sizeof(fsa_timer_t));
recheck_timer = calloc(1, sizeof(fsa_timer_t));
if (election_trigger != NULL) {
election_trigger->source_id = 0;
election_trigger->period_ms = -1;
election_trigger->fsa_input = I_DC_TIMEOUT;
election_trigger->callback = crm_timer_popped;
election_trigger->repeat = FALSE;
} else {
was_error = TRUE;
}
if (transition_timer != NULL) {
transition_timer->source_id = 0;
transition_timer->period_ms = -1;
transition_timer->fsa_input = I_PE_CALC;
transition_timer->callback = crm_timer_popped;
transition_timer->repeat = FALSE;
} else {
was_error = TRUE;
}
if (integration_timer != NULL) {
integration_timer->source_id = 0;
integration_timer->period_ms = -1;
integration_timer->fsa_input = I_INTEGRATED;
integration_timer->callback = crm_timer_popped;
integration_timer->repeat = FALSE;
} else {
was_error = TRUE;
}
if (finalization_timer != NULL) {
finalization_timer->source_id = 0;
finalization_timer->period_ms = -1;
finalization_timer->fsa_input = I_FINALIZED;
finalization_timer->callback = crm_timer_popped;
finalization_timer->repeat = FALSE;
/* for possible enabling... a bug in the join protocol left
* a slave in S_PENDING while we think its in S_NOT_DC
*
* raising I_FINALIZED put us into a transition loop which is
* never resolved.
* in this loop we continually send probes which the node
* NACK's because its in S_PENDING
*
* if we have nodes where heartbeat is active but the
* CRM is not... then this will be handled in the
* integration phase
*/
finalization_timer->fsa_input = I_ELECTION;
} else {
was_error = TRUE;
}
if (shutdown_escalation_timer != NULL) {
shutdown_escalation_timer->source_id = 0;
shutdown_escalation_timer->period_ms = -1;
shutdown_escalation_timer->fsa_input = I_STOP;
shutdown_escalation_timer->callback = crm_timer_popped;
shutdown_escalation_timer->repeat = FALSE;
} else {
was_error = TRUE;
}
if (wait_timer != NULL) {
wait_timer->source_id = 0;
wait_timer->period_ms = 2000;
wait_timer->fsa_input = I_NULL;
wait_timer->callback = crm_timer_popped;
wait_timer->repeat = FALSE;
} else {
was_error = TRUE;
}
if (recheck_timer != NULL) {
recheck_timer->source_id = 0;
recheck_timer->period_ms = -1;
recheck_timer->fsa_input = I_PE_CALC;
recheck_timer->callback = crm_timer_popped;
recheck_timer->repeat = FALSE;
} else {
was_error = TRUE;
}
/* set up the sub systems */
cib_subsystem = calloc(1, sizeof(struct crm_subsystem_s));
te_subsystem = calloc(1, sizeof(struct crm_subsystem_s));
pe_subsystem = calloc(1, sizeof(struct crm_subsystem_s));
if (cib_subsystem != NULL) {
cib_subsystem->pid = -1;
cib_subsystem->name = CRM_SYSTEM_CIB;
cib_subsystem->flag_connected = R_CIB_CONNECTED;
cib_subsystem->flag_required = R_CIB_REQUIRED;
} else {
was_error = TRUE;
}
if (te_subsystem != NULL) {
te_subsystem->pid = -1;
te_subsystem->name = CRM_SYSTEM_TENGINE;
te_subsystem->flag_connected = R_TE_CONNECTED;
te_subsystem->flag_required = R_TE_REQUIRED;
} else {
was_error = TRUE;
}
if (pe_subsystem != NULL) {
pe_subsystem->pid = -1;
pe_subsystem->path = CRM_DAEMON_DIR;
pe_subsystem->name = CRM_SYSTEM_PENGINE;
pe_subsystem->command = CRM_DAEMON_DIR "/" CRM_SYSTEM_PENGINE;
pe_subsystem->args = NULL;
pe_subsystem->flag_connected = R_PE_CONNECTED;
pe_subsystem->flag_required = R_PE_REQUIRED;
} else {
was_error = TRUE;
}
if (was_error == FALSE && need_spawn_pengine_from_crmd()) {
if (start_subsystem(pe_subsystem) == FALSE) {
was_error = TRUE;
}
}
if (was_error) {
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
}
}
static int32_t
crmd_ipc_accept(qb_ipcs_connection_t * c, uid_t uid, gid_t gid)
{
crm_trace("Connection %p", c);
if (crm_client_new(c, uid, gid) == NULL) {
return -EIO;
}
return 0;
}
static void
crmd_ipc_created(qb_ipcs_connection_t * c)
{
crm_trace("Connection %p", c);
}
static int32_t
crmd_ipc_dispatch(qb_ipcs_connection_t * c, void *data, size_t size)
{
uint32_t id = 0;
uint32_t flags = 0;
crm_client_t *client = crm_client_get(c);
xmlNode *msg = crm_ipcs_recv(client, data, size, &id, &flags);
crm_trace("Invoked: %s", crm_client_name(client));
crm_ipcs_send_ack(client, id, flags, "ack", __FUNCTION__, __LINE__);
if (msg == NULL) {
return 0;
}
#if ENABLE_ACL
CRM_ASSERT(client->user != NULL);
crm_acl_get_set_user(msg, F_CRM_USER, client->user);
#endif
crm_trace("Processing msg from %s", crm_client_name(client));
crm_log_xml_trace(msg, "CRMd[inbound]");
crm_xml_add(msg, F_CRM_SYS_FROM, client->id);
if (crmd_authorize_message(msg, client, NULL)) {
route_message(C_IPC_MESSAGE, msg);
}
trigger_fsa(fsa_source);
free_xml(msg);
return 0;
}
static int32_t
crmd_ipc_closed(qb_ipcs_connection_t * c)
{
crm_client_t *client = crm_client_get(c);
struct crm_subsystem_s *the_subsystem = NULL;
if (client == NULL) {
return 0;
}
crm_trace("Connection %p", c);
if (client->userdata == NULL) {
crm_trace("Client hadn't registered with us yet");
} else if (strcasecmp(CRM_SYSTEM_PENGINE, client->userdata) == 0) {
the_subsystem = pe_subsystem;
} else if (strcasecmp(CRM_SYSTEM_TENGINE, client->userdata) == 0) {
the_subsystem = te_subsystem;
} else if (strcasecmp(CRM_SYSTEM_CIB, client->userdata) == 0) {
the_subsystem = cib_subsystem;
}
if (the_subsystem != NULL) {
the_subsystem->source = NULL;
the_subsystem->client = NULL;
crm_info("Received HUP from %s:[%d]", the_subsystem->name, the_subsystem->pid);
} else {
/* else that was a transient client */
crm_trace("Received HUP from transient client");
}
crm_trace("Disconnecting client %s (%p)", crm_client_name(client), client);
free(client->userdata);
crm_client_destroy(client);
trigger_fsa(fsa_source);
return 0;
}
static void
crmd_ipc_destroy(qb_ipcs_connection_t * c)
{
crm_trace("Connection %p", c);
crmd_ipc_closed(c);
}
/* A_STOP */
void
do_stop(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
{
crm_trace("Closing IPC server");
mainloop_del_ipc_server(ipcs); ipcs = NULL;
register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL);
}
/* A_STARTED */
void
do_started(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
{
static struct qb_ipcs_service_handlers crmd_callbacks = {
.connection_accept = crmd_ipc_accept,
.connection_created = crmd_ipc_created,
.msg_process = crmd_ipc_dispatch,
.connection_closed = crmd_ipc_closed,
.connection_destroyed = crmd_ipc_destroy
};
if (cur_state != S_STARTING) {
crm_err("Start cancelled... %s", fsa_state2string(cur_state));
return;
} else if (is_set(fsa_input_register, R_MEMBERSHIP) == FALSE) {
crm_info("Delaying start, no membership data (%.16llx)", R_MEMBERSHIP);
crmd_fsa_stall(TRUE);
return;
} else if (is_set(fsa_input_register, R_LRM_CONNECTED) == FALSE) {
crm_info("Delaying start, LRM not connected (%.16llx)", R_LRM_CONNECTED);
crmd_fsa_stall(TRUE);
return;
} else if (is_set(fsa_input_register, R_CIB_CONNECTED) == FALSE) {
crm_info("Delaying start, CIB not connected (%.16llx)", R_CIB_CONNECTED);
crmd_fsa_stall(TRUE);
return;
} else if (is_set(fsa_input_register, R_READ_CONFIG) == FALSE) {
crm_info("Delaying start, Config not read (%.16llx)", R_READ_CONFIG);
crmd_fsa_stall(TRUE);
return;
} else if (is_set(fsa_input_register, R_PEER_DATA) == FALSE) {
/* try reading from HA */
crm_info("Delaying start, No peer data (%.16llx)", R_PEER_DATA);
#if SUPPORT_HEARTBEAT
if (is_heartbeat_cluster()) {
HA_Message *msg = NULL;
crm_trace("Looking for a HA message");
msg = fsa_cluster_conn->llc_ops->readmsg(fsa_cluster_conn, 0);
if (msg != NULL) {
crm_trace("There was a HA message");
ha_msg_del(msg);
}
}
#endif
crmd_fsa_stall(TRUE);
return;
}
crm_debug("Init server comms");
ipcs = crmd_ipc_server_init(&crmd_callbacks);
if (ipcs == NULL) {
crm_err("Failed to create IPC server: shutting down and inhibiting respawn");
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
}
if (stonith_reconnect == NULL) {
int dummy;
stonith_reconnect = mainloop_add_trigger(G_PRIORITY_LOW, te_connect_stonith, &dummy);
}
set_bit(fsa_input_register, R_ST_REQUIRED);
mainloop_set_trigger(stonith_reconnect);
crm_notice("The local CRM is operational");
clear_bit(fsa_input_register, R_STARTING);
register_fsa_input(msg_data->fsa_cause, I_PENDING, NULL);
}
/* A_RECOVER */
void
do_recover(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state, enum crmd_fsa_input current_input, fsa_data_t * msg_data)
{
set_bit(fsa_input_register, R_IN_RECOVERY);
crm_warn("Fast-tracking shutdown in response to errors");
register_fsa_input(C_FSA_INTERNAL, I_TERMINATE, NULL);
}
/* *INDENT-OFF* */
pe_cluster_option crmd_opts[] = {
/* name, old-name, validate, values, default, short description, long description */
{ "dc-version", NULL, "string", NULL, "none", NULL,
"Version of Pacemaker on the cluster's DC.",
"Includes the hash which identifies the exact changeset it was built from. Used for diagnostic purposes."
},
{ "cluster-infrastructure", NULL, "string", NULL, "heartbeat", NULL,
"The messaging stack on which Pacemaker is currently running.",
"Used for informational and diagnostic purposes." },
{ XML_CONFIG_ATTR_DC_DEADTIME, "dc_deadtime", "time", NULL, "20s", &check_time,
"How long to wait for a response from other nodes during startup.",
"The \"correct\" value will depend on the speed/load of your network and the type of switches used."
},
{ XML_CONFIG_ATTR_RECHECK, "cluster_recheck_interval", "time",
"Zero disables polling. Positive values are an interval in seconds (unless other SI units are specified. eg. 5min)",
"15min", &check_timer,
"Polling interval for time based changes to options, resource parameters and constraints.",
"The Cluster is primarily event driven, however the configuration can have elements that change based on time."
" To ensure these changes take effect, we can optionally poll the cluster's status for changes."
},
#ifdef RHEL7_COMPAT
/* this interface is expected to change but was released in RHEL 7 */
{ "notification-agent", NULL, "string", NULL, "/dev/null", &check_script,
"Notification script or tool to be called after significant cluster events",
"Full path to a script or binary that will be invoked when resources start/stop/fail, fencing occurs or nodes join/leave the cluster.\n"
"Must exist on all nodes in the cluster."
},
{ "notification-recipient", NULL, "string", NULL, "", NULL,
"Destination for notifications (Optional)",
"Where should the supplied script send notifications to. Useful to avoid hard-coding this in the script."
},
#endif
{ "load-threshold", NULL, "percentage", NULL, "80%", &check_utilization,
"The maximum amount of system resources that should be used by nodes in the cluster",
"The cluster will slow down its recovery process when the amount of system resources used"
" (currently CPU) approaches this limit",
},
{ "node-action-limit", NULL, "integer", NULL, "0", &check_number,
"The maximum number of jobs that can be scheduled per node. Defaults to 2x cores"},
{ XML_CONFIG_ATTR_ELECTION_FAIL, "election_timeout", "time", NULL, "2min", &check_timer,
"*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug."
},
{ XML_CONFIG_ATTR_FORCE_QUIT, "shutdown_escalation", "time", NULL, "20min", &check_timer,
"*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug."
},
{ "crmd-integration-timeout", NULL, "time", NULL, "3min", &check_timer,
"*** Advanced Use Only ***.", "If need to adjust this value, it probably indicates the presence of a bug."
},
{ "crmd-finalization-timeout", NULL, "time", NULL, "30min", &check_timer,
"*** Advanced Use Only ***.", "If you need to adjust this value, it probably indicates the presence of a bug."
},
{ "crmd-transition-delay", NULL, "time", NULL, "0s", &check_timer,
"*** Advanced Use Only ***\n"
"Enabling this option will slow down cluster recovery under all conditions",
"Delay cluster recovery for the configured interval to allow for additional/related events to occur.\n"
"Useful if your configuration is sensitive to the order in which ping updates arrive."
},
{ "stonith-watchdog-timeout", NULL, "time", NULL, NULL, &check_sbd_timeout,
"How long to wait before we can assume nodes are safely down", NULL
},
{ "no-quorum-policy", "no_quorum_policy", "enum", "stop, freeze, ignore, suicide", "stop", &check_quorum, NULL, NULL },
#if SUPPORT_PLUGIN
{ XML_ATTR_EXPECTED_VOTES, NULL, "integer", NULL, "2", &check_number, "The number of nodes expected to be in the cluster", "Used to calculate quorum in openais based clusters." },
#endif
};
/* *INDENT-ON* */
void
crmd_metadata(void)
{
config_metadata("CRM Daemon", "1.0",
"CRM Daemon Options",
"This is a fake resource that details the options that can be configured for the CRM Daemon.",
crmd_opts, DIMOF(crmd_opts));
}
static void
verify_crmd_options(GHashTable * options)
{
verify_all_options(options, crmd_opts, DIMOF(crmd_opts));
}
static const char *
crmd_pref(GHashTable * options, const char *name)
{
return get_cluster_pref(options, crmd_opts, DIMOF(crmd_opts), name);
}
static void
config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data)
{
#ifdef RHEL7_COMPAT
const char *script = NULL;
#endif
const char *value = NULL;
GHashTable *config_hash = NULL;
crm_time_t *now = crm_time_new(NULL);
if (rc != pcmk_ok) {
fsa_data_t *msg_data = NULL;
crm_err("Local CIB query resulted in an error: %s", pcmk_strerror(rc));
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
if (rc == -EACCES || rc == -pcmk_err_schema_validation) {
crm_err("The cluster is mis-configured - shutting down and staying down");
set_bit(fsa_input_register, R_STAYDOWN);
}
goto bail;
}
crm_debug("Call %d : Parsing CIB options", call_id);
config_hash =
g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, g_hash_destroy_str);
unpack_instance_attributes(output, output, XML_CIB_TAG_PROPSET, NULL, config_hash,
CIB_OPTIONS_FIRST, FALSE, now);
verify_crmd_options(config_hash);
#ifdef RHEL7_COMPAT
script = crmd_pref(config_hash, "notification-agent");
value = crmd_pref(config_hash, "notification-recipient");
crmd_enable_notifications(script, value);
#endif
value = crmd_pref(config_hash, XML_CONFIG_ATTR_DC_DEADTIME);
election_trigger->period_ms = crm_get_msec(value);
value = crmd_pref(config_hash, "node-action-limit"); /* Also checks migration-limit */
throttle_update_job_max(value);
value = crmd_pref(config_hash, "load-threshold");
if(value) {
throttle_load_target = strtof(value, NULL) / 100;
}
value = crmd_pref(config_hash, "no-quorum-policy");
if (safe_str_eq(value, "suicide") && pcmk_locate_sbd()) {
no_quorum_suicide_escalation = TRUE;
}
value = crmd_pref(config_hash, XML_CONFIG_ATTR_FORCE_QUIT);
shutdown_escalation_timer->period_ms = crm_get_msec(value);
/* How long to declare an election over - even if not everyone voted */
crm_debug("Shutdown escalation occurs after: %dms", shutdown_escalation_timer->period_ms);
value = crmd_pref(config_hash, XML_CONFIG_ATTR_ELECTION_FAIL);
election_timeout_set_period(fsa_election, crm_get_msec(value));
value = crmd_pref(config_hash, XML_CONFIG_ATTR_RECHECK);
recheck_timer->period_ms = crm_get_msec(value);
crm_debug("Checking for expired actions every %dms", recheck_timer->period_ms);
value = crmd_pref(config_hash, "crmd-transition-delay");
transition_timer->period_ms = crm_get_msec(value);
value = crmd_pref(config_hash, "crmd-integration-timeout");
integration_timer->period_ms = crm_get_msec(value);
value = crmd_pref(config_hash, "crmd-finalization-timeout");
finalization_timer->period_ms = crm_get_msec(value);
#if SUPPORT_COROSYNC
if (is_classic_ais_cluster()) {
value = crmd_pref(config_hash, XML_ATTR_EXPECTED_VOTES);
crm_debug("Sending expected-votes=%s to corosync", value);
send_cluster_text(crm_class_quorum, value, TRUE, NULL, crm_msg_ais);
}
#endif
free(fsa_cluster_name);
fsa_cluster_name = NULL;
value = g_hash_table_lookup(config_hash, "cluster-name");
if (value) {
fsa_cluster_name = strdup(value);
}
+#if 0
+ {
+ int sub_call_id;
+
+ sub_call_id = fsa_cib_conn->cmds->query(fsa_cib_conn,
+ "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION
+ "/" XML_CIB_TAG_NOTIFICATIONS "/" XML_CIB_TAG_NOTIFY, NULL,
+ cib_scope_local | cib_xpath);
+
+ fsa_register_cib_callback(sub_call_id, FALSE, NULL,
+ notifications_query_callback);
+
+ crm_trace("Querying the CIB for notifications ... call %d", sub_call_id);
+ }
+#endif
+
+ {
+ xmlNode *cib_object = NULL;
+ int rc;
+
+ rc = fsa_cib_conn->cmds->query(fsa_cib_conn,
+ "/" XML_TAG_CIB "/" XML_CIB_TAG_CONFIGURATION
+ "/" XML_CIB_TAG_NOTIFICATIONS "/" XML_CIB_TAG_NOTIFY, &cib_object,
+ cib_scope_local | cib_xpath | cib_sync_call);
+
+ notifications_query_callback(msg, call_id, rc, cib_object, user_data);
+ free_xml(cib_object);
+ }
+
set_bit(fsa_input_register, R_READ_CONFIG);
crm_trace("Triggering FSA: %s", __FUNCTION__);
mainloop_set_trigger(fsa_source);
g_hash_table_destroy(config_hash);
bail:
crm_time_free(now);
}
gboolean
crm_read_options(gpointer user_data)
{
int call_id =
fsa_cib_conn->cmds->query(fsa_cib_conn, XML_CIB_TAG_CRMCONFIG, NULL, cib_scope_local);
fsa_register_cib_callback(call_id, FALSE, NULL, config_query_callback);
crm_trace("Querying the CIB... call %d", call_id);
return TRUE;
}
/* A_READCONFIG */
void
do_read_config(long long action,
enum crmd_fsa_cause cause,
enum crmd_fsa_state cur_state,
enum crmd_fsa_input current_input, fsa_data_t * msg_data)
{
throttle_init();
mainloop_set_trigger(config_read);
}
void
crm_shutdown(int nsig)
{
if (crmd_mainloop != NULL && g_main_is_running(crmd_mainloop)) {
if (is_set(fsa_input_register, R_SHUTDOWN)) {
crm_err("Escalating the shutdown");
register_fsa_input_before(C_SHUTDOWN, I_ERROR, NULL);
} else {
set_bit(fsa_input_register, R_SHUTDOWN);
register_fsa_input(C_SHUTDOWN, I_SHUTDOWN, NULL);
if (shutdown_escalation_timer->period_ms < 1) {
const char *value = crmd_pref(NULL, XML_CONFIG_ATTR_FORCE_QUIT);
int msec = crm_get_msec(value);
crm_debug("Using default shutdown escalation: %dms", msec);
shutdown_escalation_timer->period_ms = msec;
}
/* can't rely on this... */
crm_notice("Requesting shutdown, upper limit is %dms",
shutdown_escalation_timer->period_ms);
crm_timer_start(shutdown_escalation_timer);
}
} else {
crm_info("exit from shutdown");
crmd_exit(pcmk_ok);
}
}
diff --git a/crmd/notify.c b/crmd/notify.c
index d5e211a09f..56cce3ba7a 100644
--- a/crmd/notify.c
+++ b/crmd/notify.c
@@ -1,199 +1,790 @@
/*
* Copyright (C) 2015 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
*/
#include <crm_internal.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
+#include <crm/pengine/rules.h>
#include "notify.h"
+#include "crmd_messages.h"
char *notify_script = NULL;
char *notify_target = NULL;
+GListPtr notify_list = NULL;
+
+typedef struct {
+ char *name;
+ char *value;
+} envvar_t;
+
+typedef struct {
+ char *id;
+ char *path;
+ int timeout;
+ char *tstamp_format;
+ char *recipient;
+ GListPtr envvars;
+} notify_entry_t;
+
+enum notify_keys_e{
+ CRM_notify_recipient = 0,
+ CRM_notify_node,
+ CRM_notify_nodeid,
+ CRM_notify_rsc,
+ CRM_notify_task,
+ CRM_notify_interval,
+ CRM_notify_desc,
+ CRM_notify_status,
+ CRM_notify_target_rc,
+ CRM_notify_rc,
+ CRM_notify_kind,
+ CRM_notify_version,
+ CRM_notify_node_sequence,
+ CRM_notify_timestamp
+};
+
+/*
+ * to allow script compatibility we can have more than one
+ * set of environment variables
+ */
+static const char *notify_keys[][3] =
+{
+ [CRM_notify_recipient] = {"CRM_notify_recipient", "CRM_alert_recipient", NULL},
+ [CRM_notify_node] = {"CRM_notify_node", "CRM_alert_node", NULL},
+ [CRM_notify_nodeid] = {"CRM_notify_nodeid", "CRM_alert_nodeid", NULL},
+ [CRM_notify_rsc] = {"CRM_notify_rsc", "CRM_alert_rsc", NULL},
+ [CRM_notify_task] = {"CRM_notify_task", "CRM_alert_task", NULL},
+ [CRM_notify_interval] = {"CRM_notify_interval", "CRM_alert_interval", NULL},
+ [CRM_notify_desc] = {"CRM_notify_desc", "CRM_alert_desc", NULL},
+ [CRM_notify_status] = {"CRM_notify_status", "CRM_alert_status", NULL},
+ [CRM_notify_target_rc] = {"CRM_notify_target_rc", "CRM_alert_target_rc", NULL},
+ [CRM_notify_rc] = {"CRM_notify_rc", "CRM_alert_rc", NULL},
+ [CRM_notify_kind] = {"CRM_notify_kind", "CRM_alert_kind", NULL},
+ [CRM_notify_version] = {"CRM_notify_version", "CRM_alert_version", NULL},
+ [CRM_notify_node_sequence] = {"CRM_notify_node_sequence", "CRM_alert_node_sequence", NULL},
+ [CRM_notify_timestamp] = {"CRM_notify_timestamp", "CRM_alert_timestamp", NULL}
+};
+
+/*
+ * higher accuracy time stuff to be generalized and moved to
+ * e.g. lib/common/utils.c|iso8601.c
+ */
+
+#include <time.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <crm/common/iso8601.h>
+
+typedef struct crm_time_us crm_time_hr_t;
+crm_time_hr_t *crm_time_hr_convert(crm_time_hr_t *target, crm_time_t *dt);
+void crm_time_set_hr_dt(crm_time_t *target, crm_time_hr_t *hr_dt);
+crm_time_hr_t *crm_time_timeval_hr_convert(crm_time_hr_t *target,
+ struct timeval *tv);
+crm_time_hr_t *crm_time_hr_new(const char *date_time);
+void crm_time_hr_free(crm_time_hr_t * hr_dt);
+char *crm_time_format_hr(const char *format, crm_time_hr_t * hr_dt);
+
+crm_time_t *parse_date(const char *date_str); /* in iso8601.c global but
+ not in header */
+
+struct crm_time_us {
+ int years;
+ int months; /* Only for durations */
+ int days;
+ int seconds;
+ int offset; /* Seconds */
+ bool duration;
+ int useconds;
+};
-static const char *notify_keys[] =
-{
- "CRM_notify_recipient",
- "CRM_notify_node",
- "CRM_notify_nodeid",
- "CRM_notify_rsc",
- "CRM_notify_task",
- "CRM_notify_interval",
- "CRM_notify_desc",
- "CRM_notify_status",
- "CRM_notify_target_rc",
- "CRM_notify_rc",
- "CRM_notify_kind",
- "CRM_notify_version",
+struct crm_time_s {
+ int years;
+ int months; /* Only for durations */
+ int days;
+ int seconds;
+ int offset; /* Seconds */
+ bool duration;
};
+
+static void
+ha_get_tm_time( struct tm *target, crm_time_t *source)
+{
+ *target = (struct tm) {
+ .tm_year = source->years - 1900,
+ .tm_yday = source->days - 1,
+ .tm_sec = source->seconds % 60,
+ .tm_min = ( source->seconds / 60 ) % 60,
+ .tm_hour = source->seconds / 60 / 60,
+
+#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
+ .tm_gmtoff = source->offset
+#endif
+ };
+}
+
+crm_time_hr_t *
+crm_time_hr_convert(crm_time_hr_t *target, crm_time_t *dt)
+{
+ crm_time_hr_t *hr_dt = NULL;
+
+ if (dt) {
+ hr_dt = target?target:calloc(1, sizeof(crm_time_hr_t));
+ if (hr_dt) {
+ *hr_dt = (crm_time_hr_t) {
+ .years = dt->years,
+ .months = dt->months,
+ .days = dt->days,
+ .seconds = dt->seconds,
+ .offset = dt->offset,
+ .duration = dt->duration
+ };
+ }
+ }
+
+ return hr_dt;
+}
+
void
-crmd_enable_notifications(const char *script, const char *target)
+crm_time_set_hr_dt(crm_time_t *target, crm_time_hr_t *hr_dt)
{
- free(notify_script);
- notify_script = NULL;
+ CRM_ASSERT((hr_dt) && (target));
+ *target = (crm_time_t) {
+ .years = hr_dt->years,
+ .months = hr_dt->months,
+ .days = hr_dt->days,
+ .seconds = hr_dt->seconds,
+ .offset = hr_dt->offset,
+ .duration = hr_dt->duration
+ };
+}
- free(notify_target);
- notify_target = NULL;
+crm_time_hr_t *
+crm_time_timeval_hr_convert(crm_time_hr_t *target, struct timeval *tv)
+{
+ crm_time_t dt;
+ crm_time_hr_t *ret;
+
+ crm_time_set_timet(&dt, &tv->tv_sec);
+ ret = crm_time_hr_convert(target, &dt);
+ if (ret) {
+ ret->useconds = tv->tv_usec;
+ }
+ return ret;
+}
+
+crm_time_hr_t *
+crm_time_hr_new(const char *date_time)
+{
+ crm_time_hr_t *hr_dt = NULL;
+ struct timeval tv_now;
+
+ if (!date_time) {
+ if (gettimeofday(&tv_now, NULL) == 0) {
+ hr_dt = crm_time_timeval_hr_convert(NULL, &tv_now);
+ }
+ } else {
+ crm_time_t *dt;
+
+ dt = parse_date(date_time);
+ hr_dt = crm_time_hr_convert(NULL, dt);
+ crm_time_free(dt);
+ }
+ return hr_dt;
+}
+
+void
+crm_time_hr_free(crm_time_hr_t * hr_dt)
+{
+ free(hr_dt);
+}
+
+char *
+crm_time_format_hr(const char *format, crm_time_hr_t * hr_dt)
+{
+ const char *mark_s;
+ int max = 128, scanned_pos = 0, printed_pos = 0, fmt_pos = 0,
+ date_len = 0, nano_digits, fmt_len;
+ char nano_s[10], date_s[max+1], nanofmt_s[5] = "%", *tmp_fmt_s;
+ struct tm tm;
+ crm_time_t dt;
+
+ if (!format) {
+ return NULL;
+ }
+ crm_time_set_hr_dt(&dt, hr_dt);
+ ha_get_tm_time(&tm, &dt);
+ sprintf(nano_s, "%06d000", hr_dt->useconds);
+
+ while ((format[scanned_pos]) != '\0') {
+ fmt_len = 0;
+ mark_s = strchr(&format[scanned_pos], '%');
+ if (mark_s) {
+ fmt_pos = mark_s - format;
+ fmt_len = 1;
+ while ((format[fmt_pos+fmt_len] != '\0') &&
+ (format[fmt_pos+fmt_len] >= '0') &&
+ (format[fmt_pos+fmt_len] <= '9')) {
+ fmt_len++;
+ }
+ scanned_pos = fmt_pos + fmt_len + 1;
+ if (format[fmt_pos+fmt_len] == 'N') {
+ nano_digits = atoi(&format[fmt_pos+1]);
+ nano_digits = (nano_digits > 6)?6:nano_digits;
+ nano_digits = (nano_digits < 0)?0:nano_digits;
+ sprintf(&nanofmt_s[1], ".%ds", nano_digits);
+ } else {
+ if (format[fmt_pos+fmt_len] != 0) {
+ continue;
+ }
+ fmt_pos = scanned_pos; /* print till end */
+ }
+ } else {
+ scanned_pos = strlen(format);
+ fmt_pos = scanned_pos; /* print till end */
+ }
+ tmp_fmt_s = strndup(&format[printed_pos], fmt_pos - printed_pos);
+#ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
+ date_len += strftime(&date_s[date_len], max-date_len, tmp_fmt_s, &tm);
+#ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
+#pragma GCC diagnostic pop
+#endif
+ printed_pos = scanned_pos;
+ free(tmp_fmt_s);
+ if (nano_digits) {
+#ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#endif
+ date_len += snprintf(&date_s[date_len], max-date_len,
+ nanofmt_s, nano_s);
+#ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
+#pragma GCC diagnostic pop
+#endif
+ nano_digits = 0;
+ }
+ }
+
+ return (date_len == 0)?NULL:strdup(date_s);
+}
+
+/*
+ * end of possibly generic time-handling stuff
+ */
+
+
+/*
+ * syncronize local data with cib
+ */
+
+static void
+free_envvar_entry(envvar_t *entry)
+{
+ free(entry->name);
+ free(entry->value);
+ free(entry);
+}
+
+static void
+free_notify_list_entry(notify_entry_t *entry)
+{
+ free(entry->id);
+ free(entry->path);
+ free(entry->tstamp_format);
+ free(entry->recipient);
+ if (entry->envvars) {
+ g_list_free_full(entry->envvars,
+ (GDestroyNotify) free_envvar_entry);
+ }
+ free(entry);
+}
+
+static void
+free_notify_list()
+{
+ if (notify_list) {
+ g_list_free_full(notify_list, (GDestroyNotify) free_notify_list_entry);
+ notify_list = NULL;
+ }
+}
+
+static gpointer
+copy_envvar_entry(envvar_t * src,
+ gpointer data)
+{
+ envvar_t *dst = calloc(1, sizeof(envvar_t));
+
+ CRM_ASSERT(dst);
+ dst->name = strdup(src->name);
+ dst->value = src->value?strdup(src->value):NULL;
+ return (gpointer) dst;
+}
+
+static GListPtr
+add_dup_envvar(GListPtr envvar_list,
+ envvar_t *entry)
+{
+ return g_list_prepend(envvar_list, copy_envvar_entry(entry, NULL));
+}
+
+static GListPtr
+drop_envvars(GListPtr envvar_list, int count)
+{
+ int i;
+
+ for (i = 0;
+ (envvar_list) && ((count < 0) || (i < count));
+ i++) {
+ free_envvar_entry((envvar_t *) g_list_first(envvar_list)->data);
+ envvar_list = g_list_delete_link(envvar_list,
+ g_list_first(envvar_list));
+ }
+ return envvar_list;
+}
+
+static GListPtr
+copy_envvar_list_remove_dupes(GListPtr src)
+{
+ GListPtr dst = NULL, ls, ld;
+
+ /* we are adding to the front so variable dupes coming via
+ * recipient-section have got precedence over those in the
+ * global section - we don't expect that many variables here
+ * that it pays off to go for a hash-table to make dupe elimination
+ * more efficient - maybe later when we might decide to do more
+ * with the variables than cycling through them
+ */
+
+ for (ls = g_list_first(src); ls; ls = g_list_next(ls)) {
+ for (ld = g_list_first(dst); ld; ld = g_list_next(ld)) {
+ if (!strcmp(((envvar_t *)(ls->data))->name,
+ ((envvar_t *)(ld->data))->name)) {
+ break;
+ }
+ }
+ if (!ld) {
+ dst = g_list_prepend(dst,
+ copy_envvar_entry((envvar_t *)(ls->data), NULL));
+ }
+ }
+
+ return dst;
+}
+
+static void
+add_dup_notify_list_entry(notify_entry_t *entry)
+{
+ notify_entry_t *new_entry =
+ (notify_entry_t *) calloc(1, sizeof(notify_entry_t));
+
+ CRM_ASSERT(new_entry);
+ *new_entry = (notify_entry_t) {
+ .id = strdup(entry->id),
+ .path = strdup(entry->path),
+ .timeout = entry->timeout,
+ .tstamp_format = entry->tstamp_format?strdup(entry->tstamp_format):NULL,
+ .recipient = entry->recipient?strdup(entry->recipient):NULL,
+ .envvars = entry->envvars?
+ copy_envvar_list_remove_dupes(entry->envvars)
+ :NULL
+ };
+ notify_list = g_list_prepend(notify_list, new_entry);
+}
+
+static GListPtr
+get_envvars_from_cib(xmlNode *basenode, GListPtr list, int *count)
+{
+ xmlNode *envvar;
+ xmlNode *pair;
+
+ if ((!basenode) ||
+ (!(envvar = first_named_child(basenode, XML_TAG_ATTR_SETS)))) {
+ return list;
+ }
+
+ for (pair = first_named_child(envvar, XML_CIB_TAG_NVPAIR);
+ pair; pair = __xml_next(pair)) {
+
+ envvar_t envvar_entry = (envvar_t) {
+ .name = (char *) crm_element_value(pair, XML_NVPAIR_ATTR_NAME),
+ .value = (char *) crm_element_value(pair, XML_NVPAIR_ATTR_VALUE)
+ };
+ crm_trace("Found environment variable %s = '%s'", envvar_entry.name,
+ envvar_entry.value?envvar_entry.value:"");
+ (*count)++;
+ list = add_dup_envvar(list, &envvar_entry);
+ }
+
+ return list;
+}
+
+static GHashTable *
+get_meta_attrs_from_cib(xmlNode *basenode, notify_entry_t *entry)
+{
+ GHashTable *config_hash =
+ g_hash_table_new_full(crm_str_hash, g_str_equal,
+ g_hash_destroy_str, g_hash_destroy_str);
+ crm_time_t *now = crm_time_new(NULL);
+ const char *value = NULL;
+
+ unpack_instance_attributes(basenode, basenode, XML_TAG_META_SETS, NULL,
+ config_hash, NULL, FALSE, now);
+
+ value = g_hash_table_lookup(config_hash, XML_NOTIFY_ATTR_TIMEOUT);
+ if (value) {
+ entry->timeout = crm_get_msec(value);
+ crm_trace("Found timeout %dmsec", entry->timeout);
+ }
+ value = g_hash_table_lookup(config_hash, XML_NOTIFY_ATTR_TSTAMP_FORMAT);
+ if (value) {
+ entry->tstamp_format = (char *) value;
+ crm_trace("Found timestamp format string '%s'", value);
+ }
+
+ crm_time_free(now);
+ return config_hash; /* keep hash as long as strings are needed */
+}
+
+void
+notifications_query_callback(xmlNode * msg, int call_id, int rc,
+ xmlNode * output, void *user_data)
+{
+ xmlNode *notify = output;
+ notify_entry_t entry;
+
+ free_notify_list();
+
+ if (rc != pcmk_ok) {
+ crm_info("No optional alerts section in cib");
+
+ if (notify_script) {
+ entry = (notify_entry_t) {
+ .id = (char *) "legacy_notification",
+ .path = notify_script,
+ .timeout = CRMD_NOTIFY_DEFAULT_TIMEOUT_MS,
+ .recipient = notify_target
+ };
+ add_dup_notify_list_entry(&entry);
+ crm_info("Legacy Notifications enabled");
+ }
- if(script == NULL || safe_str_eq(script, "/dev/null")) {
- crm_notice("Notifications disabled");
return;
+ } else {
+ crm_info("We have an alerts section in the cib");
+
+ if (notify_script) {
+ crm_warn("Cib contains configuration for Legacy Notifications "
+ "which is overruled by alerts section");
+ }
+ }
+
+ if ((notify) &&
+ (crm_element_name(notify)) &&
+ (strcmp(crm_element_name(notify), XML_CIB_TAG_NOTIFY) != 0)) {
+ notify = first_named_child(notify, XML_CIB_TAG_NOTIFY);
}
- notify_script = strdup(script);
- notify_target = strdup(target);
- crm_notice("Notifications enabled");
+ for (; notify; notify = __xml_next(notify)) {
+ xmlNode *recipient;
+ int recipients = 0, envvars = 0;
+ GHashTable *config_hash = NULL;
+
+ entry = (notify_entry_t) {
+ .id = (char *) crm_element_value(notify, XML_ATTR_ID),
+ .path = (char *) crm_element_value(notify, XML_NOTIFY_ATTR_PATH),
+ .timeout = CRMD_NOTIFY_DEFAULT_TIMEOUT_MS
+ };
+
+ entry.envvars =
+ get_envvars_from_cib(notify,
+ entry.envvars,
+ &envvars);
+
+ config_hash =
+ get_meta_attrs_from_cib(notify, &entry);
+
+ crm_debug("Found notification: id=%s, path=%s, timeout=%d, "
+ "tstamp_format=%s, %d additional environment variables",
+ entry.id, entry.path, entry.timeout,
+ entry.tstamp_format, envvars);
+
+ for (recipient = first_named_child(notify,
+ XML_CIB_TAG_NOTIFY_RECIPIENT);
+ recipient; recipient = __xml_next(recipient)) {
+ int envvars_added = 0;
+
+ entry.recipient = (char *) crm_element_value(recipient,
+ XML_NOTIFY_ATTR_REC_VALUE);
+ recipients++;
+
+ entry.envvars =
+ get_envvars_from_cib(recipient,
+ entry.envvars,
+ &envvars_added);
+
+ {
+ notify_entry_t recipient_entry = entry;
+ GHashTable *config_hash =
+ get_meta_attrs_from_cib(recipient,
+ &recipient_entry);
+
+ add_dup_notify_list_entry(&recipient_entry);
+
+ crm_debug("Notification has recipient: id=%s, value=%s, "
+ "%d additional environment variables",
+ crm_element_value(recipient, XML_ATTR_ID),
+ recipient_entry.recipient, envvars_added);
+
+ g_hash_table_destroy(config_hash);
+ }
+
+ entry.envvars =
+ drop_envvars(entry.envvars, envvars_added);
+ }
+
+ if (recipients == 0) {
+ add_dup_notify_list_entry(&entry);
+ }
+
+ drop_envvars(entry.envvars, -1);
+ g_hash_table_destroy(config_hash);
+ }
+}
+
+/*
+ * end of synchronization of local data with cib
+ */
+
+void
+crmd_enable_notifications(const char *script, const char *target)
+{
+ free(notify_script);
+ notify_script = ((script) &&
+ (strcmp(script,"/dev/null")))?strdup(script):NULL;
+
+ free(notify_target);
+ notify_target = (target != NULL)?strdup(target):NULL;
}
static void
-set_notify_key(const char *name, const char *cvalue, char *value)
+set_notify_key(enum notify_keys_e name, const char *cvalue, char *value)
{
- int lpc;
- bool found = 0;
+ const char **key;
- if(cvalue == NULL) {
+ if(!cvalue) {
cvalue = value;
}
- for(lpc = 0; lpc < DIMOF(notify_keys); lpc++) {
- if(safe_str_eq(name, notify_keys[lpc])) {
- found = 1;
- crm_trace("Setting notify key %s = '%s'", name, cvalue);
- setenv(name, cvalue, 1);
- break;
+ for(key = notify_keys[name]; *key; key++) {
+ crm_trace("Setting notify key %s = '%s'", *key, cvalue);
+ if (cvalue) {
+ setenv(*key, cvalue, 1);
+ } else {
+ unsetenv(*key);
}
}
- CRM_ASSERT(found != 0);
free(value);
}
-static void crmd_notify_complete(svc_action_t *op)
+static void
+unset_notify_keys()
+{
+ const char **key;
+ enum notify_keys_e name;
+
+ for(name = 0; name < DIMOF(notify_keys); name++) {
+ for(key = notify_keys[name]; *key; key++) {
+ crm_trace("Unsetting notify key %s", *key);
+ unsetenv(*key);
+ }
+ }
+}
+
+static void
+set_envvar_list(GListPtr envvars)
+{
+ GListPtr l;
+
+ for (l = g_list_first(envvars); l; l = g_list_next(l)) {
+ envvar_t *entry = (envvar_t *)(l->data);
+
+ crm_trace("Setting environment variable %s = '%s'", entry->name,
+ entry->value?entry->value:"");
+ if (entry->value) {
+ setenv(entry->name, entry->value, 1);
+ } else {
+ unsetenv(entry->name);
+ }
+ }
+}
+
+static void
+unset_envvar_list(GListPtr envvars)
+{
+ GListPtr l;
+
+ for (l = g_list_first(envvars); l; l = g_list_next(l)) {
+ envvar_t *entry = (envvar_t *)(l->data);
+
+ crm_trace("Unsetting environment variable %s", entry->name);
+ unsetenv(entry->name);
+ }
+}
+
+static void
+crmd_notify_complete(svc_action_t *op)
{
if(op->rc == 0) {
crm_info("Notification %d (%s) complete", op->sequence, op->agent);
} else {
- crm_warn("Notification %d (%s) failed: %d", op->sequence, op->agent, op->rc);
+ crm_warn("Notification %d (%s) failed: %d", op->sequence, op->agent,
+ op->rc);
}
}
static void
-send_notification(const char *kind)
+send_notifications(const char *kind)
{
- int lpc;
svc_action_t *notify = NULL;
static int operations = 0;
+ GListPtr l;
+ crm_time_hr_t *now = crm_time_hr_new(NULL);
+
+ set_notify_key(CRM_notify_kind, kind, NULL);
+ set_notify_key(CRM_notify_version, VERSION, NULL);
+
+ for (l = g_list_first(notify_list); l; l = g_list_next(l)) {
+ notify_entry_t *entry = (notify_entry_t *)(l->data);
+ char *timestamp = crm_time_format_hr(entry->tstamp_format, now);
+
+ operations++;
+ crm_debug("Sending '%s' notification to '%s' via '%s'", kind,
+ entry->recipient, entry->path);
+ set_notify_key(CRM_notify_recipient, entry->recipient, NULL);
+ set_notify_key(CRM_notify_node_sequence, crm_itoa(operations), NULL);
+ set_notify_key(CRM_notify_timestamp, timestamp, NULL);
- crm_debug("Sending '%s' notification to '%s' via '%s'", kind, notify_target, notify_script);
+ notify = services_action_create_generic(entry->path, NULL);
- set_notify_key("CRM_notify_recipient", notify_target, NULL);
- set_notify_key("CRM_notify_kind", kind, NULL);
- set_notify_key("CRM_notify_version", VERSION, NULL);
+ notify->timeout = entry->timeout;
+ notify->standard = strdup("event");
+ notify->id = strdup(entry->id);
+ notify->agent = strdup(entry->path);
+ notify->sequence = operations;
- notify = services_action_create_generic(notify_script, NULL);
+ set_envvar_list(entry->envvars);
- notify->timeout = CRMD_NOTIFY_TIMEOUT_MS;
- notify->standard = strdup("event");
- notify->id = strdup(notify_script);
- notify->agent = strdup(notify_script);
- notify->sequence = ++operations;
+ if(services_action_async(notify, &crmd_notify_complete) == FALSE) {
+ services_action_free(notify);
+ }
+
+ unset_envvar_list(entry->envvars);
- if(services_action_async(notify, &crmd_notify_complete) == FALSE) {
- services_action_free(notify);
+ free(timestamp);
}
- for(lpc = 0; lpc < DIMOF(notify_keys); lpc++) {
- unsetenv(notify_keys[lpc]);
+ unset_notify_keys();
+ if (now) {
+ free(now);
}
}
-void crmd_notify_node_event(crm_node_t *node)
+void
+crmd_notify_node_event(crm_node_t *node)
{
- if(notify_script == NULL) {
+ if(!notify_list) {
return;
}
- set_notify_key("CRM_notify_node", node->uname, NULL);
- set_notify_key("CRM_notify_nodeid", NULL, crm_itoa(node->id));
- set_notify_key("CRM_notify_desc", node->state, NULL);
+ set_notify_key(CRM_notify_node, node->uname, NULL);
+ set_notify_key(CRM_notify_nodeid, NULL, crm_itoa(node->id));
+ set_notify_key(CRM_notify_desc, node->state, NULL);
- send_notification("node");
+ send_notifications("node");
}
void
crmd_notify_fencing_op(stonith_event_t * e)
{
char *desc = NULL;
- if (notify_script == NULL) {
+ if (!notify_list) {
return;
}
- desc = crm_strdup_printf("Operation %s requested by %s for peer %s: %s (ref=%s)",
- e->operation, e->origin, e->target, pcmk_strerror(e->result),
- e->id);
+ desc = crm_strdup_printf(
+ "Operation %s requested by %s for peer %s: %s (ref=%s)",
+ e->operation, e->origin, e->target, pcmk_strerror(e->result),
+ e->id);
- set_notify_key("CRM_notify_node", e->target, NULL);
- set_notify_key("CRM_notify_task", e->operation, NULL);
- set_notify_key("CRM_notify_desc", NULL, desc);
- set_notify_key("CRM_notify_rc", NULL, crm_itoa(e->result));
+ set_notify_key(CRM_notify_node, e->target, NULL);
+ set_notify_key(CRM_notify_task, e->operation, NULL);
+ set_notify_key(CRM_notify_desc, NULL, desc);
+ set_notify_key(CRM_notify_rc, NULL, crm_itoa(e->result));
- send_notification("fencing");
+ send_notifications("fencing");
}
void
crmd_notify_resource_op(const char *node, lrmd_event_data_t * op)
{
int target_rc = 0;
- if(notify_script == NULL) {
+ if(!notify_list) {
return;
}
target_rc = rsc_op_expected_rc(op);
- if(op->interval == 0 && target_rc == op->rc && safe_str_eq(op->op_type, RSC_STATUS)) {
+ if(op->interval == 0 && target_rc == op->rc &&
+ safe_str_eq(op->op_type, RSC_STATUS)) {
/* Leave it up to the script if they want to notify for
* 'failed' probes, only swallow ones for which the result was
* unexpected.
*
* Even if we find a resource running, it was probably because
* someone erased the status section.
*/
return;
}
- set_notify_key("CRM_notify_node", node, NULL);
+ set_notify_key(CRM_notify_node, node, NULL);
- set_notify_key("CRM_notify_rsc", op->rsc_id, NULL);
- set_notify_key("CRM_notify_task", op->op_type, NULL);
- set_notify_key("CRM_notify_interval", NULL, crm_itoa(op->interval));
+ set_notify_key(CRM_notify_rsc, op->rsc_id, NULL);
+ set_notify_key(CRM_notify_task, op->op_type, NULL);
+ set_notify_key(CRM_notify_interval, NULL, crm_itoa(op->interval));
- set_notify_key("CRM_notify_target_rc", NULL, crm_itoa(target_rc));
- set_notify_key("CRM_notify_status", NULL, crm_itoa(op->op_status));
- set_notify_key("CRM_notify_rc", NULL, crm_itoa(op->rc));
+ set_notify_key(CRM_notify_target_rc, NULL, crm_itoa(target_rc));
+ set_notify_key(CRM_notify_status, NULL, crm_itoa(op->op_status));
+ set_notify_key(CRM_notify_rc, NULL, crm_itoa(op->rc));
if(op->op_status == PCMK_LRM_OP_DONE) {
- set_notify_key("CRM_notify_desc", services_ocf_exitcode_str(op->rc), NULL);
+ set_notify_key(CRM_notify_desc,
+ services_ocf_exitcode_str(op->rc), NULL);
} else {
- set_notify_key("CRM_notify_desc", services_lrm_status_str(op->op_status), NULL);
+ set_notify_key(CRM_notify_desc,
+ services_lrm_status_str(op->op_status), NULL);
}
- send_notification("resource");
-}
-
+ send_notifications("resource");
+}
\ No newline at end of file
diff --git a/crmd/notify.h b/crmd/notify.h
index 131203834f..406a108c61 100644
--- a/crmd/notify.h
+++ b/crmd/notify.h
@@ -1,33 +1,34 @@
/*
* Copyright (C) 2015 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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 Lesser 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
*/
#ifndef CRMD_NOTIFY__H
# define CRMD_NOTIFY__H
# include <crm/crm.h>
# include <crm/cluster.h>
# include <crm/stonith-ng.h>
-/* Timeout to use before killing a notification script (in milliseconds) */
-# define CRMD_NOTIFY_TIMEOUT_MS (300000)
+/* Default-Timeout to use before killing a notification script (in milliseconds) */
+# define CRMD_NOTIFY_DEFAULT_TIMEOUT_MS (300000)
void crmd_enable_notifications(const char *script, const char *target);
void crmd_notify_node_event(crm_node_t *node);
void crmd_notify_fencing_op(stonith_event_t * e);
void crmd_notify_resource_op(const char *node, lrmd_event_data_t * op);
+void notifications_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data);
#endif
diff --git a/extra/pcmk_notify_sample.sh b/extra/alerts/pcmk_alert_sample.sh
similarity index 71%
rename from extra/pcmk_notify_sample.sh
rename to extra/alerts/pcmk_alert_sample.sh
index 83cf8e9355..f6ca070a18 100755
--- a/extra/pcmk_notify_sample.sh
+++ b/extra/alerts/pcmk_alert_sample.sh
@@ -1,68 +1,73 @@
#!/bin/bash
#
# Copyright (C) 2015 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
if [ -z $CRM_notify_version ]; then
echo "Pacemaker version 1.1.14 is required" >> ${CRM_notify_recipient}
exit 0
fi
+tstamp=`printf "%04d. " "$CRM_notify_node_sequence"`
+if [ ! -z $CRM_notify_timestamp ]; then
+ tstamp="${tstamp} $CRM_notify_timestamp (`date "+%H:%M:%S.%06N"`): "
+fi
+
case $CRM_notify_kind in
node)
- echo "Node '${CRM_notify_node}' is now '${CRM_notify_desc}'" >> ${CRM_notify_recipient}
+ echo "${tstamp}Node '${CRM_notify_node}' is now '${CRM_notify_desc}'" >> ${CRM_notify_recipient}
;;
fencing)
# Other keys:
#
# CRM_notify_node
# CRM_notify_task
# CRM_notify_rc
#
- echo "Fencing ${CRM_notify_desc}" >> ${CRM_notify_recipient}
+ echo "${tstamp}Fencing ${CRM_notify_desc}" >> ${CRM_notify_recipient}
;;
resource)
# Other keys:
#
# CRM_notify_target_rc
# CRM_notify_status
# CRM_notify_rc
#
if [ ${CRM_notify_interval} = "0" ]; then
CRM_notify_interval=""
else
CRM_notify_interval=" (${CRM_notify_interval})"
fi
if [ ${CRM_notify_target_rc} = "0" ]; then
CRM_notify_target_rc=""
else
CRM_notify_target_rc=" (target: ${CRM_notify_target_rc})"
fi
case ${CRM_notify_desc} in
Cancelled) ;;
*)
- echo "Resource operation '${CRM_notify_task}${CRM_notify_interval}' for '${CRM_notify_rsc}' on '${CRM_notify_node}': ${CRM_notify_desc}${CRM_notify_target_rc}" >> ${CRM_notify_recipient}
+ echo "${tstamp}Resource operation '${CRM_notify_task}${CRM_notify_interval}' for '${CRM_notify_rsc}' on '${CRM_notify_node}': ${CRM_notify_desc}${CRM_notify_target_rc}" >> ${CRM_notify_recipient}
;;
esac
;;
*)
- echo "Unhandled $CRM_notify_kind notification" >> ${CRM_notify_recipient}
+ echo "${tstamp}Unhandled $CRM_notify_kind notification" >> ${CRM_notify_recipient}
env | grep CRM_notify >> ${CRM_notify_recipient}
;;
esac
diff --git a/extra/pcmk_snmp_helper.sh b/extra/alerts/pcmk_snmp_helper.sh
old mode 100644
new mode 100755
similarity index 100%
rename from extra/pcmk_snmp_helper.sh
rename to extra/alerts/pcmk_snmp_helper.sh
diff --git a/include/crm/msg_xml.h b/include/crm/msg_xml.h
index d8c72c3ad5..a18776e73d 100644
--- a/include/crm/msg_xml.h
+++ b/include/crm/msg_xml.h
@@ -1,418 +1,426 @@
/*
* 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 Lesser 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 Lesser 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
*/
#ifndef XML_TAGS__H
# define XML_TAGS__H
# ifndef F_ORIG
# define F_ORIG "src"
# endif
# ifndef F_SEQ
# define F_SEQ "seq"
# endif
# ifndef F_SUBTYPE
# define F_SUBTYPE "subt"
# endif
# ifndef F_TYPE
# define F_TYPE "t"
# endif
# ifndef F_CLIENTNAME
# define F_CLIENTNAME "cn"
# endif
# ifndef F_XML_TAGNAME
# define F_XML_TAGNAME "__name__"
# endif
# ifndef T_CRM
# define T_CRM "crmd"
# endif
# ifndef T_ATTRD
# define T_ATTRD "attrd"
# endif
# define CIB_OPTIONS_FIRST "cib-bootstrap-options"
# define F_CRM_DATA "crm_xml"
# define F_CRM_TASK "crm_task"
# define F_CRM_HOST_TO "crm_host_to"
# define F_CRM_MSG_TYPE F_SUBTYPE
# define F_CRM_SYS_TO "crm_sys_to"
# define F_CRM_SYS_FROM "crm_sys_from"
# define F_CRM_HOST_FROM F_ORIG
# define F_CRM_REFERENCE XML_ATTR_REFERENCE
# define F_CRM_VERSION XML_ATTR_VERSION
# define F_CRM_ORIGIN "origin"
# define F_CRM_USER "crm_user"
# define F_CRM_JOIN_ID "join_id"
# define F_CRM_ELECTION_ID "election-id"
# define F_CRM_ELECTION_AGE_S "election-age-sec"
# define F_CRM_ELECTION_AGE_US "election-age-nano-sec"
# define F_CRM_ELECTION_OWNER "election-owner"
# define F_CRM_TGRAPH "crm-tgraph"
# define F_CRM_TGRAPH_INPUT "crm-tgraph-in"
# define F_CRM_THROTTLE_MODE "crm-limit-mode"
# define F_CRM_THROTTLE_MAX "crm-limit-max"
/*---- Common tags/attrs */
# define XML_DIFF_MARKER "__crm_diff_marker__"
# define XML_ATTR_TAGNAME F_XML_TAGNAME
# define XML_TAG_CIB "cib"
# define XML_TAG_FAILED "failed"
# define XML_ATTR_CRM_VERSION "crm_feature_set"
# define XML_ATTR_DIGEST "digest"
# define XML_ATTR_VALIDATION "validate-with"
# define XML_ATTR_QUORUM_PANIC "no-quorum-panic"
# define XML_ATTR_HAVE_QUORUM "have-quorum"
# define XML_ATTR_HAVE_WATCHDOG "have-watchdog"
# define XML_ATTR_EXPECTED_VOTES "expected-quorum-votes"
# define XML_ATTR_GENERATION "epoch"
# define XML_ATTR_GENERATION_ADMIN "admin_epoch"
# define XML_ATTR_NUMUPDATES "num_updates"
# define XML_ATTR_TIMEOUT "timeout"
# define XML_ATTR_ORIGIN "crm-debug-origin"
# define XML_ATTR_TSTAMP "crm-timestamp"
# define XML_CIB_ATTR_WRITTEN "cib-last-written"
# define XML_ATTR_VERSION "version"
# define XML_ATTR_DESC "description"
# define XML_ATTR_ID "id"
# define XML_ATTR_IDREF "id-ref"
# define XML_ATTR_ID_LONG "long-id"
# define XML_ATTR_TYPE "type"
# define XML_ATTR_FILTER_TYPE "type-filter"
# define XML_ATTR_FILTER_ID "id-filter"
# define XML_ATTR_FILTER_PRIORITY "priority-filter"
# define XML_ATTR_VERBOSE "verbose"
# define XML_ATTR_OP "op"
# define XML_ATTR_DC "is_dc"
# define XML_ATTR_DC_UUID "dc-uuid"
# define XML_ATTR_UPDATE_ORIG "update-origin"
# define XML_ATTR_UPDATE_CLIENT "update-client"
# define XML_ATTR_UPDATE_USER "update-user"
# define XML_BOOLEAN_TRUE "true"
# define XML_BOOLEAN_FALSE "false"
# define XML_BOOLEAN_YES XML_BOOLEAN_TRUE
# define XML_BOOLEAN_NO XML_BOOLEAN_FALSE
# define XML_TAG_OPTIONS "options"
/*---- top level tags/attrs */
# define XML_MSG_TAG "crm_message"
# define XML_MSG_TAG_DATA "msg_data"
# define XML_ATTR_REQUEST "request"
# define XML_ATTR_RESPONSE "response"
# define XML_ATTR_UNAME "uname"
# define XML_ATTR_UUID "id"
# define XML_ATTR_REFERENCE "reference"
# define XML_FAIL_TAG_RESOURCE "failed_resource"
# define XML_FAILRES_ATTR_RESID "resource_id"
# define XML_FAILRES_ATTR_REASON "reason"
# define XML_FAILRES_ATTR_RESSTATUS "resource_status"
# define XML_CRM_TAG_PING "ping_response"
# define XML_PING_ATTR_STATUS "result"
# define XML_PING_ATTR_SYSFROM "crm_subsystem"
# define XML_TAG_FRAGMENT "cib_fragment"
# define XML_ATTR_RESULT "result"
# define XML_ATTR_SECTION "section"
# define XML_FAIL_TAG_CIB "failed_update"
# define XML_FAILCIB_ATTR_ID "id"
# define XML_FAILCIB_ATTR_OBJTYPE "object_type"
# define XML_FAILCIB_ATTR_OP "operation"
# define XML_FAILCIB_ATTR_REASON "reason"
/*---- CIB specific tags/attrs */
# define XML_CIB_TAG_SECTION_ALL "all"
# define XML_CIB_TAG_CONFIGURATION "configuration"
# define XML_CIB_TAG_STATUS "status"
# define XML_CIB_TAG_RESOURCES "resources"
# define XML_CIB_TAG_NODES "nodes"
# define XML_CIB_TAG_DOMAINS "domains"
# define XML_CIB_TAG_CONSTRAINTS "constraints"
# define XML_CIB_TAG_CRMCONFIG "crm_config"
# define XML_CIB_TAG_OPCONFIG "op_defaults"
# define XML_CIB_TAG_RSCCONFIG "rsc_defaults"
# define XML_CIB_TAG_ACLS "acls"
+# define XML_CIB_TAG_NOTIFICATIONS "alerts"
+# define XML_CIB_TAG_NOTIFY "alert"
+# define XML_CIB_TAG_NOTIFY_RECIPIENT "recipient"
# define XML_CIB_TAG_STATE "node_state"
# define XML_CIB_TAG_NODE "node"
# define XML_CIB_TAG_DOMAIN "domain"
# define XML_CIB_TAG_CONSTRAINT "constraint"
# define XML_CIB_TAG_NVPAIR "nvpair"
# define XML_CIB_TAG_PROPSET "cluster_property_set"
# define XML_TAG_ATTR_SETS "instance_attributes"
# define XML_TAG_META_SETS "meta_attributes"
# define XML_TAG_ATTRS "attributes"
# define XML_TAG_PARAMS "parameters"
# define XML_TAG_PARAM "param"
# define XML_TAG_UTILIZATION "utilization"
# define XML_TAG_RESOURCE_REF "resource_ref"
# define XML_CIB_TAG_RESOURCE "primitive"
# define XML_CIB_TAG_GROUP "group"
# define XML_CIB_TAG_INCARNATION "clone"
# define XML_CIB_TAG_MASTER "master"
# define XML_CIB_TAG_RSC_TEMPLATE "template"
# define XML_RSC_ATTR_ISOLATION_INSTANCE "isolation-instance"
# define XML_RSC_ATTR_ISOLATION_WRAPPER "isolation-wrapper"
# define XML_RSC_ATTR_ISOLATION_HOST "isolation-host"
# define XML_RSC_ATTR_ISOLATION "isolation"
# define XML_RSC_ATTR_RESTART "restart-type"
# define XML_RSC_ATTR_ORDERED "ordered"
# define XML_RSC_ATTR_INTERLEAVE "interleave"
# define XML_RSC_ATTR_INCARNATION "clone"
# define XML_RSC_ATTR_INCARNATION_MAX "clone-max"
# define XML_RSC_ATTR_INCARNATION_MIN "clone-min"
# define XML_RSC_ATTR_INCARNATION_NODEMAX "clone-node-max"
# define XML_RSC_ATTR_MASTER_MAX "master-max"
# define XML_RSC_ATTR_MASTER_NODEMAX "master-node-max"
# define XML_RSC_ATTR_STATE "clone-state"
# define XML_RSC_ATTR_MANAGED "is-managed"
# define XML_RSC_ATTR_TARGET_ROLE "target-role"
# define XML_RSC_ATTR_UNIQUE "globally-unique"
# define XML_RSC_ATTR_NOTIFY "notify"
# define XML_RSC_ATTR_STICKINESS "resource-stickiness"
# define XML_RSC_ATTR_FAIL_STICKINESS "migration-threshold"
# define XML_RSC_ATTR_FAIL_TIMEOUT "failure-timeout"
# define XML_RSC_ATTR_MULTIPLE "multiple-active"
# define XML_RSC_ATTR_PRIORITY "priority"
# define XML_RSC_ATTR_REQUIRES "requires"
# define XML_RSC_ATTR_PROVIDES "provides"
# define XML_RSC_ATTR_CONTAINER "container"
# define XML_RSC_ATTR_INTERNAL_RSC "internal_rsc"
# define XML_RSC_ATTR_MAINTENANCE "maintenance"
# define XML_RSC_ATTR_REMOTE_NODE "remote-node"
# define XML_REMOTE_ATTR_RECONNECT_INTERVAL "reconnect_interval"
# define XML_OP_ATTR_ON_FAIL "on-fail"
# define XML_OP_ATTR_START_DELAY "start-delay"
# define XML_OP_ATTR_ALLOW_MIGRATE "allow-migrate"
# define XML_OP_ATTR_DEPENDENT "dependent-on"
# define XML_OP_ATTR_ORIGIN "interval-origin"
# define XML_OP_ATTR_PENDING "record-pending"
# define XML_CIB_TAG_LRM "lrm"
# define XML_LRM_TAG_RESOURCES "lrm_resources"
# define XML_LRM_TAG_RESOURCE "lrm_resource"
# define XML_LRM_TAG_AGENTS "lrm_agents"
# define XML_LRM_TAG_AGENT "lrm_agent"
# define XML_LRM_TAG_RSC_OP "lrm_rsc_op"
# define XML_AGENT_ATTR_CLASS "class"
# define XML_AGENT_ATTR_PROVIDER "provider"
# define XML_LRM_TAG_ATTRIBUTES "attributes"
# define XML_CIB_ATTR_REPLACE "replace"
# define XML_CIB_ATTR_SOURCE "source"
# define XML_CIB_ATTR_HEALTH "health"
# define XML_CIB_ATTR_WEIGHT "weight"
# define XML_CIB_ATTR_PRIORITY "priority"
# define XML_CIB_ATTR_CLEAR "clear_on"
# define XML_CIB_ATTR_SOURCE "source"
# define XML_NODE_JOIN_STATE "join"
# define XML_NODE_EXPECTED "expected"
# define XML_NODE_IN_CLUSTER "in_ccm"
# define XML_NODE_IS_PEER "crmd"
# define XML_NODE_IS_REMOTE "remote_node"
# define XML_NODE_IS_FENCED "node_fenced"
# define XML_CIB_ATTR_SHUTDOWN "shutdown"
# define XML_CIB_ATTR_STONITH "stonith"
/* LRM is a bit of a misnomer here; the crmd and pengine use these to track
* actions, which usually but not always are LRM operations
*/
# define XML_LRM_ATTR_INTERVAL "interval"
# define XML_LRM_ATTR_TASK "operation"
# define XML_LRM_ATTR_TASK_KEY "operation_key"
# define XML_LRM_ATTR_TARGET "on_node"
# define XML_LRM_ATTR_TARGET_UUID "on_node_uuid"
/*! Actions to be executed on Pacemaker Remote nodes are routed through
* crmd on the cluster node hosting the remote connection. That cluster node
* is considered the router node for the action.
*/
# define XML_LRM_ATTR_ROUTER_NODE "router_node"
# define XML_LRM_ATTR_RSCID "rsc-id"
# define XML_LRM_ATTR_OPSTATUS "op-status"
# define XML_LRM_ATTR_RC "rc-code"
# define XML_LRM_ATTR_CALLID "call-id"
# define XML_LRM_ATTR_OP_DIGEST "op-digest"
# define XML_LRM_ATTR_OP_RESTART "op-force-restart"
# define XML_LRM_ATTR_OP_SECURE "op-secure-params"
# define XML_LRM_ATTR_RESTART_DIGEST "op-restart-digest"
# define XML_LRM_ATTR_SECURE_DIGEST "op-secure-digest"
# define XML_LRM_ATTR_EXIT_REASON "exit-reason"
# define XML_RSC_OP_LAST_CHANGE "last-rc-change"
# define XML_RSC_OP_LAST_RUN "last-run"
# define XML_RSC_OP_T_EXEC "exec-time"
# define XML_RSC_OP_T_QUEUE "queue-time"
# define XML_LRM_ATTR_MIGRATE_SOURCE "migrate_source"
# define XML_LRM_ATTR_MIGRATE_TARGET "migrate_target"
# define XML_TAG_GRAPH "transition_graph"
# define XML_GRAPH_TAG_RSC_OP "rsc_op"
# define XML_GRAPH_TAG_PSEUDO_EVENT "pseudo_event"
# define XML_GRAPH_TAG_CRM_EVENT "crm_event"
# define XML_GRAPH_TAG_DOWNED "downed"
# define XML_TAG_RULE "rule"
# define XML_RULE_ATTR_SCORE "score"
# define XML_RULE_ATTR_SCORE_ATTRIBUTE "score-attribute"
# define XML_RULE_ATTR_SCORE_MANGLED "score-attribute-mangled"
# define XML_RULE_ATTR_ROLE "role"
# define XML_RULE_ATTR_RESULT "result"
# define XML_RULE_ATTR_BOOLEAN_OP "boolean-op"
# define XML_TAG_EXPRESSION "expression"
# define XML_EXPR_ATTR_ATTRIBUTE "attribute"
# define XML_EXPR_ATTR_OPERATION "operation"
# define XML_EXPR_ATTR_VALUE "value"
# define XML_EXPR_ATTR_TYPE "type"
# define XML_CONS_TAG_RSC_DEPEND "rsc_colocation"
# define XML_CONS_TAG_RSC_ORDER "rsc_order"
# define XML_CONS_TAG_RSC_LOCATION "rsc_location"
# define XML_CONS_TAG_RSC_TICKET "rsc_ticket"
# define XML_CONS_TAG_RSC_SET "resource_set"
# define XML_CONS_ATTR_SYMMETRICAL "symmetrical"
# define XML_LOCATION_ATTR_DISCOVERY "resource-discovery"
# define XML_COLOC_ATTR_SOURCE "rsc"
# define XML_COLOC_ATTR_SOURCE_ROLE "rsc-role"
# define XML_COLOC_ATTR_TARGET "with-rsc"
# define XML_COLOC_ATTR_TARGET_ROLE "with-rsc-role"
# define XML_COLOC_ATTR_NODE_ATTR "node-attribute"
# define XML_COLOC_ATTR_SOURCE_INSTANCE "rsc-instance"
# define XML_COLOC_ATTR_TARGET_INSTANCE "with-rsc-instance"
# define XML_ORDER_ATTR_FIRST "first"
# define XML_ORDER_ATTR_THEN "then"
# define XML_ORDER_ATTR_FIRST_ACTION "first-action"
# define XML_ORDER_ATTR_THEN_ACTION "then-action"
# define XML_ORDER_ATTR_FIRST_INSTANCE "first-instance"
# define XML_ORDER_ATTR_THEN_INSTANCE "then-instance"
# define XML_ORDER_ATTR_KIND "kind"
# define XML_TICKET_ATTR_TICKET "ticket"
# define XML_TICKET_ATTR_LOSS_POLICY "loss-policy"
# define XML_NVPAIR_ATTR_NAME "name"
# define XML_NVPAIR_ATTR_VALUE "value"
# define XML_NODE_ATTR_STATE "state"
# define XML_NODE_ATTR_RSC_DISCOVERY "resource-discovery-enabled"
# define XML_CONFIG_ATTR_DC_DEADTIME "dc-deadtime"
# define XML_CONFIG_ATTR_ELECTION_FAIL "election-timeout"
# define XML_CONFIG_ATTR_FORCE_QUIT "shutdown-escalation"
# define XML_CONFIG_ATTR_RECHECK "cluster-recheck-interval"
+# define XML_NOTIFY_ATTR_PATH "path"
+# define XML_NOTIFY_ATTR_TIMEOUT "timeout"
+# define XML_NOTIFY_ATTR_TSTAMP_FORMAT "tstamp_format"
+# define XML_NOTIFY_ATTR_REC_VALUE "value"
+
# define XML_CIB_TAG_GENERATION_TUPPLE "generation_tuple"
# define XML_ATTR_TRANSITION_MAGIC "transition-magic"
# define XML_ATTR_TRANSITION_KEY "transition-key"
# define XML_ATTR_TE_NOWAIT "op_no_wait"
# define XML_ATTR_TE_TARGET_RC "op_target_rc"
# define XML_ATTR_LRM_PROBE "lrm-is-probe"
# define XML_TAG_TRANSIENT_NODEATTRS "transient_attributes"
# define XML_TAG_DIFF_ADDED "diff-added"
# define XML_TAG_DIFF_REMOVED "diff-removed"
# define XML_ACL_TAG_USER "acl_target"
# define XML_ACL_TAG_USERv1 "acl_user"
# define XML_ACL_TAG_GROUP "acl_group"
# define XML_ACL_TAG_ROLE "acl_role"
# define XML_ACL_TAG_PERMISSION "acl_permission"
# define XML_ACL_TAG_ROLE_REF "role"
# define XML_ACL_TAG_ROLE_REFv1 "role_ref"
# define XML_ACL_ATTR_KIND "kind"
# define XML_ACL_TAG_READ "read"
# define XML_ACL_TAG_WRITE "write"
# define XML_ACL_TAG_DENY "deny"
# define XML_ACL_ATTR_REF "reference"
# define XML_ACL_ATTR_REFv1 "ref"
# define XML_ACL_ATTR_TAG "object-type"
# define XML_ACL_ATTR_TAGv1 "tag"
# define XML_ACL_ATTR_XPATH "xpath"
# define XML_ACL_ATTR_ATTRIBUTE "attribute"
# define XML_CIB_TAG_TICKETS "tickets"
# define XML_CIB_TAG_TICKET_STATE "ticket_state"
# define XML_CIB_TAG_TAGS "tags"
# define XML_CIB_TAG_TAG "tag"
# define XML_CIB_TAG_OBJ_REF "obj_ref"
# define XML_TAG_FENCING_TOPOLOGY "fencing-topology"
# define XML_TAG_FENCING_LEVEL "fencing-level"
# define XML_ATTR_STONITH_INDEX "index"
# define XML_ATTR_STONITH_TARGET "target"
# define XML_ATTR_STONITH_TARGET_VALUE "target-value"
# define XML_ATTR_STONITH_TARGET_PATTERN "target-pattern"
# define XML_ATTR_STONITH_TARGET_ATTRIBUTE "target-attribute"
# define XML_ATTR_STONITH_DEVICES "devices"
# define XML_TAG_DIFF "diff"
# define XML_DIFF_VERSION "version"
# define XML_DIFF_VSOURCE "source"
# define XML_DIFF_VTARGET "target"
# define XML_DIFF_CHANGE "change"
# define XML_DIFF_LIST "change-list"
# define XML_DIFF_ATTR "change-attr"
# define XML_DIFF_RESULT "change-result"
# define XML_DIFF_OP "operation"
# define XML_DIFF_PATH "path"
# define XML_DIFF_POSITION "position"
/* Defined for backward API compatibility but no longer used by Pacemaker */
# define XML_ATTR_TE_ALLOWFAIL "op_allow_fail"
# include <crm/common/xml.h>
# define ID(x) crm_element_value(x, XML_ATTR_ID)
# define INSTANCE(x) crm_element_value(x, XML_CIB_ATTR_INSTANCE)
# define TSTAMP(x) crm_element_value(x, XML_ATTR_TSTAMP)
# define TYPE(x) crm_element_name(x)
# define NAME(x) crm_element_value(x, XML_NVPAIR_ATTR_NAME)
# define VALUE(x) crm_element_value(x, XML_NVPAIR_ATTR_VALUE)
#endif
diff --git a/xml/Makefile.am b/xml/Makefile.am
index d10e0d2a59..0487cc6729 100644
--- a/xml/Makefile.am
+++ b/xml/Makefile.am
@@ -1,175 +1,175 @@
#
# Copyright (C) 2004 Andrew Beekhof
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
MAINTAINERCLEANFILES = Makefile.in
dtddir = $(CRM_DTD_DIRECTORY)
dtd_DATA = crm.dtd crm-transitional.dtd
xsltdir = $(dtddir)
xslt_DATA = upgrade06.xsl upgrade-*.xsl
noinst_DATA = context-of.xsl
RNGdir = $(dtddir)
# See Readme.md for details on updating schema files
# Sorted list of available numeric RNG versions,
# extracted from filenames like NAME-MAJOR[.MINOR][.MINOR-MINOR].rng
RNG_numeric_versions = $(shell ls -1 *.rng \
| sed -n -e 's/^.*-\([0-9][0-9.]*\).rng$$/\1/p' \
| sort -u -t. -k 1,1n -k 2,2n -k 3,3n)
# The highest numeric version
RNG_max ?= $(lastword $(RNG_numeric_versions))
# A sorted list of all RNG versions (numeric and "next")
RNG_versions = next $(RNG_numeric_versions)
RNG_version_pairs = $(join \
${RNG_numeric_versions},$(addprefix \
-,$(wordlist \
2,$(words ${RNG_numeric_versions}),${RNG_numeric_versions} \
) next \
) \
)
RNG_version_pairs_cnt = $(words ${RNG_version_pairs})
RNG_version_pairs_last = $(wordlist \
$(words \
$(wordlist \
2,${RNG_version_pairs_cnt},${RNG_version_pairs} \
) \
),${RNG_version_pairs_cnt},${RNG_version_pairs} \
)
RNG_generated = pacemaker.rng $(foreach base,$(RNG_versions),pacemaker-$(base).rng) versions.rng
-RNG_cfg_base = options nodes resources constraints fencing acls tags
+RNG_cfg_base = options nodes resources constraints fencing acls tags alerts
RNG_base = cib $(RNG_cfg_base) status score rule nvset
RNG_files = $(foreach base,$(RNG_base),$(wildcard $(base)*.rng))
# List of non-Pacemaker RNGs
RNG_extra = crm_mon.rng
RNG_DATA = $(RNG_files) $(RNG_generated) $(RNG_extra)
EXTRA_DIST = best-match.sh
versions:
echo "Max: $(RNG_max)"
echo "Available: $(RNG_versions)"
versions.rng: Makefile.am
echo " RNG $@"
echo '<?xml version="1.0" encoding="UTF-8"?>' > $@
echo '<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">' >> $@
echo ' <start>' >> $@
echo ' <interleave>' >> $@
echo ' <optional>' >> $@
echo ' <attribute name="validate-with">' >> $@
echo ' <choice>' >> $@
echo ' <value>none</value>' >> $@
echo ' <value>pacemaker-0.6</value>' >> $@
echo ' <value>transitional-0.6</value>' >> $@
echo ' <value>pacemaker-0.7</value>' >> $@
echo ' <value>pacemaker-1.1</value>' >> $@
for rng in $(RNG_versions); do echo " <value>pacemaker-$$rng</value>" >> $@; done
echo ' </choice>' >> $@
echo ' </attribute>' >> $@
echo ' </optional>' >> $@
echo ' <attribute name="admin_epoch"><data type="nonNegativeInteger"/></attribute>' >> $@
echo ' <attribute name="epoch"><data type="nonNegativeInteger"/></attribute>' >> $@
echo ' <attribute name="num_updates"><data type="nonNegativeInteger"/></attribute>' >> $@
echo ' </interleave>' >> $@
echo ' </start>' >> $@
echo '</grammar>' >> $@
pacemaker.rng: pacemaker-$(RNG_max).rng
echo " RNG $@"
cp $(top_builddir)/xml/$< $@
pacemaker-%.rng: $(RNG_files) best-match.sh Makefile.am
echo " RNG $@"
echo '<?xml version="1.0" encoding="UTF-8"?>' > $@
echo '<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">' >> $@
echo ' <start>' >> $@
echo ' <element name="cib">' >> $@
./best-match.sh cib $(*) $(@) " "
echo ' <element name="configuration">' >> $@
echo ' <interleave>' >> $@
for rng in $(RNG_cfg_base); do ./best-match.sh $$rng $(*) $(@) " " || :; done
echo ' </interleave>' >> $@
echo ' </element>' >> $@
echo ' <optional>' >> $@
echo ' <element name="status">' >> $@
./best-match.sh status $(*) $(@) " "
echo ' </element>' >> $@
echo ' </optional>' >> $@
echo ' </element>' >> $@
echo ' </start>' >> $@
echo '</grammar>' >> $@
# diff fails with ec=2 if no predecessor is found;
# this uses '=' GNU extension to sed, if that's not available,
# one can use: hline=`echo "$${p}" | grep -Fn "$${hunk}" | cut -d: -f1`;
# XXX: use line information from hunk to avoid "not detected" for ambiguity
version_diff = \
@for p in $(1); do \
set `echo "$${p}" | tr '-' ' '`; \
echo "\#\#\# *-$$2.rng vs. predecessor"; \
for v in *-$$2.rng; do \
echo "\#\#\#\# $${v} vs. predecessor"; b=`echo "$${v}" | cut -d- -f1`; \
old=`./best-match.sh $${b} $$1`; \
p=`diff -u "$${old}" "$${v}" 2>/dev/null`; \
case $$? in \
1) echo "$${p}" | sed -n -e '/^@@ /!d;=;p' \
-e ':l;n;/^\([- ]\|+.*<[^ />]\+\([^/>]\+="ID\|>$$\)\)/bl;s/^[+ ]\(.*\)/\1/p' \
| while read hline; do \
read h && read i || break; \
iline=`grep -Fn "$${i}" "$${v}" | cut -d: -f1`; \
ctxt="(not detected)"; \
if test `echo "$${iline}" | wc -l` -eq 1; then \
ctxt=`{ sed -n -e "1,$$(($${iline}-1))p" "$${v}"; \
echo "<inject id=\"GOAL\"/>$${i}"; \
sed -n -e "$$(($${iline}+1)),$$ p" "$${v}"; \
} | $(XSLTPROC) --param skip 1 context-of.xsl -`; \
fi; \
echo "$${p}" | sed -n -e "$$(($${hline}-2)),$${hline}!d" \
-e '/^\(+++\|---\)/p'; \
echo "$${h} context: $${ctxt}"; \
echo "$${p}" | sed -n -e "1,$${hline}d" \
-e '/^\(---\|@@ \)/be;p;d;:e;n;be'; \
done; \
;; \
2) echo "\#\#\#\#\# $${v} has no predecessor";; \
esac; \
done; \
done
diff: best-match.sh
@echo "# Comparing changes in + since $(RNG_max)"
$(call version_diff,${RNG_version_pairs_last})
fulldiff: best-match.sh
@echo "# Comparing all changes across all the subsequent increments"
$(call version_diff,${RNG_version_pairs})
sync:
git rm -f $(wildcard *-next.rng)
make pacemaker-next.rng
CLEANFILES = $(RNG_generated)
diff --git a/xml/alerts-2.5.rng b/xml/alerts-2.5.rng
new file mode 100644
index 0000000000..15d72f27d1
--- /dev/null
+++ b/xml/alerts-2.5.rng
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+ <start>
+ <ref name="element-alerts"/>
+ </start>
+
+ <define name="element-alerts">
+ <optional>
+ <element name="alerts">
+ <zeroOrMore>
+ <element name="alert">
+ <attribute name="id"><data type="ID"/></attribute>
+ <optional>
+ <attribute name="description"><text/></attribute>
+ </optional>
+ <!-- path to the script called for alert -->
+ <attribute name="path"><text/></attribute>
+ <ref name="element-alert-extra"/>
+ <zeroOrMore>
+ <element name="recipient">
+ <attribute name="id"><data type="ID"/></attribute>
+ <optional>
+ <attribute name="description"><text/></attribute>
+ </optional>
+ <attribute name="value"><text/></attribute>
+ <ref name="element-alert-extra"/>
+ </element>
+ </zeroOrMore>
+ </element>
+ </zeroOrMore>
+ </element>
+ </optional>
+ </define>
+
+ <define name="element-alert-extra">
+ <zeroOrMore>
+ <choice>
+ <element name="meta_attributes">
+ <externalRef href="nvset-1.3.rng"/>
+ </element>
+ <element name="instance_attributes">
+ <externalRef href="nvset-1.3.rng"/>
+ </element>
+ </choice>
+ </zeroOrMore>
+ </define>
+
+</grammar>

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jun 25, 6:35 AM (10 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1952460
Default Alt Text
(168 KB)

Event Timeline