Page MenuHomeClusterLabs Projects

No OneTemporary

This document is not UTF8. It was detected as Shift JIS and converted to UTF8 for display.
diff --git a/configure.ac b/configure.ac
index 0e97ac754..b82c21adc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,926 +1,921 @@
dnl
dnl autoconf for Agents
dnl
dnl License: GNU General Public License (GPL)
dnl ===============================================
dnl Bootstrap
dnl ===============================================
AC_PREREQ(2.63)
dnl Suggested structure:
dnl information on the package
dnl checks for programs
dnl checks for libraries
dnl checks for header files
dnl checks for types
dnl checks for structures
dnl checks for compiler characteristics
dnl checks for library functions
dnl checks for system services
AC_INIT([resource-agents],
m4_esyscmd([make/git-version-gen .tarball-version]),
[to_be_defined@foobar.org])
AC_USE_SYSTEM_EXTENSIONS
CRM_DTD_VERSION="1.0"
PKG_FEATURES=""
AC_CONFIG_AUX_DIR(.)
AC_CANONICAL_HOST
dnl Where #defines go (e.g. `AC_CHECK_HEADERS' below)
dnl
dnl Internal header: include/config.h
dnl - Contains ALL defines
dnl - include/config.h.in is generated automatically by autoheader
dnl - NOT to be included in any header files except lha_internal.h
dnl (which is also not to be included in any other header files)
dnl
dnl External header: include/agent_config.h
dnl - Contains a subset of defines checked here
dnl - Manually edit include/agent_config.h.in to have configure include new defines
dnl - Should not include HAVE_* defines
dnl - Safe to include anywhere
AM_CONFIG_HEADER(include/config.h include/agent_config.h)
ALL_LINGUAS="en fr"
AC_ARG_WITH(version,
[ --with-version=version Override package version (if you're a packager needing to pretend) ],
[ PACKAGE_VERSION="$withval" ])
AC_ARG_WITH(pkg-name,
[ --with-pkg-name=name Override package name (if you're a packager needing to pretend) ],
[ PACKAGE_NAME="$withval" ])
AC_PATH_PROGS(PKGCONFIG, pkg-config)
if test x"${PKGCONFIG}" = x""; then
AC_MSG_ERROR(You need pkgconfig installed in order to build ${PACKAGE})
fi
AC_ARG_WITH([systemdsystemunitdir],
[AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],,
[with_systemdsystemunitdir=auto])
AS_IF([test "x$with_systemdsystemunitdir" = "xyes" -o "x$with_systemdsystemunitdir" = "xauto"], [
def_systemdsystemunitdir=$($PKGCONFIG --variable=systemdsystemunitdir systemd)
AS_IF([test "x$def_systemdsystemunitdir" = "x"],
[AS_IF([test "x$with_systemdsystemunitdir" = "xyes"],
[AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])])
with_systemdsystemunitdir=no],
[with_systemdsystemunitdir="$def_systemdsystemunitdir"])])
AS_IF([test "x$with_systemdsystemunitdir" != "xno"],
[AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])])
AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"])
dnl
dnl AM_INIT_AUTOMAKE([1.11.1 foreign dist-bzip2 dist-xz])
dnl
AM_INIT_AUTOMAKE([1.10.1 foreign dist-bzip2])
AC_DEFINE_UNQUOTED(AGENTS_VERSION, "$PACKAGE_VERSION", Current agents version)
CC_IN_CONFIGURE=yes
export CC_IN_CONFIGURE
LDD=ldd
dnl ========================================================================
dnl Compiler characteristics
dnl ========================================================================
# check stolen from gnulib/m4/gnu-make.m4
if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then
AC_MSG_ERROR([you don't seem to have GNU make; it is required])
fi
AC_PROG_CC dnl Can force other with environment variable "CC".
AM_PROG_CC_C_O
AC_PROG_CC_STDC
AC_PROG_AWK
AC_PROG_LN_S
AC_PROG_INSTALL
AC_PROG_MAKE_SET
AC_C_STRINGIZE
AC_C_INLINE
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
AC_TYPE_UID_T
AC_TYPE_UINT16_T
AC_TYPE_UINT8_T
AC_TYPE_UINT32_T
AC_CHECK_SIZEOF(char)
AC_CHECK_SIZEOF(short)
AC_CHECK_SIZEOF(int)
AC_CHECK_SIZEOF(long)
AC_CHECK_SIZEOF(long long)
AC_STRUCT_TIMEZONE
dnl ===============================================
dnl Helpers
dnl ===============================================
cc_supports_flag() {
local CPPFLAGS="$@"
AC_MSG_CHECKING(whether $CC supports "$@")
AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])],
[RC=0; AC_MSG_RESULT([yes])],
[RC=1; AC_MSG_RESULT([no])])
return $RC
}
extract_header_define() {
AC_MSG_CHECKING(for $2 in $1)
Cfile=$srcdir/extract_define.$2.${$}
printf "#include <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 -f ${Cfile}.c ${Cfile}
}
AC_MSG_NOTICE(Sanitizing prefix: ${prefix})
case $prefix in
NONE)
prefix=/usr
dnl Fix default variables - "prefix" variable if not specified
if test "$localstatedir" = "\${prefix}/var"; then
localstatedir="/var"
fi
if test "$sysconfdir" = "\${prefix}/etc"; then
sysconfdir="/etc"
fi
;;
esac
dnl ===============================================
dnl Configure Options
dnl ===============================================
dnl Some systems, like Solaris require a custom package name
AC_ARG_WITH(pkgname,
[ --with-pkgname=name name for pkg (typically for Solaris) ],
[ PKGNAME="$withval" ],
[ PKGNAME="LXHAhb" ],
)
AC_SUBST(PKGNAME)
AC_ARG_ENABLE([ansi],
[ --enable-ansi force GCC to compile to ANSI/ANSI standard for older compilers.
[default=yes]])
AC_ARG_ENABLE([fatal-warnings],
[ --enable-fatal-warnings very pedantic and fatal warnings for gcc
[default=yes]])
INITDIR=""
AC_ARG_WITH(initdir,
[ --with-initdir=DIR directory for init (rc) scripts [${INITDIR}]],
[ INITDIR="$withval" ])
-OCF_EXIT_REASON_COOKIE="ocf-exit-reason:"
-
OCF_ROOT_DIR="/usr/lib/ocf"
AC_ARG_WITH(ocf-root,
[ --with-ocf-root=DIR directory for OCF scripts [${OCF_ROOT_DIR}]],
[ if test x"$withval" = xprefix; then OCF_ROOT_DIR=${prefix}; else
OCF_ROOT_DIR="$withval"; fi ])
HA_RSCTMPDIR=${localstatedir}/run/resource-agents
AC_ARG_WITH(rsctmpdir,
[ --with-rsctmpdir=DIR directory for resource agents state files [${HA_RSCTMPDIR}]],
[ if test x"$withval" = xprefix; then HA_RSCTMPDIR=${prefix}; else
HA_RSCTMPDIR="$withval"; fi ])
AC_ARG_ENABLE([libnet],
[ --enable-libnet Use libnet for ARP based funcationality, [default=try]],
[enable_libnet="$enableval"], [enable_libnet=try])
BUILD_RGMANAGER=0
BUILD_LINUX_HA=0
RASSET=all
AC_ARG_WITH(ras-set,
[ --with-ras-set=SET build/install only linux-ha or rgmanager resource-agents [default: all]],
[ RASSET="$withval" ])
if test x$RASSET = xyes || test x$RASSET = xall ; then
BUILD_RGMANAGER=1
BUILD_LINUX_HA=1
fi
if test x$RASSET = xlinux-ha; then
BUILD_LINUX_HA=1
fi
if test x$RASSET = xrgmanager; then
BUILD_RGMANAGER=1
fi
if test $BUILD_LINUX_HA -eq 0 && test $BUILD_RGMANAGER -eq 0; then
AC_MSG_ERROR([Are you really sure you want this package?])
exit 1
fi
AM_CONDITIONAL(BUILD_LINUX_HA, test $BUILD_LINUX_HA -eq 1)
AM_CONDITIONAL(BUILD_RGMANAGER, test $BUILD_RGMANAGER -eq 1)
dnl ===============================================
dnl General Processing
dnl ===============================================
echo Our Host OS: $host_os/$host
AC_MSG_NOTICE(Sanitizing exec_prefix: ${exec_prefix})
case $exec_prefix in
dnl For consistency with Heartbeat, map NONE->$prefix
NONE) exec_prefix=$prefix;;
prefix) exec_prefix=$prefix;;
esac
AC_MSG_NOTICE(Sanitizing INITDIR: ${INITDIR})
case $INITDIR in
prefix) INITDIR=$prefix;;
"")
AC_MSG_CHECKING(which init (rc) directory to use)
for initdir in /etc/init.d /etc/rc.d/init.d /sbin/init.d \
/usr/local/etc/rc.d /etc/rc.d
do
if
test -d $initdir
then
INITDIR=$initdir
break
fi
done
if
test -z $INITDIR
then
INITDIR=${sysconfdir}/init.d
fi
AC_MSG_RESULT($INITDIR);;
esac
AC_SUBST(INITDIR)
if test "${prefix}" = "/usr"; then
INITDIRPREFIX="$INITDIR"
else
INITDIRPREFIX="${prefix}/$INITDIR"
fi
AC_SUBST(INITDIRPREFIX)
AC_MSG_NOTICE(Sanitizing libdir: ${libdir})
case $libdir in
dnl For consistency with Heartbeat, map NONE->$prefix
*prefix*|NONE)
AC_MSG_CHECKING(which lib directory to use)
for aDir in lib64 lib
do
trydir="${exec_prefix}/${aDir}"
if
test -d ${trydir}
then
libdir=${trydir}
break
fi
done
AC_MSG_RESULT($libdir);
;;
esac
dnl Expand autoconf variables so that we dont end up with '${prefix}'
dnl in #defines and python scripts
dnl NOTE: Autoconf deliberately leaves them unexpanded to allow
dnl make exec_prefix=/foo install
dnl No longer being able to do this seems like no great loss to me...
eval prefix="`eval echo ${prefix}`"
eval exec_prefix="`eval echo ${exec_prefix}`"
eval bindir="`eval echo ${bindir}`"
eval sbindir="`eval echo ${sbindir}`"
eval libexecdir="`eval echo ${libexecdir}`"
eval datadir="`eval echo ${datadir}`"
eval sysconfdir="`eval echo ${sysconfdir}`"
eval sharedstatedir="`eval echo ${sharedstatedir}`"
eval localstatedir="`eval echo ${localstatedir}`"
eval libdir="`eval echo ${libdir}`"
eval includedir="`eval echo ${includedir}`"
eval oldincludedir="`eval echo ${oldincludedir}`"
eval infodir="`eval echo ${infodir}`"
eval mandir="`eval echo ${mandir}`"
dnl docdir is a recent addition to autotools
eval docdir="`eval echo ${docdir}`"
if test "x$docdir" = "x"; then
docdir="`eval echo ${datadir}/doc`"
fi
AC_SUBST(docdir)
dnl Home-grown variables
eval INITDIR="${INITDIR}"
for j in prefix exec_prefix bindir sbindir libexecdir datadir sysconfdir \
sharedstatedir localstatedir libdir includedir oldincludedir infodir \
mandir INITDIR docdir
do
dirname=`eval echo '${'${j}'}'`
if
test ! -d "$dirname"
then
AC_MSG_WARN([$j directory ($dirname) does not exist!])
fi
done
dnl This OS-based decision-making is poor autotools practice;
dnl feature-based mechanisms are strongly preferred.
dnl
dnl So keep this section to a bare minimum; regard as a "necessary evil".
REBOOT_OPTIONS="-f"
POWEROFF_OPTIONS="-f"
case "$host_os" in
*bsd*) LIBS="-L/usr/local/lib"
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
;;
*solaris*)
REBOOT_OPTIONS="-n"
POWEROFF_OPTIONS="-n"
;;
*linux*)
AC_DEFINE_UNQUOTED(ON_LINUX, 1, Compiling for Linux platform)
POWEROFF_OPTIONS="-nf"
REBOOT_OPTIONS="-nf"
;;
darwin*)
AC_DEFINE_UNQUOTED(ON_DARWIN, 1, Compiling for Darwin platform)
LIBS="$LIBS -L${prefix}/lib"
CFLAGS="$CFLAGS -I${prefix}/include"
;;
esac
AC_DEFINE_UNQUOTED(HA_LOG_FACILITY, LOG_DAEMON, Default logging facility)
AC_MSG_NOTICE(Host CPU: $host_cpu)
case "$host_cpu" in
ppc64|powerpc64)
case $CFLAGS in
*powerpc64*) ;;
*) if test "$GCC" = yes; then
CFLAGS="$CFLAGS -m64"
fi ;;
esac
esac
AC_MSG_CHECKING(which format is needed to print uint64_t)
case "$host_cpu" in
s390x)U64T="%lu";;
*64*) U64T="%lu";;
*) U64T="%llu";;
esac
AC_MSG_RESULT($U64T)
AC_DEFINE_UNQUOTED(U64T, "$U64T", Correct printf format for logging uint64_t)
dnl Variables needed for substitution
AC_CHECK_HEADERS(heartbeat/glue_config.h)
if test "$ac_cv_header_heartbeat_glue_config_h" = "yes"; then
OCF_ROOT_DIR=`extract_header_define heartbeat/glue_config.h OCF_ROOT_DIR`
else
enable_libnet=no
fi
-AC_DEFINE_UNQUOTED(OCF_EXIT_REASON_COOKIE,"$OCF_EXIT_REASON_COOKIE", OCF exit message delimiter - specifies the start of the exit reason string)
-AC_SUBST(OCF_EXIT_REASON_COOKIE)
-
AC_DEFINE_UNQUOTED(OCF_ROOT_DIR,"$OCF_ROOT_DIR", OCF root directory - specified by the OCF standard)
AC_SUBST(OCF_ROOT_DIR)
GLUE_STATE_DIR=${localstatedir}/run
AC_DEFINE_UNQUOTED(GLUE_STATE_DIR,"$GLUE_STATE_DIR", Where to keep state files and sockets)
AC_SUBST(GLUE_STATE_DIR)
AC_DEFINE_UNQUOTED(HA_VARRUNDIR,"$GLUE_STATE_DIR", Where Heartbeat keeps state files and sockets - old name)
HA_VARRUNDIR="$GLUE_STATE_DIR"
AC_SUBST(HA_VARRUNDIR)
# Expand $prefix
eval HA_RSCTMPDIR="`eval echo ${HA_RSCTMPDIR}`"
AC_DEFINE_UNQUOTED(HA_RSCTMPDIR,"$HA_RSCTMPDIR", Where Resouce agents keep state files)
AC_SUBST(HA_RSCTMPDIR)
dnl Eventually move out of the heartbeat dir tree and create symlinks when needed
HA_VARLIBHBDIR=${localstatedir}/lib/heartbeat
AC_DEFINE_UNQUOTED(HA_VARLIBHBDIR,"$HA_VARLIBHBDIR", Whatever this used to mean)
AC_SUBST(HA_VARLIBHBDIR)
OCF_RA_DIR="${OCF_ROOT_DIR}/resource.d/"
AC_DEFINE_UNQUOTED(OCF_RA_DIR,"$OCF_RA_DIR", Location for OCF RAs)
AC_SUBST(OCF_RA_DIR)
if test "${prefix}" = "/usr"; then
OCF_RA_DIR_PREFIX="$OCF_RA_DIR"
else
OCF_RA_DIR_PREFIX="${prefix}/$OCF_RA_DIR"
fi
AC_SUBST(OCF_RA_DIR_PREFIX)
OCF_LIB_DIR="${OCF_ROOT_DIR}/lib/"
AC_DEFINE_UNQUOTED(OCF_LIB_DIR,"$OCF_LIB_DIR", Location for shared code for OCF RAs)
AC_SUBST(OCF_LIB_DIR)
if test "${prefix}" = "/usr"; then
OCF_LIB_DIR_PREFIX="$OCF_LIB_DIR"
else
OCF_LIB_DIR_PREFIX="${prefix}/$OCF_LIB_DIR"
fi
AC_SUBST(OCF_LIB_DIR_PREFIX)
dnl ===============================================
dnl rgmanager ras bits
dnl ===============================================
LOGDIR=${localstatedir}/log/cluster
CLUSTERDATA=${datadir}/cluster
AC_SUBST([LOGDIR])
AC_SUBST([CLUSTERDATA])
dnl ===============================================
dnl Program Paths
dnl ===============================================
PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin"
export PATH
AM_PATH_PYTHON
AC_CHECK_PROGS(MAKE, gmake make)
AC_PATH_PROGS(SSH, ssh, /usr/bin/ssh)
AC_PATH_PROGS(SCP, scp, /usr/bin/scp)
AC_PATH_PROGS(TAR, tar)
AC_PATH_PROGS(MD5, md5)
AC_PATH_PROGS(TEST, test)
AC_PATH_PROGS(PING, ping, /bin/ping)
AC_PATH_PROGS(IFCONFIG, ifconfig, /sbin/ifconfig)
AC_PATH_PROGS(MAILCMD, mailx mail, mail)
AC_PATH_PROGS(EGREP, egrep)
AC_SUBST(MAILCMD)
AC_SUBST(EGREP)
AC_SUBST(SHELL)
AC_SUBST(PING)
AC_SUBST(TEST)
AC_PATH_PROGS(ROUTE, route)
AC_DEFINE_UNQUOTED(ROUTE, "$ROUTE", path to route command)
AC_MSG_CHECKING(ifconfig option to list interfaces)
for IFCONFIG_A_OPT in "-A" "-a" ""
do
$IFCONFIG $IFCONFIG_A_OPT > /dev/null 2>&1
if
test "$?" = 0
then
AC_DEFINE_UNQUOTED(IFCONFIG_A_OPT, "$IFCONFIG_A_OPT", option for ifconfig command)
AC_MSG_RESULT($IFCONFIG_A_OPT)
break
fi
done
AC_SUBST(IFCONFIG_A_OPT)
if test x"${MAKE}" = x""; then
AC_MSG_ERROR(You need (g)make installed in order to build ${PACKAGE})
fi
dnl ===============================================
dnl Libraries
dnl ===============================================
AC_CHECK_LIB(socket, socket)
AC_CHECK_LIB(gnugetopt, getopt_long) dnl if available
if test "x${enable_thread_safe}" = "xyes"; then
GPKGNAME="gthread-2.0"
else
GPKGNAME="glib-2.0"
fi
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)
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 ========================================================================
dnl Headers
dnl ========================================================================
AC_HEADER_STDC
AC_CHECK_HEADERS(sys/socket.h)
AC_CHECK_HEADERS(sys/sockio.h)
AC_CHECK_HEADERS([arpa/inet.h])
AC_CHECK_HEADERS([fcntl.h])
AC_CHECK_HEADERS([limits.h])
AC_CHECK_HEADERS([malloc.h])
AC_CHECK_HEADERS([netdb.h])
AC_CHECK_HEADERS([netinet/in.h])
AC_CHECK_HEADERS([sys/file.h])
AC_CHECK_HEADERS([sys/ioctl.h])
AC_CHECK_HEADERS([sys/param.h])
AC_CHECK_HEADERS([sys/time.h])
AC_CHECK_HEADERS([syslog.h])
dnl ========================================================================
dnl Functions
dnl ========================================================================
AC_FUNC_FORK
AC_FUNC_STRNLEN
AC_CHECK_FUNCS([alarm gettimeofday inet_ntoa memset mkdir socket uname])
AC_CHECK_FUNCS([strcasecmp strchr strdup strerror strrchr strspn strstr strtol strtoul])
AC_PATH_PROGS(REBOOT, reboot, /sbin/reboot)
AC_SUBST(REBOOT)
AC_SUBST(REBOOT_OPTIONS)
AC_DEFINE_UNQUOTED(REBOOT, "$REBOOT", path to the reboot command)
AC_DEFINE_UNQUOTED(REBOOT_OPTIONS, "$REBOOT_OPTIONS", reboot options)
AC_PATH_PROGS(POWEROFF_CMD, poweroff, /sbin/poweroff)
AC_SUBST(POWEROFF_CMD)
AC_SUBST(POWEROFF_OPTIONS)
AC_DEFINE_UNQUOTED(POWEROFF_CMD, "$POWEROFF_CMD", path to the poweroff command)
AC_DEFINE_UNQUOTED(POWEROFF_OPTIONS, "$POWEROFF_OPTIONS", poweroff options)
AC_PATH_PROGS(XSLTPROC, xsltproc)
AM_CONDITIONAL(BUILD_DOC, test "x$XSLTPROC" != "x" )
if test "x$XSLTPROC" = "x"; then
AC_MSG_WARN([xsltproc not installed, unable to (re-)build manual pages])
fi
AC_SUBST(XSLTPROC)
AC_PATH_PROGS(POD2MAN, pod2man)
AM_CONDITIONAL(BUILD_POD_DOC, test "x$POD2MAN" != "x" )
if test "x$POD2MAN" = "x"; then
AC_MSG_WARN([pod2man not installed, unable to (re-)build ldirector manual page])
fi
AC_SUBST(POD2MAN)
dnl ========================================================================
dnl Functions
dnl ========================================================================
AC_CHECK_FUNCS(getopt, AC_DEFINE(HAVE_DECL_GETOPT, 1, [Have getopt function]))
dnl ========================================================================
dnl sfex
dnl ========================================================================
build_sfex=no
case $host_os in
*Linux*|*linux*)
if test "$ac_cv_header_heartbeat_glue_config_h" = "yes"; then
build_sfex=yes
fi
;;
esac
AM_CONDITIONAL(BUILD_SFEX, test "$build_sfex" = "yes" )
dnl ========================================================================
dnl tickle (needs port to BSD platforms)
dnl ========================================================================
AC_CHECK_MEMBERS([struct iphdr.saddr],,,[[#include <netinet/ip.h>]])
AM_CONDITIONAL(BUILD_TICKLE, test "$ac_cv_member_struct_iphdr_saddr" = "yes" )
dnl ========================================================================
dnl libnet
dnl ========================================================================
libnet=""
libnet_version="none"
LIBNETLIBS=""
LIBNETDEFINES=""
AC_MSG_CHECKING(if libnet is required)
libnet_fatal=$enable_libnet
case $enable_libnet in
no) ;;
yes|libnet10|libnet11|10|11) libnet_fatal=yes;;
try)
case $host_os in
*Linux*|*linux*) libnet_fatal=no;;
*) libnet_fatal=yes;; dnl legacy behavior
esac
;;
*) libnet_fatal=yes; enable_libnet=try;;
esac
AC_MSG_RESULT($libnet_fatal)
if test "x$enable_libnet" != "xno"; then
AC_PATH_PROGS(LIBNETCONFIG, libnet-config)
AC_CHECK_LIB(nsl, t_open) dnl -lnsl
AC_CHECK_LIB(socket, socket) dnl -lsocket
AC_CHECK_LIB(net, libnet_get_hwaddr, LIBNETLIBS=" -lnet", [])
fi
AC_MSG_CHECKING(for libnet)
if test "x$LIBNETLIBS" != "x" -o "x$enable_libnet" = "xlibnet11"; then
LIBNETDEFINES=""
if test "$ac_cv_lib_nsl_t_open" = yes; then
LIBNETLIBS="-lnsl $LIBNETLIBS"
fi
if test "$ac_cv_lib_socket_socket" = yes; then
LIBNETLIBS="-lsocket $LIBNETLIBS"
fi
libnet=net
libnet_version="libnet1.1"
fi
if test "x$enable_libnet" = "xtry" -o "x$enable_libnet" = "xlibnet10"; then
if test "x$LIBNETLIBS" = x -a "x${LIBNETCONFIG}" != "x" ; then
LIBNETDEFINES="`$LIBNETCONFIG --defines` `$LIBNETCONFIG --cflags`";
LIBNETLIBS="`$LIBNETCONFIG --libs`";
libnet_version="libnet1.0 (old)"
case $LIBNETLIBS in
*-l*) libnet=`echo $LIBNETLIBS | sed 's%.*-l%%'`;;
*) libnet_version=none;;
esac
CPPFLAGS="$CPPFLAGS $LIBNETDEFINES"
AC_CHECK_HEADERS(libnet.h)
if test "$ac_cv_header_libnet_h" = no; then
libnet_version=none
fi
fi
fi
AC_MSG_RESULT(found $libnet_version)
if test "$libnet_version" = none; then
LIBNETLIBS=""
LIBNETDEFINES=""
if test $libnet_fatal = yes; then
AC_MSG_ERROR(libnet not found)
fi
else
AC_CHECK_LIB($libnet,libnet_init,
[new_libnet=yes; AC_DEFINE(HAVE_LIBNET_1_1_API, 1, Libnet 1.1 API)],
[new_libnet=no; AC_DEFINE(HAVE_LIBNET_1_0_API, 1, Libnet 1.0 API)],$LIBNETLIBS)
AC_SUBST(LIBNETLIBS)
fi
if test "$new_libnet" = yes; then
AC_MSG_CHECKING(for libnet API 1.1.4: )
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -fgnu89-inline -Wall -Werror"
AC_COMPILE_IFELSE([
AC_LANG_SOURCE(#include <libnet.h>
int main(){libnet_t *l=NULL; libnet_pblock_record_ip_offset(l, l->total_size); return(0); })],
[AC_MSG_RESULT(no)],
[AC_DEFINE(HAVE_LIBNET_1_1_4_API, 1, Libnet 1.1.4 API) AC_MSG_RESULT(yes)])
CFLAGS="$save_CFLAGS"
fi
sendarp_linux=0
case $host_os in
*Linux*|*linux*) sendarp_linux=1;;
esac
AC_SUBST(LIBNETLIBS)
AC_SUBST(LIBNETDEFINES)
AM_CONDITIONAL(SENDARP_LINUX, test $sendarp_linux = 1 )
AM_CONDITIONAL(USE_LIBNET, test "x$libnet_version" != "xnone" )
dnl ************************************************************************
dnl * Check for netinet/icmp6.h to enable the IPv6addr resource agent
AC_CHECK_HEADERS(netinet/icmp6.h,[],[],[#include <sys/types.h>])
AM_CONDITIONAL(USE_IPV6ADDR_AGENT, test "$ac_cv_header_netinet_icmp6_h" = yes && test "$ac_cv_header_heartbeat_glue_config_h" = yes)
AM_CONDITIONAL(IPV6ADDR_COMPATIBLE, test "$ac_cv_header_netinet_icmp6_h" = yes)
dnl ========================================================================
dnl Compiler flags
dnl ========================================================================
dnl Make sure that CFLAGS is not exported. If the user did
dnl not have CFLAGS in their environment then this should have
dnl no effect. However if CFLAGS was exported from the user's
dnl environment, then the new CFLAGS will also be exported
dnl to sub processes.
CC_ERRORS=""
CC_EXTRAS=""
if export | fgrep " CFLAGS=" > /dev/null; then
export -n CFLAGS || true # We don't want to bomb out if this fails
SAVED_CFLAGS="$CFLAGS"
unset CFLAGS
CFLAGS="$SAVED_CFLAGS"
unset SAVED_CFLAGS
fi
if test "$GCC" != yes; then
CFLAGS="$CFLAGS -g"
enable_fatal_warnings=no
else
CFLAGS="$CFLAGS -ggdb3"
# We had to eliminate -Wnested-externs because of libtool changes
# Also remove -Waggregate-return because we use one libnet
# call which returns a struct
EXTRA_FLAGS="-fgnu89-inline
-fstack-protector-all
-Wall
-Wbad-function-cast
-Wcast-qual
-Wcast-align
-Wdeclaration-after-statement
-Wendif-labels
-Wfloat-equal
-Wformat=2
-Wformat-security
-Wformat-nonliteral
-Winline
-Wmissing-prototypes
-Wmissing-declarations
-Wmissing-format-attribute
-Wnested-externs
-Wno-long-long
-Wno-strict-aliasing
-Wpointer-arith
-Wstrict-prototypes
-Wunsigned-char
-Wwrite-strings"
# Additional warnings it might be nice to enable one day
# -Wshadow
# -Wunreachable-code
for j in $EXTRA_FLAGS
do
if
cc_supports_flag $j
then
CC_EXTRAS="$CC_EXTRAS $j"
fi
done
dnl In lib/ais/Makefile.am there's a gcc option available as of v4.x
GCC_MAJOR=`gcc -v 2>&1 | awk 'END{print $3}' | sed 's/[.].*//'`
AM_CONDITIONAL(GCC_4, test "${GCC_MAJOR}" = 4)
dnl System specific options
case "$host_os" in
*linux*|*bsd*)
if test "${enable_fatal_warnings}" = "unknown"; then
enable_fatal_warnings=yes
fi
;;
esac
if test "x${enable_fatal_warnings}" != xno && cc_supports_flag -Werror ; then
enable_fatal_warnings=yes
else
enable_fatal_warnings=no
fi
if test "x${enable_ansi}" != xno && cc_supports_flag -std=iso9899:199409 ; then
AC_MSG_NOTICE(Enabling ANSI Compatibility)
CC_EXTRAS="$CC_EXTRAS -ansi -D_GNU_SOURCE -DANSI_ONLY"
fi
AC_MSG_NOTICE(Activated additional gcc flags: ${CC_EXTRAS})
fi
CFLAGS="$CFLAGS $CC_EXTRAS"
NON_FATAL_CFLAGS="$CFLAGS"
AC_SUBST(NON_FATAL_CFLAGS)
dnl
dnl We reset CFLAGS to include our warnings *after* all function
dnl checking goes on, so that our warning flags don't keep the
dnl AC_*FUNCS() calls above from working. In particular, -Werror will
dnl *always* cause us troubles if we set it before here.
dnl
dnl
if test "x${enable_fatal_warnings}" = xyes ; then
AC_MSG_NOTICE(Enabling Fatal Warnings)
CFLAGS="$CFLAGS -Werror"
fi
AC_SUBST(CFLAGS)
dnl This is useful for use in Makefiles that need to remove one specific flag
CFLAGS_COPY="$CFLAGS"
AC_SUBST(CFLAGS_COPY)
AC_SUBST(LOCALE)
AC_SUBST(CC)
AC_SUBST(MAKE)
dnl The Makefiles and shell scripts we output
AC_CONFIG_FILES(Makefile \
include/Makefile \
heartbeat/Makefile \
heartbeat/ocf-binaries \
heartbeat/ocf-directories \
heartbeat/ocf-shellfuncs \
heartbeat/shellfuncs \
tools/Makefile \
tools/ocf-tester \
tools/ocft/Makefile \
tools/ocft/ocft \
tools/ocft/caselib \
tools/ocft/README \
tools/ocft/README.zh_CN \
ldirectord/Makefile \
ldirectord/ldirectord \
ldirectord/init.d/Makefile \
ldirectord/init.d/ldirectord \
ldirectord/init.d/ldirectord.debian \
ldirectord/init.d/ldirectord.debian.default \
ldirectord/systemd/Makefile \
ldirectord/systemd/ldirectord.service \
ldirectord/logrotate.d/Makefile \
ldirectord/OCF/Makefile \
ldirectord/OCF/ldirectord \
doc/Makefile \
doc/man/Makefile \
rgmanager/Makefile \
rgmanager/src/Makefile \
rgmanager/src/resources/Makefile \
rgmanager/src/resources/utils/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}])
AC_MSG_RESULT([ Build Version = $Format:%H$])
AC_MSG_RESULT([ Features =${PKG_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([ Documentation = ${docdir}])
AC_MSG_RESULT([ State information = ${localstatedir}])
AC_MSG_RESULT([ System configuration = ${sysconfdir}])
AC_MSG_RESULT([ RA state files = ${HA_RSCTMPDIR}])
AC_MSG_RESULT([ AIS Plugins = ${LCRSODIR}])
AC_MSG_RESULT([])
AC_MSG_RESULT([ CFLAGS = ${CFLAGS}])
AC_MSG_RESULT([ Libraries = ${LIBS}])
AC_MSG_RESULT([ Stack Libraries = ${CLUSTERLIBS}])
diff --git a/heartbeat/Dummy b/heartbeat/Dummy
index c8c22e561..a0929fac0 100755
--- a/heartbeat/Dummy
+++ b/heartbeat/Dummy
@@ -1,180 +1,180 @@
#!/bin/sh
#
#
# Dummy OCF RA. Does nothing but wait a few seconds, can be
# configured to fail occassionally.
#
# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Br馥
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Further, this software is distributed without any warranty that it is
# free of the rightful claim of any third person regarding infringement
# or the like. Any license provided herein, whether implied or
# otherwise, applies only to this software file. Patent licenses, if
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
#######################################################################
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="Dummy" version="0.9">
<version>1.0</version>
<longdesc lang="en">
This is a Dummy Resource Agent. It does absolutely nothing except
keep track of whether its running or not.
Its purpose in life is for testing and to serve as a template for RA writers.
NB: Please pay attention to the timeouts specified in the actions
section below. They should be meaningful for the kind of resource
the agent manages. They should be the minimum advised timeouts,
but they shouldn't/cannot cover _all_ possible resource
instances. So, try to be neither overly generous nor too stingy,
but moderate. The minimum timeouts should never be below 10 seconds.
</longdesc>
<shortdesc lang="en">Example stateless resource agent</shortdesc>
<parameters>
<parameter name="state" unique="1">
<longdesc lang="en">
Location to store the resource state in.
</longdesc>
<shortdesc lang="en">State file</shortdesc>
<content type="string" default="${HA_RSCTMP}/Dummy-${OCF_RESOURCE_INSTANCE}.state" />
</parameter>
<parameter name="fake" unique="0">
<longdesc lang="en">
Fake attribute that can be changed to cause a reload
</longdesc>
<shortdesc lang="en">Fake attribute that can be changed to cause a reload</shortdesc>
<content type="string" default="dummy" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="20" />
<action name="stop" timeout="20" />
<action name="monitor" timeout="20" interval="10" depth="0" />
<action name="reload" timeout="20" />
<action name="migrate_to" timeout="20" />
<action name="migrate_from" timeout="20" />
<action name="meta-data" timeout="5" />
<action name="validate-all" timeout="20" />
</actions>
</resource-agent>
END
}
#######################################################################
dummy_usage() {
cat <<END
usage: $0 {start|stop|monitor|migrate_to|migrate_from|validate-all|meta-data}
Expects to have a fully populated OCF RA-compliant environment set.
END
}
dummy_start() {
dummy_monitor
if [ $? = $OCF_SUCCESS ]; then
return $OCF_SUCCESS
fi
touch ${OCF_RESKEY_state}
}
dummy_stop() {
dummy_monitor
if [ $? = $OCF_SUCCESS ]; then
rm ${OCF_RESKEY_state}
fi
return $OCF_SUCCESS
}
dummy_monitor() {
# Monitor _MUST!_ differentiate correctly between running
# (SUCCESS), failed (ERROR) or _cleanly_ stopped (NOT RUNNING).
# That is THREE states, not just yes/no.
if [ -f ${OCF_RESKEY_state} ]; then
return $OCF_SUCCESS
fi
if false ; then
return $OCF_ERR_GENERIC
fi
- if ! ocf_is_probe; then
+ if ! ocf_is_probe && [ "$__OCF_ACTION" = "monitor" ]; then
# set exit string only when NOT_RUNNING occurs during an actual monitor operation.
- ocf_exit_reason "No process state file found" "monitor"
+ ocf_exit_reason "No process state file found"
fi
return $OCF_NOT_RUNNING
}
dummy_validate() {
# Is the state directory writable?
state_dir=`dirname "$OCF_RESKEY_state"`
touch "$state_dir/$$"
if [ $? != 0 ]; then
ocf_exit_reason "State file \"$OCF_RESKEY_state\" is not writable"
return $OCF_ERR_ARGS
fi
rm "$state_dir/$$"
return $OCF_SUCCESS
}
: ${OCF_RESKEY_state=${HA_RSCTMP}/Dummy-${OCF_RESOURCE_INSTANCE}.state}
: ${OCF_RESKEY_fake="dummy"}
case $__OCF_ACTION in
meta-data) meta_data
exit $OCF_SUCCESS
;;
start) dummy_start;;
stop) dummy_stop;;
monitor) dummy_monitor;;
migrate_to) ocf_log info "Migrating ${OCF_RESOURCE_INSTANCE} to ${OCF_RESKEY_CRM_meta_migrate_target}."
dummy_stop
;;
migrate_from) ocf_log info "Migrating ${OCF_RESOURCE_INSTANCE} from ${OCF_RESKEY_CRM_meta_migrate_source}."
dummy_start
;;
reload) ocf_log info "Reloading ${OCF_RESOURCE_INSTANCE} ..."
;;
validate-all) dummy_validate;;
usage|help) dummy_usage
exit $OCF_SUCCESS
;;
*) dummy_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
rc=$?
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
exit $rc
diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2
index f62d71adc..a58068388 100755
--- a/heartbeat/IPaddr2
+++ b/heartbeat/IPaddr2
@@ -1,1075 +1,1077 @@
#!/bin/sh
#
# $Id: IPaddr2.in,v 1.24 2006/08/09 13:01:54 lars Exp $
#
# OCF Resource Agent compliant IPaddr2 script.
#
# Based on work by Tuomo Soini, ported to the OCF RA API by Lars
# Marowsky-Brテゥe. Implements Cluster Alias IP functionality too.
#
# Cluster Alias IP cleanup, fixes and testing by Michael Schwartzkopff
#
#
# Copyright (c) 2003 Tuomo Soini
# Copyright (c) 2004-2006 SUSE LINUX AG, Lars Marowsky-Brテゥe
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Further, this software is distributed without any warranty that it is
# free of the rightful claim of any third person regarding infringement
# or the like. Any license provided herein, whether implied or
# otherwise, applies only to this software file. Patent licenses, if
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#
#
# TODO:
# - There ought to be an ocf_run_cmd function which does all logging,
# timeout handling etc for us
# - Make this the standard IP address agent on Linux; the other
# platforms simply should ignore the additional parameters OR can use
# the legacy heartbeat resource script...
# - Check LVS <-> clusterip incompatibilities.
#
# OCF parameters are as below
# OCF_RESKEY_ip
# OCF_RESKEY_broadcast
# OCF_RESKEY_nic
# OCF_RESKEY_cidr_netmask
# OCF_RESKEY_iflabel
# OCF_RESKEY_mac
# OCF_RESKEY_clusterip_hash
# OCF_RESKEY_arp_interval
# OCF_RESKEY_arp_count
# OCF_RESKEY_arp_bg
# OCF_RESKEY_arp_mac
#
# OCF_RESKEY_CRM_meta_clone
# OCF_RESKEY_CRM_meta_clone_max
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
. ${OCF_FUNCTIONS_DIR}/findif.sh
# Defaults
OCF_RESKEY_lvs_support_default=false
OCF_RESKEY_lvs_ipv6_addrlabel_default=false
OCF_RESKEY_lvs_ipv6_addrlabel_value_default=99
OCF_RESKEY_clusterip_hash_default="sourceip-sourceport"
OCF_RESKEY_unique_clone_address_default=false
OCF_RESKEY_arp_interval_default=200
OCF_RESKEY_arp_count_default=5
OCF_RESKEY_arp_bg_default=true
OCF_RESKEY_arp_mac_default="ffffffffffff"
: ${OCF_RESKEY_lvs_support=${OCF_RESKEY_lvs_support_default}}
: ${OCF_RESKEY_lvs_ipv6_addrlabel=${OCF_RESKEY_lvs_ipv6_addrlabel_default}}
: ${OCF_RESKEY_lvs_ipv6_addrlabel_value=${OCF_RESKEY_lvs_ipv6_addrlabel_value_default}}
: ${OCF_RESKEY_clusterip_hash=${OCF_RESKEY_clusterip_hash_default}}
: ${OCF_RESKEY_unique_clone_address=${OCF_RESKEY_unique_clone_address_default}}
: ${OCF_RESKEY_arp_interval=${OCF_RESKEY_arp_interval_default}}
: ${OCF_RESKEY_arp_count=${OCF_RESKEY_arp_count_default}}
: ${OCF_RESKEY_arp_bg=${OCF_RESKEY_arp_bg_default}}
: ${OCF_RESKEY_arp_mac=${OCF_RESKEY_arp_mac_default}}
#######################################################################
SENDARP=$HA_BIN/send_arp
SENDUA=$HA_BIN/send_ua
FINDIF=findif
VLDIR=$HA_RSCTMP
SENDARPPIDDIR=$HA_RSCTMP
CIP_lockfile=$HA_RSCTMP/IPaddr2-CIP-${OCF_RESKEY_ip}
#######################################################################
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="IPaddr2">
<version>1.0</version>
<longdesc lang="en">
This Linux-specific resource manages IP alias IP addresses.
It can add an IP alias, or remove one.
In addition, it can implement Cluster Alias IP functionality
if invoked as a clone resource.
If used as a clone, you should explicitly set clone-node-max &gt;= 2,
and/or clone-max &lt; number of nodes. In case of node failure,
clone instances need to be re-allocated on surviving nodes.
This would not be possible if there is already an instance on those nodes,
and clone-node-max=1 (which is the default).
</longdesc>
<shortdesc lang="en">Manages virtual IPv4 and IPv6 addresses (Linux specific version)</shortdesc>
<parameters>
<parameter name="ip" unique="1" required="1">
<longdesc lang="en">
The IPv4 (dotted quad notation) or IPv6 address (colon hexadecimal notation)
example IPv4 "192.168.1.1".
example IPv6 "2001:db8:DC28:0:0:FC57:D4C8:1FFF".
</longdesc>
<shortdesc lang="en">IPv4 or IPv6 address</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="nic" unique="0">
<longdesc lang="en">
The base network interface on which the IP address will be brought
online.
If left empty, the script will try and determine this from the
routing table.
Do NOT specify an alias interface in the form eth0:1 or anything here;
rather, specify the base interface only.
If you want a label, see the iflabel parameter.
Prerequisite:
There must be at least one static IP address, which is not managed by
the cluster, assigned to the network interface.
If you can not assign any static IP address on the interface,
modify this kernel parameter:
sysctl -w net.ipv4.conf.all.promote_secondaries=1 # (or per device)
</longdesc>
<shortdesc lang="en">Network interface</shortdesc>
<content type="string"/>
</parameter>
<parameter name="cidr_netmask">
<longdesc lang="en">
The netmask for the interface in CIDR format
(e.g., 24 and not 255.255.255.0)
If unspecified, the script will also try to determine this from the
routing table.
</longdesc>
<shortdesc lang="en">CIDR netmask</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="broadcast">
<longdesc lang="en">
Broadcast address associated with the IP. If left empty, the script will
determine this from the netmask.
</longdesc>
<shortdesc lang="en">Broadcast address</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="iflabel">
<longdesc lang="en">
You can specify an additional label for your IP address here.
This label is appended to your interface name.
The kernel allows alphanumeric labels up to a maximum length of 15
characters including the interface name and colon (e.g. eth0:foobar1234)
A label can be specified in nic parameter but it is deprecated.
If a label is specified in nic name, this parameter has no effect.
</longdesc>
<shortdesc lang="en">Interface label</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="lvs_support">
<longdesc lang="en">
Enable support for LVS Direct Routing configurations. In case a IP
address is stopped, only move it to the loopback device to allow the
local node to continue to service requests, but no longer advertise it
on the network.
Notes for IPv6:
It is not necessary to enable this option on IPv6.
Instead, enable 'lvs_ipv6_addrlabel' option for LVS-DR usage on IPv6.
</longdesc>
<shortdesc lang="en">Enable support for LVS DR</shortdesc>
<content type="boolean" default="${OCF_RESKEY_lvs_support_default}"/>
</parameter>
<parameter name="lvs_ipv6_addrlabel">
<longdesc lang="en">
Enable adding IPv6 address label so IPv6 traffic originating from
the address's interface does not use this address as the source.
This is necessary for LVS-DR health checks to realservers to work. Without it,
the most recently added IPv6 address (probably the address added by IPaddr2)
will be used as the source address for IPv6 traffic from that interface and
since that address exists on loopback on the realservers, the realserver
response to pings/connections will never leave its loopback.
See RFC3484 for the detail of the source address selection.
See also 'lvs_ipv6_addrlabel_value' parameter.
</longdesc>
<shortdesc lang="en">Enable adding IPv6 address label.</shortdesc>
<content type="boolean" default="${OCF_RESKEY_lvs_ipv6_addrlabel_default}"/>
</parameter>
<parameter name="lvs_ipv6_addrlabel_value">
<longdesc lang="en">
Specify IPv6 address label value used when 'lvs_ipv6_addrlabel' is enabled.
The value should be an unused label in the policy table
which is shown by 'ip addrlabel list' command.
You would rarely need to change this parameter.
</longdesc>
<shortdesc lang="en">IPv6 address label value.</shortdesc>
<content type="integer" default="${OCF_RESKEY_lvs_ipv6_addrlabel_value_default}"/>
</parameter>
<parameter name="mac">
<longdesc lang="en">
Set the interface MAC address explicitly. Currently only used in case of
the Cluster IP Alias. Leave empty to chose automatically.
</longdesc>
<shortdesc lang="en">Cluster IP MAC address</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="clusterip_hash">
<longdesc lang="en">
Specify the hashing algorithm used for the Cluster IP functionality.
</longdesc>
<shortdesc lang="en">Cluster IP hashing function</shortdesc>
<content type="string" default="${OCF_RESKEY_clusterip_hash_default}"/>
</parameter>
<parameter name="unique_clone_address">
<longdesc lang="en">
If true, add the clone ID to the supplied value of IP to create
a unique address to manage
</longdesc>
<shortdesc lang="en">Create a unique address for cloned instances</shortdesc>
<content type="boolean" default="${OCF_RESKEY_unique_clone_address_default}"/>
</parameter>
<parameter name="arp_interval">
<longdesc lang="en">
Specify the interval between unsolicited ARP packets in milliseconds.
</longdesc>
<shortdesc lang="en">ARP packet interval in ms</shortdesc>
<content type="integer" default="${OCF_RESKEY_arp_interval_default}"/>
</parameter>
<parameter name="arp_count">
<longdesc lang="en">
Number of unsolicited ARP packets to send.
</longdesc>
<shortdesc lang="en">ARP packet count</shortdesc>
<content type="integer" default="${OCF_RESKEY_arp_count_default}"/>
</parameter>
<parameter name="arp_bg">
<longdesc lang="en">
Whether or not to send the ARP packets in the background.
</longdesc>
<shortdesc lang="en">ARP from background</shortdesc>
<content type="string" default="${OCF_RESKEY_arp_bg_default}"/>
</parameter>
<parameter name="arp_mac">
<longdesc lang="en">
MAC address to send the ARP packets to.
You really shouldn't be touching this.
</longdesc>
<shortdesc lang="en">ARP MAC</shortdesc>
<content type="string" default="${OCF_RESKEY_arp_mac_default}"/>
</parameter>
<parameter name="arp_sender">
<longdesc lang="en">
The program to send ARP packets with on start. For infiniband
interfaces, default is ipoibarping. If ipoibarping is not
available, set this to send_arp.
</longdesc>
<shortdesc lang="en">ARP sender</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="flush_routes">
<longdesc lang="en">
Flush the routing table on stop. This is for
applications which use the cluster IP address
and which run on the same physical host that the
IP address lives on. The Linux kernel may force that
application to take a shortcut to the local loopback
interface, instead of the interface the address
is really bound to. Under those circumstances, an
application may, somewhat unexpectedly, continue
to use connections for some time even after the
IP address is deconfigured. Set this parameter in
order to immediately disable said shortcut when the
IP address goes away.
</longdesc>
<shortdesc lang="en">Flush kernel routing table on stop</shortdesc>
<content type="boolean" default="false"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="20s" />
<action name="stop" timeout="20s" />
<action name="status" depth="0" timeout="20s" interval="10s" />
<action name="monitor" depth="0" timeout="20s" interval="10s" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="20s" />
</actions>
</resource-agent>
END
exit $OCF_SUCCESS
}
ip_init() {
local rc
if [ X`uname -s` != "XLinux" ]; then
- ocf_log err "IPaddr2 only supported Linux."
+ ocf_exit_reason "IPaddr2 only supported Linux."
exit $OCF_ERR_INSTALLED
fi
if [ X"$OCF_RESKEY_ip" = "X" ]; then
- ocf_log err "IP address (the ip parameter) is mandatory"
+ ocf_exit_reason "IP address (the ip parameter) is mandatory"
exit $OCF_ERR_CONFIGURED
fi
if
case $__OCF_ACTION in
start|stop) ocf_is_root;;
*) true;;
esac
then
: YAY!
else
- ocf_log err "You must be root for $__OCF_ACTION operation."
+ ocf_exit_reason "You must be root for $__OCF_ACTION operation."
exit $OCF_ERR_PERM
fi
BASEIP="$OCF_RESKEY_ip"
BRDCAST="$OCF_RESKEY_broadcast"
NIC="$OCF_RESKEY_nic"
# Note: We had a version out there for a while which used
# netmask instead of cidr_netmask. Don't remove this aliasing code!
if
[ ! -z "$OCF_RESKEY_netmask" -a -z "$OCF_RESKEY_cidr_netmask" ]
then
OCF_RESKEY_cidr_netmask=$OCF_RESKEY_netmask
export OCF_RESKEY_cidr_netmask
fi
NETMASK="$OCF_RESKEY_cidr_netmask"
IFLABEL="$OCF_RESKEY_iflabel"
IF_MAC="$OCF_RESKEY_mac"
IP_INC_GLOBAL=${OCF_RESKEY_CRM_meta_clone_max:-1}
IP_INC_NO=`expr ${OCF_RESKEY_CRM_meta_clone:-0} + 1`
if ocf_is_true ${OCF_RESKEY_lvs_support} && [ $IP_INC_GLOBAL -gt 1 ]; then
- ocf_log err "LVS and load sharing do not go together well"
+ ocf_exit_reason "LVS and load sharing do not go together well"
exit $OCF_ERR_CONFIGURED
fi
if ocf_is_decimal "$IP_INC_GLOBAL" && [ $IP_INC_GLOBAL -gt 0 ]; then
:
else
- ocf_log err "Invalid meta-attribute clone_max [$IP_INC_GLOBAL], should be positive integer"
+ ocf_exit_reason "Invalid meta-attribute clone_max [$IP_INC_GLOBAL], should be positive integer"
exit $OCF_ERR_CONFIGURED
fi
echo $OCF_RESKEY_ip | grep -qs ":"
if [ $? -ne 0 ];then
FAMILY=inet
if ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
- ocf_log err "IPv4 does not support lvs_ipv6_addrlabel"
+ ocf_exit_reason "IPv4 does not support lvs_ipv6_addrlabel"
exit $OCF_ERR_CONFIGURED
fi
else
FAMILY=inet6
if ocf_is_true $OCF_RESKEY_lvs_support ;then
- ocf_log err "The IPv6 does not support lvs_support"
+ ocf_exit_reason "The IPv6 does not support lvs_support"
exit $OCF_ERR_CONFIGURED
fi
if ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
if ocf_is_decimal "$OCF_RESKEY_lvs_ipv6_addrlabel_value" && [ $OCF_RESKEY_lvs_ipv6_addrlabel_value -ge 0 ]; then
:
else
- ocf_log err "Invalid lvs_ipv6_addrlabel_value [$OCF_RESKEY_lvs_ipv6_addrlabel_value], should be positive integer"
+ ocf_exit_reason "Invalid lvs_ipv6_addrlabel_value [$OCF_RESKEY_lvs_ipv6_addrlabel_value], should be positive integer"
exit $OCF_ERR_CONFIGURED
fi
fi
fi
# support nic:iflabel format in nic parameter
case $NIC in
*:*)
IFLABEL=`echo $NIC | sed 's/[^:]*://'`
NIC=`echo $NIC | sed 's/:.*//'`
# only the base name should be passed to findif
OCF_RESKEY_nic=$NIC
;;
esac
# $FINDIF takes its parameters from the environment
#
NICINFO=`$FINDIF`
rc=$?
if
[ $rc -eq 0 ]
then
NICINFO=`echo "$NICINFO" | sed -e 's/netmask\ //;s/broadcast\ //'`
NIC=`echo "$NICINFO" | cut -d" " -f1`
NETMASK=`echo "$NICINFO" | cut -d" " -f2`
BRDCAST=`echo "$NICINFO" | cut -d" " -f3`
else
# findif couldn't find the interface
if ocf_is_probe; then
ocf_log info "[$FINDIF] failed"
exit $OCF_NOT_RUNNING
elif [ "$__OCF_ACTION" = stop ]; then
ocf_log warn "[$FINDIF] failed"
exit $OCF_SUCCESS
else
- ocf_log err "[$FINDIF] failed"
+ ocf_exit_reason "[$FINDIF] failed"
exit $rc
fi
fi
SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$OCF_RESKEY_ip"
if [ -n "$IFLABEL" ]; then
IFLABEL=${NIC}:${IFLABEL}
if [ ${#IFLABEL} -gt 15 ]; then
- ocf_log err "Interface label [$IFLABEL] exceeds maximum character limit of 15"
+ ocf_exit_reason "Interface label [$IFLABEL] exceeds maximum character limit of 15"
exit $OCF_ERR_CONFIGURED
fi
fi
if [ "$IP_INC_GLOBAL" -gt 1 ] && ! ocf_is_true "$OCF_RESKEY_unique_clone_address"; then
IP_CIP="yes"
IP_CIP_HASH="${OCF_RESKEY_clusterip_hash}"
if [ -z "$IF_MAC" ]; then
# Choose a MAC
# 1. Concatenate some input together
# 2. This doesn't need to be a cryptographically
# secure hash.
# 3. Drop everything after the first 6 octets (12 chars)
# 4. Delimit the octets with ':'
# 5. Make sure the first octet is odd,
# so the result is a multicast MAC
IF_MAC=`echo $OCF_RESKEY_ip $NETMASK $BRDCAST | \
md5sum | \
sed -e 's#\(............\).*#\1#' \
-e 's#..#&:#g; s#:$##' \
-e 's#^\(.\)[02468aAcCeE]#\11#'`
fi
IP_CIP_FILE="/proc/net/ipt_CLUSTERIP/$OCF_RESKEY_ip"
fi
}
#
# Find out which interfaces serve the given IP address and netmask.
# The arguments are an IP address and a netmask.
# Its output are interface names devided by spaces (e.g., "eth0 eth1").
#
find_interface() {
local ipaddr="$1"
local netmask="$2"
#
# List interfaces but exclude FreeS/WAN ipsecN virtual interfaces
#
local iface="`$IP2UTIL -o -f $FAMILY addr show \
| grep "\ $ipaddr/$netmask" \
| cut -d ' ' -f2 \
| grep -v '^ipsec[0-9][0-9]*$'`"
echo "$iface"
return 0
}
#
# Delete an interface
#
delete_interface () {
ipaddr="$1"
iface="$2"
netmask="$3"
CMD="$IP2UTIL -f $FAMILY addr delete $ipaddr/$netmask dev $iface"
ocf_run $CMD || return $OCF_ERR_GENERIC
if ocf_is_true $OCF_RESKEY_flush_routes; then
ocf_run $IP2UTIL route flush cache
fi
if [ "$FAMILY" = "inet6" ] && ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
delete_ipv6_addrlabel $ipaddr
fi
return $OCF_SUCCESS
}
#
# Add an interface
#
add_interface () {
local cmd msg ipaddr netmask broadcast iface label
ipaddr="$1"
netmask="$2"
broadcast="$3"
iface="$4"
label="$5"
if [ "$FAMILY" = "inet6" ] && ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then
add_ipv6_addrlabel $ipaddr
fi
cmd="$IP2UTIL -f $FAMILY addr add $ipaddr/$netmask dev $iface"
msg="Adding $FAMILY address $ipaddr/$netmask to device $iface"
if [ "$broadcast" != "none" ]; then
cmd="$IP2UTIL -f $FAMILY addr add $ipaddr/$netmask brd $broadcast dev $iface"
msg="Adding $FAMILY address $ipaddr/$netmask with broadcast address $broadcast to device $iface"
fi
if [ ! -z "$label" ]; then
cmd="$cmd label $label"
msg="${msg} (with label $label)"
fi
ocf_log info "$msg"
ocf_run $cmd || return $OCF_ERR_GENERIC
msg="Bringing device $iface up"
cmd="$IP2UTIL link set $iface up"
ocf_log info "$msg"
ocf_run $cmd || return $OCF_ERR_GENERIC
return $OCF_SUCCESS
}
#
# Delete a route
#
delete_route () {
prefix="$1"
iface="$2"
CMD="$IP2UTIL route delete $prefix dev $iface"
ocf_log info "$CMD"
$CMD
return $?
}
# On Linux systems the (hidden) loopback interface may
# conflict with the requested IP address. If so, this
# unoriginal code will remove the offending loopback address
# and save it in VLDIR so it can be added back in later
# when the IPaddr is released.
#
# TODO: This is very ugly and should be controlled by an additional
# instance parameter. Or even: multi-state, with the IP only being
# "active" on the master!?
#
remove_conflicting_loopback() {
ipaddr="$1"
netmask="$2"
broadcast="$3"
ifname="$4"
ocf_log info "Removing conflicting loopback $ifname."
if
echo "$ipaddr $netmask $broadcast $ifname" > "$VLDIR/$ipaddr"
then
: Saved loopback information in $VLDIR/$ipaddr
else
ocf_log err "Could not save conflicting loopback $ifname." \
"it will not be restored."
fi
delete_interface "$ipaddr" "$ifname" "$netmask"
# Forcibly remove the route (if it exists) to the loopback.
delete_route "$ipaddr" "$ifname"
}
#
# On Linux systems the (hidden) loopback interface may
# need to be restored if it has been taken down previously
# by remove_conflicting_loopback()
#
restore_loopback() {
ipaddr="$1"
if [ -s "$VLDIR/$ipaddr" ]; then
ifinfo=`cat "$VLDIR/$ipaddr"`
ocf_log info "Restoring loopback IP Address " \
"$ifinfo."
add_interface $ifinfo
rm -f "$VLDIR/$ipaddr"
fi
}
add_ipv6_addrlabel() {
local cmd ipaddr value
ipaddr="$1"
value="$OCF_RESKEY_lvs_ipv6_addrlabel_value"
cmd="$IP2UTIL addrlabel add prefix $ipaddr label $value"
ocf_log info "Adding IPv6 address label prefix $ipaddr label $value"
ocf_run $cmd || ocf_log warn "$cmd failed."
}
delete_ipv6_addrlabel() {
local cmd ipaddr value
ipaddr="$1"
value="$OCF_RESKEY_lvs_ipv6_addrlabel_value"
cmd="$IP2UTIL addrlabel del prefix $ipaddr label $value"
ocf_run $cmd # an error can be ignored
}
is_infiniband() {
$IP2UTIL link show $NIC | grep link/infiniband >/dev/null
}
#
# Run send_arp to note peers about new mac address
#
run_send_arp() {
ARGS="-i $OCF_RESKEY_arp_interval -r $OCF_RESKEY_arp_count -p $SENDARPPIDFILE $NIC $OCF_RESKEY_ip auto not_used not_used"
if [ "x$IP_CIP" = "xyes" ] ; then
if [ x = "x$IF_MAC" ] ; then
MY_MAC=auto
else
MY_MAC=`echo ${IF_MAC} | sed -e 's/://g'`
fi
ARGS="-i $OCF_RESKEY_arp_interval -r $OCF_RESKEY_arp_count -p $SENDARPPIDFILE $NIC $OCF_RESKEY_ip $MY_MAC not_used not_used"
fi
ocf_log info "$SENDARP $ARGS"
if ocf_is_true $OCF_RESKEY_arp_bg; then
($SENDARP $ARGS || ocf_log err "Could not send gratuitous arps")& >&2
else
$SENDARP $ARGS || ocf_log err "Could not send gratuitous arps"
fi
}
#
# Run send_ua to note send ICMPv6 Unsolicited Neighbor Advertisements.
#
run_send_ua() {
local i
# Wait until the allocated IPv6 address gets ready by checking
# "tentative" flag is disappeared, otherwise send_ua can not
# send the unsolicited advertisement requests.
for i in 1 2 3 4 5; do
$IP2UTIL -o -f $FAMILY addr show dev $NIC \
| grep -q -e "$OCF_RESKEY_ip/$NETMASK .* tentative"
[ $? -ne 0 ] && break
if [ $i -eq 5 ]; then
ocf_log warn "$OCF_RESKEY_ip still has 'tentative' status. (ignored)"
break
fi
sleep 1
done
ARGS="-i $OCF_RESKEY_arp_interval -c $OCF_RESKEY_arp_count $OCF_RESKEY_ip $NETMASK $NIC"
ocf_log info "$SENDUA $ARGS"
$SENDUA $ARGS || ocf_log err "Could not send ICMPv6 Unsolicited Neighbor Advertisements."
}
#
# Run ipoibarping to note peers about new Infiniband address
#
run_send_ib_arp() {
ARGS="-q -c $OCF_RESKEY_arp_count -U -I $NIC $OCF_RESKEY_ip"
ocf_log info "ipoibarping $ARGS"
if ocf_is_true $OCF_RESKEY_arp_bg; then
(ipoibarping $ARGS || ocf_log err "Could not send gratuitous arps")& >&2
else
ipoibarping $ARGS || ocf_log err "Could not send gratuitous arps"
fi
}
# Do we already serve this IP address on the given $NIC?
#
# returns:
# ok = served (for CIP: + hash bucket)
# partial = served and no hash bucket (CIP only)
# partial2 = served and no CIP iptables rule
# no = nothing
#
ip_served() {
if [ -z "$NIC" ]; then # no nic found or specified
echo "no"
return 0
fi
cur_nic="`find_interface $OCF_RESKEY_ip $NETMASK`"
if [ -z "$cur_nic" ]; then
echo "no"
return 0
fi
if [ -z "$IP_CIP" ]; then
for i in $cur_nic; do
# only mark as served when on the same interfaces as $NIC
[ "$i" = "$NIC" ] || continue
echo "ok"
return 0
done
# There used to be logic here to pretend "not served",
# if ${OCF_RESKEY_lvs_support} was enabled, and the IP was
# found active on "lo*" only. With lvs_support on, you should
# have NIC != lo, so thats already filtered
# by the continue above.
echo "no"
return 0
fi
# Special handling for the CIP:
if [ ! -e $IP_CIP_FILE ]; then
echo "partial2"
return 0
fi
if egrep -q "(^|,)${IP_INC_NO}(,|$)" $IP_CIP_FILE ; then
echo "ok"
return 0
else
echo "partial"
return 0
fi
exit $OCF_ERR_GENERIC
}
#######################################################################
ip_usage() {
cat <<END
usage: $0 {start|stop|status|monitor|validate-all|meta-data}
Expects to have a fully populated OCF RA-compliant environment set.
END
}
ip_start() {
- if [ -z "$NIC" ]; then # no nic found or specified
+ if [ -z "$NIC" ]; then
+ ocf_exit_reason "No nic found or specified"
exit $OCF_ERR_CONFIGURED
fi
if [ -n "$IP_CIP" ]; then
# Cluster IPs need special processing when the first bucket
# is added to the node... take a lock to make sure only one
# process executes that code
ocf_take_lock $CIP_lockfile
ocf_release_lock_on_exit $CIP_lockfile
fi
#
# Do we already service this IP address on $NIC?
#
local ip_status=`ip_served`
if [ "$ip_status" = "ok" ]; then
exit $OCF_SUCCESS
fi
if [ -n "$IP_CIP" ] && [ $ip_status = "no" ] || [ $ip_status = "partial2" ]; then
$MODPROBE ip_conntrack
$IPTABLES -I INPUT -d $OCF_RESKEY_ip -i $NIC -j CLUSTERIP \
--new \
--clustermac $IF_MAC \
--total-nodes $IP_INC_GLOBAL \
--local-node $IP_INC_NO \
--hashmode $IP_CIP_HASH
if [ $? -ne 0 ]; then
- ocf_log err "iptables failed"
+ ocf_exit_reason "iptables failed"
exit $OCF_ERR_GENERIC
fi
fi
if [ -n "$IP_CIP" ] && [ $ip_status = "partial" ]; then
echo "+$IP_INC_NO" >$IP_CIP_FILE
fi
if [ "$ip_status" = "no" ]; then
if ocf_is_true ${OCF_RESKEY_lvs_support}; then
for i in `find_interface $OCF_RESKEY_ip 32`; do
case $i in
lo*)
remove_conflicting_loopback $OCF_RESKEY_ip 32 255.255.255.255 lo
;;
esac
done
fi
add_interface $OCF_RESKEY_ip $NETMASK ${BRDCAST:-none} $NIC $IFLABEL
if [ $? -ne 0 ]; then
- ocf_log err "$CMD failed."
+ ocf_exit_reason "$CMD failed."
exit $OCF_ERR_GENERIC
fi
fi
case $NIC in
lo*)
: no need to run send_arp on loopback
;;
*)
if [ $FAMILY = "inet" ];then
$ARP_SEND_FUN
else
if [ -x $SENDUA ]; then
run_send_ua
fi
fi
;;
esac
exit $OCF_SUCCESS
}
ip_stop() {
local ip_del_if="yes"
if [ -n "$IP_CIP" ]; then
# Cluster IPs need special processing when the last bucket
# is removed from the node... take a lock to make sure only one
# process executes that code
ocf_take_lock $CIP_lockfile
ocf_release_lock_on_exit $CIP_lockfile
fi
if [ -f "$SENDARPPIDFILE" ] ; then
kill `cat "$SENDARPPIDFILE"`
if [ $? -ne 0 ]; then
ocf_log warn "Could not kill previously running send_arp for $OCF_RESKEY_ip"
else
ocf_log info "killed previously running send_arp for $OCF_RESKEY_ip"
rm -f "$SENDARPPIDFILE"
fi
fi
local ip_status=`ip_served`
ocf_log info "IP status = $ip_status, IP_CIP=$IP_CIP"
if [ $ip_status = "no" ]; then
: Requested interface not in use
exit $OCF_SUCCESS
fi
if [ -n "$IP_CIP" ] && [ $ip_status != "partial2" ]; then
if [ $ip_status = "partial" ]; then
exit $OCF_SUCCESS
fi
echo "-$IP_INC_NO" >$IP_CIP_FILE
if [ "x$(cat $IP_CIP_FILE)" = "x" ]; then
ocf_log info $OCF_RESKEY_ip, $IP_CIP_HASH
i=1
while [ $i -le $IP_INC_GLOBAL ]; do
ocf_log info $i
$IPTABLES -D INPUT -d $OCF_RESKEY_ip -i $NIC -j CLUSTERIP \
--new \
--clustermac $IF_MAC \
--total-nodes $IP_INC_GLOBAL \
--local-node $i \
--hashmode $IP_CIP_HASH
i=`expr $i + 1`
done
else
ip_del_if="no"
fi
fi
if [ "$ip_del_if" = "yes" ]; then
delete_interface $OCF_RESKEY_ip $NIC $NETMASK
if [ $? -ne 0 ]; then
+ ocf_exit_reason "Unable to remove IP [${OCF_RESKEY_ip} from interface [ $NIC ]"
exit $OCF_ERR_GENERIC
fi
if ocf_is_true ${OCF_RESKEY_lvs_support}; then
restore_loopback "$OCF_RESKEY_ip"
fi
fi
exit $OCF_SUCCESS
}
ip_monitor() {
# TODO: Implement more elaborate monitoring like checking for
# interface health maybe via a daemon like FailSafe etc...
local ip_status=`ip_served`
case $ip_status in
ok)
return $OCF_SUCCESS
;;
partial|no|partial2)
exit $OCF_NOT_RUNNING
;;
*)
# Errors on this interface?
return $OCF_ERR_GENERIC
;;
esac
}
# make sure that we have something to send ARPs with
set_send_arp_program() {
ARP_SEND_FUN=run_send_arp
if [ -n "$OCF_RESKEY_arp_sender" ]; then
case "$OCF_RESKEY_arp_sender" in
send_arp)
check_binary $SENDARP
;;
ipoibarping)
check_binary ipoibarping
ARP_SEND_FUN=run_send_ib_arp
;;
*)
- ocf_log err "unrecognized arp_sender value: $OCF_RESKEY_arp_sender"
+ ocf_exit_reason "unrecognized arp_sender value: $OCF_RESKEY_arp_sender"
exit $OCF_ERR_CONFIGURED
;;
esac
else
if is_infiniband; then
ARP_SEND_FUN=run_send_ib_arp
if ! have_binary ipoibarping; then
[ "$__OCF_ACTION" = start ] &&
ocf_log warn "using send_arp for infiniband because ipoibarping is not available (set arp_sender to \"send_arp\" to suppress this message)"
check_binary $SENDARP
ARP_SEND_FUN=run_send_arp
fi
fi
fi
}
ip_validate() {
check_binary $IP2UTIL
IP_CIP=
ip_init
set_send_arp_program
if [ -n "$IP_CIP" ]; then
check_binary $IPTABLES
check_binary $MODPROBE
fi
# $BASEIP, $NETMASK, $NIC , $IP_INC_GLOBAL, and $BRDCAST have been checked within ip_init,
# do not bother here.
if ocf_is_true "$OCF_RESKEY_unique_clone_address" &&
! ocf_is_true "$OCF_RESKEY_CRM_meta_globally_unique"; then
- ocf_log err "unique_clone_address makes sense only with meta globally_unique set"
+ ocf_exit_reason "unique_clone_address makes sense only with meta globally_unique set"
exit $OCF_ERR_CONFIGURED
fi
if ocf_is_decimal "$OCF_RESKEY_arp_interval" && [ $OCF_RESKEY_arp_interval -gt 0 ]; then
:
else
- ocf_log err "Invalid OCF_RESKEY_arp_interval [$OCF_RESKEY_arp_interval]"
+ ocf_exit_reason "Invalid OCF_RESKEY_arp_interval [$OCF_RESKEY_arp_interval]"
exit $OCF_ERR_CONFIGURED
fi
if ocf_is_decimal "$OCF_RESKEY_arp_count" && [ $OCF_RESKEY_arp_count -gt 0 ]; then
:
else
- ocf_log err "Invalid OCF_RESKEY_arp_count [$OCF_RESKEY_arp_count]"
+ ocf_exit_reason "Invalid OCF_RESKEY_arp_count [$OCF_RESKEY_arp_count]"
exit $OCF_ERR_CONFIGURED
fi
if [ -n "$IP_CIP" ]; then
local valid=1
case $IP_CIP_HASH in
sourceip|sourceip-sourceport|sourceip-sourceport-destport)
;;
*)
- ocf_log err "Invalid OCF_RESKEY_clusterip_hash [$IP_CIP_HASH]"
+ ocf_exit_reason "Invalid OCF_RESKEY_clusterip_hash [$IP_CIP_HASH]"
exit $OCF_ERR_CONFIGURED
;;
esac
if ocf_is_true ${OCF_RESKEY_lvs_support}; then
- ecf_log err "LVS and load sharing not advised to try"
+ ocf_exit_reason "LVS and load sharing not advised to try"
exit $OCF_ERR_CONFIGURED
fi
case $IF_MAC in
[0-9a-zA-Z][13579bBdDfF][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z])
;;
*)
valid=0
;;
esac
if [ $valid -eq 0 ]; then
- ocf_log err "Invalid IF_MAC [$IF_MAC]"
+ ocf_exit_reason "Invalid IF_MAC [$IF_MAC]"
exit $OCF_ERR_CONFIGURED
fi
fi
}
if ocf_is_true "$OCF_RESKEY_unique_clone_address"; then
prefix=`echo $OCF_RESKEY_ip | awk -F. '{print $1"."$2"."$3}'`
suffix=`echo $OCF_RESKEY_ip | awk -F. '{print $4}'`
suffix=`expr ${OCF_RESKEY_CRM_meta_clone:-0} + $suffix`
OCF_RESKEY_ip="$prefix.$suffix"
fi
case $__OCF_ACTION in
meta-data) meta_data
;;
usage|help) ip_usage
exit $OCF_SUCCESS
;;
esac
ip_validate
case $__OCF_ACTION in
start) ip_start
;;
stop) ip_stop
;;
status) ip_status=`ip_served`
if [ $ip_status = "ok" ]; then
echo "running"
exit $OCF_SUCCESS
else
echo "stopped"
exit $OCF_NOT_RUNNING
fi
;;
monitor) ip_monitor
;;
validate-all) ;;
*) ip_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
# vi:sw=4:ts=8:
diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain
index 546edd746..2e22b4f85 100755
--- a/heartbeat/VirtualDomain
+++ b/heartbeat/VirtualDomain
@@ -1,741 +1,742 @@
#!/bin/sh
#
# Support: linux-ha@lists.linux-ha.org
# License: GNU General Public License (GPL)
#
# Resource Agent for domains managed by the libvirt API.
# Requires a running libvirt daemon (libvirtd).
#
# (c) 2008-2010 Florian Haas, Dejan Muhamedagic,
# and Linux-HA contributors
#
# usage: $0 {start|stop|status|monitor|migrate_to|migrate_from|meta-data|validate-all}
#
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
# Defaults
OCF_RESKEY_force_stop_default=0
OCF_RESKEY_autoset_utilization_cpu_default="true"
OCF_RESKEY_autoset_utilization_hv_memory_default="true"
OCF_RESKEY_migrateport_default=$(( 49152 + $(ocf_maybe_random) % 64 ))
OCF_RESKEY_CRM_meta_timeout_default=90000
OCF_RESKEY_save_config_on_stop_default=false
: ${OCF_RESKEY_force_stop=${OCF_RESKEY_force_stop_default}}
: ${OCF_RESKEY_autoset_utilization_cpu=${OCF_RESKEY_autoset_utilization_cpu_default}}
: ${OCF_RESKEY_autoset_utilization_hv_memory=${OCF_RESKEY_autoset_utilization_hv_memory_default}}
: ${OCF_RESKEY_migrateport=${OCF_RESKEY_migrateport_default}}
: ${OCF_RESKEY_CRM_meta_timeout=${OCF_RESKEY_CRM_meta_timeout_default}}
: ${OCF_RESKEY_save_config_on_stop=${OCF_RESKEY_save_config_on_stop_default}}
#######################################################################
## I'd very much suggest to make this RA use bash,
## and then use magic $SECONDS.
## But for now:
NOW=$(date +%s)
usage() {
echo "usage: $0 {start|stop|status|monitor|migrate_to|migrate_from|meta-data|validate-all}"
}
meta_data() {
cat <<EOF
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="VirtualDomain">
<version>1.1</version>
<longdesc lang="en">
Resource agent for a virtual domain (a.k.a. domU, virtual machine,
virtual environment etc., depending on context) managed by libvirtd.
</longdesc>
<shortdesc lang="en">Manages virtual domains through the libvirt virtualization framework</shortdesc>
<parameters>
<parameter name="config" unique="1" required="1">
<longdesc lang="en">
Absolute path to the libvirt configuration file,
for this virtual domain.
</longdesc>
<shortdesc lang="en">Virtual domain configuration file</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="hypervisor" unique="0" required="0">
<longdesc lang="en">
Hypervisor URI to connect to. See the libvirt documentation for
details on supported URI formats. The default is system dependent.
Determine the system's default uri by running 'virsh --quiet uri'.
</longdesc>
<shortdesc lang="en">Hypervisor URI</shortdesc>
<content type="string"/>
</parameter>
<parameter name="force_stop" unique="0" required="0">
<longdesc lang="en">
Always forcefully shut down ("destroy") the domain on stop. The default
behavior is to resort to a forceful shutdown only after a graceful
shutdown attempt has failed. You should only set this to true if
your virtual domain (or your virtualization backend) does not support
graceful shutdown.
</longdesc>
<shortdesc lang="en">Always force shutdown on stop</shortdesc>
<content type="boolean" default="${OCF_RESKEY_force_stop_default}" />
</parameter>
<parameter name="migration_transport" unique="0" required="0">
<longdesc lang="en">
Transport used to connect to the remote hypervisor while
migrating. Please refer to the libvirt documentation for details on
transports available. If this parameter is omitted, the resource will
use libvirt's default transport to connect to the remote hypervisor.
</longdesc>
<shortdesc lang="en">Remote hypervisor transport</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="migration_network_suffix" unique="0" required="0">
<longdesc lang="en">
Use a dedicated migration network. The migration URI is composed by
adding this parameters value to the end of the node name. If the node
name happens to be an FQDN (as opposed to an unqualified host name),
insert the suffix immediately prior to the first period (.) in the FQDN.
At the moment Qemu/KVM and Xen migration via a dedicated network is supported.
Note: Be sure this composed host name is locally resolveable and the
associated IP is reachable through the favored network.
</longdesc>
<shortdesc lang="en">Migration network host name suffix</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="monitor_scripts" unique="0" required="0">
<longdesc lang="en">
To additionally monitor services within the virtual domain, add this
parameter with a list of scripts to monitor.
Note: when monitor scripts are used, the start and migrate_from operations
will complete only when all monitor scripts have completed successfully.
Be sure to set the timeout of these operations to accommodate this delay.
</longdesc>
<shortdesc lang="en">space-separated list of monitor scripts</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="autoset_utilization_cpu" unique="0" required="0">
<longdesc lang="en">
If set true, the agent will detect the number of domainU's vCPUs from virsh, and put it
into the CPU utilization of the resource when the monitor is executed.
</longdesc>
<shortdesc lang="en">Enable auto-setting the CPU utilization of the resource</shortdesc>
<content type="boolean" default="true" />
</parameter>
<parameter name="autoset_utilization_hv_memory" unique="0" required="0">
<longdesc lang="en">
If set true, the agent will detect the number of *Max memory* from virsh, and put it
into the hv_memory utilization of the resource when the monitor is executed.
</longdesc>
<shortdesc lang="en">Enable auto-setting the hv_memory utilization of the resource</shortdesc>
<content type="boolean" default="true" />
</parameter>
<parameter name="migrateport" unique="0" required="0">
<longdesc lang="en">
This port will be used in the qemu migrateuri. If unset, the port will be a random highport.
</longdesc>
<shortdesc lang="en">Port for migrateuri</shortdesc>
<content type="integer" />
</parameter>
<parameter name="save_config_on_stop" unique="0" required="0">
<longdesc lang="en">
Changes to a running VM's config are normally lost on stop.
This parameter instructs the RA to save the configuration back to the xml file provided in the "config" parameter.
</longdesc>
<shortdesc lang="en">Save running VM's config back to its config file</shortdesc>
<content type="boolean" />
</parameter>
<parameter name="snapshot">
<longdesc lang="en">
Path to the snapshot directory where the virtual machine image will be stored. When this
parameter is set, the virtual machine's RAM state will be saved to a file in the snapshot
directory when stopped. If on start a state file is present for the domain, the domain
will be restored to the same state it was in right before it stopped last. This option
is incompatible with the 'force_stop' option.
</longdesc>
<shortdesc lang="en">
Restore state on start/stop
</shortdesc>
<content type="string" default=""/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="90" />
<action name="stop" timeout="90" />
<action name="status" depth="0" timeout="30" interval="10" />
<action name="monitor" depth="0" timeout="30" interval="10" />
<action name="migrate_from" timeout="60" />
<action name="migrate_to" timeout="120" />
<action name="meta-data" timeout="5" />
<action name="validate-all" timeout="5" />
</actions>
</resource-agent>
EOF
}
set_util_attr() {
local attr=$1 val=$2
local cval outp
cval=$(crm_resource -Q -r $OCF_RESOURCE_INSTANCE -z -g $attr 2>/dev/null)
if [ $? -ne 0 ] && [ -z "$cval" ]; then
crm_resource -Q -r $OCF_RESOURCE_INSTANCE -z -g $attr 2>&1 | grep -e "not connected" > /dev/null 2>&1
if [ $? -eq 0 ]; then
ocf_log debug "Unable to set utilization attribute, cib is not available"
return
fi
fi
if [ "$cval" != "$val" ]; then
outp=$(crm_resource -r $OCF_RESOURCE_INSTANCE -z -p $attr -v $val 2>&1) ||
ocf_log warn "crm_resource failed to set utilization attribute $attr: $outp"
fi
}
update_utilization() {
local dom_cpu dom_mem
if ocf_is_true "$OCF_RESKEY_autoset_utilization_cpu"; then
dom_cpu=$(LANG=C virsh $VIRSH_OPTIONS dominfo ${DOMAIN_NAME} 2>/dev/null | awk '/CPU\(s\)/{print $2}')
test -n "$dom_cpu" && set_util_attr cpu $dom_cpu
fi
if ocf_is_true "$OCF_RESKEY_autoset_utilization_hv_memory"; then
dom_mem=$(LANG=C virsh $VIRSH_OPTIONS dominfo ${DOMAIN_NAME} 2>/dev/null | awk '/Max memory/{printf("%d", $3/1024)}')
test -n "$dom_mem" && set_util_attr hv_memory "$dom_mem"
fi
}
get_emulator()
{
local emulator=""
emulator=$(virsh $VIRSH_OPTIONS dumpxml $DOMAIN_NAME 2>/dev/null | sed -n -e 's/^.*<emulator>\(.*\)<\/emulator>.*$/\1/p')
if [ -z "$emulator" ] && [ -a "$EMULATOR_STATE" ]; then
emulator=$(cat $EMULATOR_STATE)
fi
if [ -z "$emulator" ]; then
emulator=$(cat ${OCF_RESKEY_config} | sed -n -e 's/^.*<emulator>\(.*\)<\/emulator>.*$/\1/p')
fi
if [ -n "$emulator" ]; then
basename $emulator
else
ocf_log error "Unable to determine emulator for $DOMAIN_NAME"
fi
}
update_emulator_cache()
{
local emulator
emulator=$(get_emulator)
if [ -n "$emulator" ]; then
echo $emulator > $EMULATOR_STATE
fi
}
# attempt to check domain status outside of libvirt using the emulator process
pid_status()
{
local rc=$OCF_ERR_GENERIC
local emulator=$(get_emulator)
case "$emulator" in
qemu-kvm|qemu-dm|qemu-system-*)
rc=$OCF_NOT_RUNNING
ps awx | grep -E "[q]emu-(kvm|dm|system).*-name $DOMAIN_NAME " > /dev/null 2>&1
if [ $? -eq 0 ]; then
rc=$OCF_SUCCESS
fi
;;
libvirt_lxc)
rc=$OCF_NOT_RUNNING
ps awx | grep -E "[l]ibvirt_lxc.*-name $DOMAIN_NAME " > /dev/null 2>&1
if [ $? -eq 0 ]; then
rc=$OCF_SUCCESS
fi
;;
# This can be expanded to check for additional emulators
*)
# We may be running xen with PV domains, they don't
# have an emulator set. try xenstore-ls in this case
if have_binary xenstore-ls; then
xenstore-ls -f /vm | grep -E "/vm.*name = \"$DOMAIN_NAME\"" > /dev/null 2>&1
if [ $? -eq 0 ]; then
rc=$OCF_SUCCESS
fi
fi
;;
esac
if [ $rc -eq $OCF_SUCCESS ]; then
ocf_log debug "Virtual domain $DOMAIN_NAME is currently running."
elif [ $rc -eq $OCF_NOT_RUNNING ]; then
ocf_log debug "Virtual domain $DOMAIN_NAME is currently not running."
fi
return $rc
}
VirtualDomain_Status() {
local try=0
rc=$OCF_ERR_GENERIC
status="no state"
while [ "$status" = "no state" ]; do
try=$(($try + 1 ))
status=$(virsh $VIRSH_OPTIONS domstate $DOMAIN_NAME 2>&1 | tr 'A-Z' 'a-z')
case "$status" in
*"error:"*"domain not found"*|"shut off")
# shut off: domain is defined, but not started, will not happen if
# domain is created but not defined
# Domain not found: domain is not defined and thus not started
ocf_log debug "Virtual domain $DOMAIN_NAME is not running: $(echo $status | sed s/error://g)"
rc=$OCF_NOT_RUNNING
;;
running|paused|idle|blocked|"in shutdown")
# running: domain is currently actively consuming cycles
# paused: domain is paused (suspended)
# idle: domain is running but idle
# blocked: synonym for idle used by legacy Xen versions
# in shutdown: the domain is in process of shutting down, but has not completely shutdown or crashed.
ocf_log debug "Virtual domain $DOMAIN_NAME is currently $status."
rc=$OCF_SUCCESS
;;
""|*"failed to "*"connect to the hypervisor"*|"no state")
# Empty string may be returned when virsh does not
# receive a reply from libvirtd.
# "no state" may occur when the domain is currently
# being migrated (on the migration target only), or
# whenever virsh can't reliably obtain the domain
# state.
status="no state"
if [ "$__OCF_ACTION" = "stop" ] && [ $try -ge 3 ]; then
# During the stop operation, we want to bail out
# quickly, so as to be able to force-stop (destroy)
# the domain if necessary.
ocf_log error "Virtual domain $DOMAIN_NAME has no state during stop operation, bailing out."
return $OCF_ERR_GENERIC;
elif [ "$__OCF_ACTION" = "monitor" ]; then
pid_status
rc=$?
if [ $rc -ne $OCF_ERR_GENERIC ]; then
# we've successfully determined the domains status outside of libvirt
return $rc
fi
else
# During all other actions, we just wait and try
# again, relying on the CRM/LRM to time us out if
# this takes too long.
ocf_log info "Virtual domain $DOMAIN_NAME currently has no state, retrying."
fi
sleep 1
;;
*)
# any other output is unexpected.
ocf_log error "Virtual domain $DOMAIN_NAME has unknown status \"$status\"!"
sleep 1
;;
esac
done
return $rc
}
verify_undefined() {
for dom in `virsh --connect=${OCF_RESKEY_hypervisor} list --all --name 2>/dev/null`; do
if [ "$dom" = "$DOMAIN_NAME" ]; then
virsh $VIRSH_OPTIONS undefine $DOMAIN_NAME > /dev/null 2>&1
return
fi
done
}
VirtualDomain_Start() {
local snapshotimage
if VirtualDomain_Status; then
ocf_log info "Virtual domain $DOMAIN_NAME already running."
return $OCF_SUCCESS
fi
snapshotimage="$OCF_RESKEY_snapshot/${DOMAIN_NAME}.state"
if [ -n "$OCF_RESKEY_snapshot" -a -f "$snapshotimage" ]; then
virsh restore $snapshotimage
if [ $? -eq 0 ]; then
rm -f $snapshotimage
return $OCF_SUCCESS
fi
- ocf_log error "Failed to restore ${DOMAIN_NAME} from state file in ${OCF_RESKEY_snapshot} directory."
+ ocf_exit_reason "Failed to restore ${DOMAIN_NAME} from state file in ${OCF_RESKEY_snapshot} directory."
return $OCF_ERR_GENERIC
fi
# Make sure domain is undefined before creating.
# The 'create' command guarantees that the domain will be
# undefined on shutdown, but requires the domain to be undefined.
# if a user defines the domain
# outside of this agent, we have to ensure that the domain
# is restored to an 'undefined' state before creating.
verify_undefined
virsh $VIRSH_OPTIONS create ${OCF_RESKEY_config}
rc=$?
if [ $rc -ne 0 ]; then
- ocf_log error "Failed to start virtual domain ${DOMAIN_NAME}."
+ ocf_exit_reason "Failed to start virtual domain ${DOMAIN_NAME}."
return $OCF_ERR_GENERIC
fi
while ! VirtualDomain_Monitor; do
sleep 1
done
return $OCF_SUCCESS
}
force_stop()
{
local out ex
local status=0
ocf_log info "Issuing forced shutdown (destroy) request for domain ${DOMAIN_NAME}."
out=$(virsh $VIRSH_OPTIONS destroy ${DOMAIN_NAME} 2>&1|tr 'A-Z' 'a-z')
ex=$?
echo >&2 "$out"
case $ex$out in
*"error:"*"domain is not running"*|*"error:"*"domain not found"*)
: ;; # unexpected path to the intended outcome, all is well
[!0]*)
+ ocf_exit_reason "forced stop failed"
return $OCF_ERR_GENERIC ;;
0*)
while [ $status != $OCF_NOT_RUNNING ]; do
VirtualDomain_Status
status=$?
done ;;
esac
return $OCF_SUCCESS
}
save_config(){
CFGTMP=$(mktemp -t vmcfgsave.XXX)
virsh $VIRSH_OPTIONS dumpxml ${DOMAIN_NAME} > ${CFGTMP}
if [ -s ${CFGTMP} ]; then
if virt-xml-validate ${CFGTMP} domain 2>/dev/null ; then
ocf_log info "Saving domain $DOMAIN_NAME to ${OCF_RESKEY_config}. Please make sure it's present on all nodes."
if cat ${CFGTMP} > ${OCF_RESKEY_config} ; then
ocf_log info "Saved $DOMAIN_NAME domain's configuration to ${OCF_RESKEY_config}."
else
ocf_log warn "Moving ${CFGTMP} to ${OCF_RESKEY_config} failed."
fi
else
ocf_log warn "Domain $DOMAIN_NAME config failed to validate after dump. Skipping config update."
fi
else
ocf_log warn "Domain $DOMAIN_NAME config has 0 size. Skipping config update."
fi
rm -f ${CFGTMP}
}
VirtualDomain_Stop() {
local i
local status
local shutdown_timeout
local needshutdown=1
VirtualDomain_Status
status=$?
case $status in
$OCF_SUCCESS)
if ocf_is_true $OCF_RESKEY_force_stop; then
# if force stop, don't bother attempting graceful shutdown.
force_stop
return $?
fi
ocf_log info "Issuing graceful shutdown request for domain ${DOMAIN_NAME}."
if [ -n "$OCF_RESKEY_snapshot" ]; then
virsh save $DOMAIN_NAME "$OCF_RESKEY_snapshot/${DOMAIN_NAME}.state"
if [ $? -eq 0 ]; then
needshutdown=0
else
ocf_log error "Failed to save snapshot state of ${DOMAIN_NAME} on stop"
fi
fi
# save config if needed
if ocf_is_true "$OCF_RESKEY_save_config_on_stop"; then
save_config
fi
# issue the shutdown if save state didn't shutdown for us
if [ $needshutdown -eq 1 ]; then
# Issue a graceful shutdown request
virsh $VIRSH_OPTIONS shutdown ${DOMAIN_NAME}
fi
# The "shutdown_timeout" we use here is the operation
# timeout specified in the CIB, minus 5 seconds
shutdown_timeout=$(( $NOW + ($OCF_RESKEY_CRM_meta_timeout/1000) -5 ))
# Loop on status until we reach $shutdown_timeout
while [ $NOW -lt $shutdown_timeout ]; do
VirtualDomain_Status
status=$?
case $status in
$OCF_NOT_RUNNING)
# This was a graceful shutdown.
return $OCF_SUCCESS
;;
$OCF_SUCCESS)
# Domain is still running, keep
# waiting (until shutdown_timeout
# expires)
sleep 1
;;
*)
# Something went wrong. Bail out and
# resort to forced stop (destroy).
break;
esac
NOW=$(date +%s)
done
;;
$OCF_NOT_RUNNING)
ocf_log info "Domain $DOMAIN_NAME already stopped."
return $OCF_SUCCESS
esac
# OK. Now if the above graceful shutdown hasn't worked, kill
# off the domain with destroy. If that too does not work,
# have the LRM time us out.
force_stop
}
VirtualDomain_Migrate_To() {
local target_node
local remoteuri
local transport_suffix
local migrateuri
local migrateport
local migrate_target
local hypervisor
target_node="$OCF_RESKEY_CRM_meta_migrate_target"
if VirtualDomain_Status; then
# Find out the remote hypervisor to connect to. That is, turn
# something like "qemu://foo:9999/system" into
# "qemu+tcp://bar:9999/system"
if [ -n "${OCF_RESKEY_migration_transport}" ]; then
transport_suffix="+${OCF_RESKEY_migration_transport}"
fi
# A typical migration URI via a special migration network looks
# like "tcp://bar-mig:49152". The port would be randomly chosen
# by libvirt from the range 49152-49215 if omitted, at least since
# version 0.7.4 ...
if [ -n "${OCF_RESKEY_migration_network_suffix}" ]; then
hypervisor="${OCF_RESKEY_hypervisor%%[+:]*}"
# Hostname might be a FQDN
migrate_target=$(echo ${target_node} | sed -e "s,^\([^.]\+\),\1${OCF_RESKEY_migration_network_suffix},")
case $hypervisor in
qemu)
# For quiet ancient libvirt versions a migration port is needed
# and the URI must not contain the "//". Newer versions can handle
# the "bad" URI.
migrateuri="tcp:${migrate_target}:${OCF_RESKEY_migrateport}"
;;
xen)
migrateuri="xenmigr://${migrate_target}"
;;
*)
ocf_log warn "$DOMAIN_NAME: Migration via dedicated network currently not supported for ${hypervisor}."
;;
esac
fi
# Scared of that sed expression? So am I. :-)
remoteuri=$(echo ${OCF_RESKEY_hypervisor} | sed -e "s,\(.*\)://[^/:]*\(:\?[0-9]*\)/\(.*\),\1${transport_suffix}://${target_node}\2/\3,")
# save config if needed
if ocf_is_true "$OCF_RESKEY_save_config_on_stop"; then
save_config
fi
# OK, we know where to connect to. Now do the actual migration.
ocf_log info "$DOMAIN_NAME: Starting live migration to ${target_node} (using remote hypervisor URI ${remoteuri} ${migrateuri})."
virsh ${VIRSH_OPTIONS} migrate --live $DOMAIN_NAME ${remoteuri} ${migrateuri}
rc=$?
if [ $rc -ne 0 ]; then
- ocf_log err "$DOMAIN_NAME: live migration to ${remoteuri} ${migrateuri} failed: $rc"
+ ocf_exit_reason "$DOMAIN_NAME: live migration to ${remoteuri} ${migrateuri} failed: $rc"
return $OCF_ERR_GENERIC
else
ocf_log info "$DOMAIN_NAME: live migration to ${target_node} succeeded."
return $OCF_SUCCESS
fi
else
- ocf_log err "$DOMAIN_NAME: migrate_to: Not active locally!"
+ ocf_exit_reason "$DOMAIN_NAME: migrate_to: Not active locally!"
return $OCF_ERR_GENERIC
fi
}
VirtualDomain_Migrate_From() {
while ! VirtualDomain_Monitor; do
sleep 1
done
ocf_log info "$DOMAIN_NAME: live migration from ${OCF_RESKEY_CRM_meta_migrate_source} succeeded."
# save config if needed
if ocf_is_true "$OCF_RESKEY_save_config_on_stop"; then
save_config
fi
return $OCF_SUCCESS
}
VirtualDomain_Monitor() {
# First, check the domain status. If that returns anything other
# than $OCF_SUCCESS, something is definitely wrong.
VirtualDomain_Status
rc=$?
if [ ${rc} -eq ${OCF_SUCCESS} ]; then
# OK, the generic status check turned out fine. Now, if we
# have monitor scripts defined, run them one after another.
for script in ${OCF_RESKEY_monitor_scripts}; do
script_output="$($script 2>&1)"
script_rc=$?
if [ ${script_rc} -ne ${OCF_SUCCESS} ]; then
# A monitor script returned a non-success exit
# code. Stop iterating over the list of scripts, log a
# warning message, and propagate $OCF_ERR_GENERIC.
- ocf_log warn "Monitor command \"${script}\" for domain ${DOMAIN_NAME} returned ${script_rc} with output: ${script_output}"
+ ocf_exit_reason "Monitor command \"${script}\" for domain ${DOMAIN_NAME} returned ${script_rc} with output: ${script_output}"
rc=$OCF_ERR_GENERIC
break
else
ocf_log debug "Monitor command \"${script}\" for domain ${DOMAIN_NAME} completed successfully with output: ${script_output}"
fi
done
fi
update_emulator_cache
update_utilization
return ${rc}
}
VirtualDomain_Validate_All() {
# Required binaries:
for binary in virsh sed; do
check_binary $binary
done
if [ -z $OCF_RESKEY_config ]; then
- ocf_log error "Missing configuration parameter \"config\"."
+ ocf_exit_reason "Missing configuration parameter \"config\"."
return $OCF_ERR_CONFIGURED
fi
if ocf_is_true $OCF_RESKEY_force_stop; then
if [ -n "$OCF_RESKEY_snapshot" ]; then
- ocf_log error "The 'force_stop' and 'snapshot' options can not be used together."
+ ocf_exit_reason "The 'force_stop' and 'snapshot' options can not be used together."
return $OCF_ERR_CONFIGURED
fi
fi
# check if we can read the config file (otherwise we're unable to
# deduce $DOMAIN_NAME from it, see below)
if [ ! -r $OCF_RESKEY_config ]; then
if ocf_is_probe; then
ocf_log info "Configuration file $OCF_RESKEY_config not readable during probe."
elif [ "$__OCF_ACTION" = "stop" ]; then
ocf_log info "Configuration file $OCF_RESKEY_config not readable, resource considered stopped."
else
- ocf_log error "Configuration file $OCF_RESKEY_config does not exist or is not readable."
+ ocf_exit_reason "Configuration file $OCF_RESKEY_config does not exist or is not readable."
return $OCF_ERR_INSTALLED
fi
fi
}
if [ $# -ne 1 ]; then
usage
exit $OCF_ERR_ARGS
fi
case $1 in
meta-data) meta_data
exit $OCF_SUCCESS
;;
usage) usage
exit $OCF_SUCCESS
;;
esac
# Grab the virsh uri default, but only if hypervisor isn't set
: ${OCF_RESKEY_hypervisor=$(virsh --quiet uri 2>/dev/null)}
# Set options to be passed to virsh:
VIRSH_OPTIONS="--connect=${OCF_RESKEY_hypervisor} --quiet"
# Everything except usage and meta-data must pass the validate test
VirtualDomain_Validate_All || exit $?
# During a probe, it is permissible for the config file to not be
# readable (it might be on shared storage not available during the
# probe). In that case, we're
# unable to get the domain name. Thus, we also can't check whether the
# domain is running. The only thing we can do here is to assume that
# it is not running.
if [ ! -r $OCF_RESKEY_config ]; then
ocf_is_probe && exit $OCF_NOT_RUNNING
[ "$__OCF_ACTION" = "stop" ] && exit $OCF_SUCCESS
fi
# Retrieve the domain name from the xml file.
DOMAIN_NAME=`egrep '[[:space:]]*<name>.*</name>[[:space:]]*$' ${OCF_RESKEY_config} | sed -e 's/[[:space:]]*<name>\(.*\)<\/name>[[:space:]]*$/\1/' 2>/dev/null`
if [ -z $DOMAIN_NAME ]; then
- ocf_log err "This is unexpected. Cannot determine domain name."
+ ocf_exit_reason "Unable to determine domain name."
exit $OCF_ERR_GENERIC
fi
EMULATOR_STATE="${HA_RSCTMP}/VirtualDomain-${DOMAIN_NAME}-emu.state"
case $1 in
start)
VirtualDomain_Start
;;
stop)
VirtualDomain_Stop
;;
migrate_to)
VirtualDomain_Migrate_To
;;
migrate_from)
VirtualDomain_Migrate_From
;;
status)
VirtualDomain_Status
;;
monitor)
VirtualDomain_Monitor
;;
validate-all)
;;
*)
usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit $?
diff --git a/heartbeat/exportfs b/heartbeat/exportfs
index 14e70ae7a..da848fea2 100755
--- a/heartbeat/exportfs
+++ b/heartbeat/exportfs
@@ -1,430 +1,433 @@
#!/bin/sh
# exportfs
#
# Description: Manages nfs exported file system.
#
# (c) 2010 Ben Timby, Florian Haas, Dejan Muhamedagic,
# and Linux-HA contributors
#
# License: GNU General Public License v2 (GPLv2) and later
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
# Defaults
OCF_RESKEY_unlock_on_stop_default=1
OCF_RESKEY_wait_for_leasetime_on_stop_default=0
OCF_RESKEY_rmtab_backup_default=".rmtab"
: ${OCF_RESKEY_unlock_on_stop=${OCF_RESKEY_unlock_on_stop_default}}
: ${OCF_RESKEY_wait_for_leasetime_on_stop=${OCF_RESKEY_wait_for_leasetime_on_stop_default}}
: ${OCF_RESKEY_rmtab_backup=${OCF_RESKEY_rmtab_backup_default}}
#######################################################################
exportfs_meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="exportfs">
<version>1.0</version>
<longdesc lang="en">
Exportfs uses the exportfs command to add/remove nfs exports.
It does NOT manage the nfs server daemon.
It depends on Linux specific NFS implementation details,
so is considered not portable to other platforms yet.
</longdesc>
<shortdesc lang="en">
Manages NFS exports
</shortdesc>
<parameters>
<parameter name="clientspec" unique="0" required="1">
<longdesc lang="en">
The client specification allowing remote machines to mount the directory
(or directories) over NFS.
</longdesc>
<shortdesc lang="en">
Client ACL.
</shortdesc>
<content type="string" />
</parameter>
<parameter name="options" unique="0" required="0">
<longdesc lang="en">
The options to pass to exportfs for the exported directory
or directories.
</longdesc>
<shortdesc lang="en">
Export options.
</shortdesc>
<content type="string" />
</parameter>
<parameter name="directory" unique="0" required="1">
<longdesc lang="en">
The directory or directories to be exported using NFS. Multiple
directories are separated by white space.
</longdesc>
<shortdesc lang="en">
The directory or directories to export.
</shortdesc>
<content type="string" />
</parameter>
<parameter name="fsid" unique="1" required="1">
<longdesc lang="en">
The fsid option to pass to exportfs. This can be a unique positive
integer, a UUID, or the special string "root" which is functionally
identical to numeric fsid of 0.
If multiple directories are being exported, then they are
assigned ids sequentially starting with this fsid (fsid, fsid+1,
fsid+2, ...). Obviously, in that case the fsid must be an
integer.
0 (root) identifies the export as the root of an NFSv4
pseudofilesystem -- avoid this setting unless you understand its
special status.
This value will override any fsid provided via the options parameter.
</longdesc>
<shortdesc lang="en">
Unique fsid within cluster or starting fsid for multiple exports.
</shortdesc>
<content type="string" />
</parameter>
<parameter name="unlock_on_stop">
<longdesc lang="en">
Relinquish NFS locks associated with this filesystem when the resource
stops. Enabling this parameter is highly recommended unless the path exported
by this ${__SCRIPT_NAME} resource is also exported by a different resource.
Note: Unlocking is only possible on Linux systems where
/proc/fs/nfsd/unlock_filesystem exists and is writable. If your system does
not fulfill this requirement (on account of having an nonrecent kernel,
for example), you may set this parameter to 0 to silence the associated
warning.
</longdesc>
<shortdesc lang="en">
Unlock filesystem on stop?
</shortdesc>
<content type="boolean" default="${OCF_RESKEY_unlock_on_stop_default}" />
</parameter>
<parameter name="wait_for_leasetime_on_stop">
<longdesc lang="en">
When stopping (unexporting), wait out the NFSv4 lease time.
Only after all leases have expired does the NFS kernel server
relinquish all server-side handles on the exported filesystem.
If this ${__SCRIPT_NAME} resource manages an export that resides
on a mount point designed to fail over along with the NFS export
itself, then enabling this parameter will ensure such failover
is working properly. Note that when this parameter is set, your
stop timeout MUST accommodate for the wait period. This parameter
is safe to disable if none of your NFS clients are using NFS
version 4 or later.
</longdesc>
<shortdesc lang="en">
Ride out the NFSv4 lease time on resource stop?
</shortdesc>
<content type="boolean" default="${OCF_RESKEY_wait_for_leasetime_on_stop_default}" />
</parameter>
<parameter name="rmtab_backup">
<longdesc lang="en">
Back up those entries from the NFS rmtab that apply to the exported
directory, to the specified backup file. The filename is interpreted
as relative to the exported directory. This backup is required if
clients are connecting to the export via NFSv3 over TCP. Note that a
configured monitor operation is required for this functionality.
To disable rmtab backups, set this parameter to the special
string "none".
</longdesc>
<shortdesc lang="en">
Location of the rmtab backup, relative to directory.
</shortdesc>
<content type="string" default="${OCF_RESKEY_rmtab_backup_default}" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="40" />
<action name="stop" timeout="120" />
<action name="monitor" depth="0" timeout="20" interval="10" />
<action name="meta-data" timeout="5" />
<action name="validate-all" timeout="30" />
</actions>
</resource-agent>
END
return $OCF_SUCCESS
}
exportfs_methods() {
cat <<-!
start
stop
status
monitor
validate-all
methods
meta-data
usage
!
}
reset_fsid() {
CURRENT_FSID=$OCF_RESKEY_fsid
}
bump_fsid() {
let $((CURRENT_FSID++))
}
get_fsid() {
echo $CURRENT_FSID
}
# run a function on all directories
forall() {
local func=$1
shift 1
local fast_exit=""
local dir rc=0
if [ "$2" = fast_exit ]; then
fast_exit=1
shift 1
fi
reset_fsid
for dir in $OCF_RESKEY_directory; do
$func $dir "$@"
rc=$(($rc | $?))
bump_fsid
[ "$fast_exit" ] && continue
[ $rc -ne 0 ] && return $rc
done
return $rc
}
backup_rmtab() {
local dir=$1
local rmtab_backup
rmtab_backup="$dir/${OCF_RESKEY_rmtab_backup}"
grep ":$dir:" /var/lib/nfs/rmtab > ${rmtab_backup}
}
restore_rmtab() {
local dir=$1
local rmtab_backup
rmtab_backup="$dir/${OCF_RESKEY_rmtab_backup}"
if [ -r ${rmtab_backup} ]; then
local tmpf=`mktemp`
sort -u ${rmtab_backup} /var/lib/nfs/rmtab > $tmpf &&
install -o root -m 644 $tmpf /var/lib/nfs/rmtab
rm -f $tmpf
ocf_log debug "Restored `wc -l ${rmtab_backup}` rmtab entries from ${rmtab_backup}."
else
ocf_log warn "rmtab backup ${rmtab_backup} not found or not readable."
fi
}
exportfs_usage() {
cat <<END
usage: $0 {start|stop|monitor|status|validate-all|meta-data}
END
}
format_exports() {
# exportfs output wraps lines for long export directory names.
# We unwrap here with sed.
# We then do a literal match on the full line (grep -x -F)
exportfs |
sed -e '$! N; s/\n[[:space:]]\+/ /; t; s/[[:space:]]\+\([^[:space:]]\+\)\(\n\|$\)/ \1\2/g; P;D;'
}
is_exported() {
local dir=$1
local spec=$2
local rc
format_exports | grep -q -x -F "$dir $spec"
rc=$?
if [ $rc -ne 0 -a "$spec" = "*" ]; then
# on some platforms, exportfs may print
# "<world>" instead of "*"
format_exports | grep -q -x -F "$dir <world>"
rc=$?
fi
# log something only for monitors
if [ $rc -ne 0 -a "$__OCF_ACTION" = "monitor" ]; then
local sev="info"
ocf_is_probe || sev="err"
ocf_log $sev "$dir not exported to $spec (stopped)."
fi
return $rc
}
exportfs_monitor ()
{
if forall is_exported "${OCF_RESKEY_clientspec}"; then
if [ ${OCF_RESKEY_rmtab_backup} != "none" ]; then
forall backup_rmtab
fi
return $OCF_SUCCESS
else
return $OCF_NOT_RUNNING
fi
}
export_one() {
local dir=$1
local opts sep
sep=""
if [ -n "$OCF_RESKEY_options" ]; then
opts="$OCF_RESKEY_options"
sep=","
fi
if echo "$opts" | grep fsid >/dev/null; then
#replace fsid in options list
opts=`echo "$opts" | sed "s/fsid=[0-9]\+/fsid=$(get_fsid)/g"`
else
#tack the fsid option onto our options list.
opts="${opts}${sep}fsid=$(get_fsid)"
fi
opts="-o $opts"
# if any of directories fails to export we can exit
# immediately
- ocf_run exportfs -v $opts "${OCF_RESKEY_clientspec}:$dir" ||
+ ocf_run exportfs -v $opts "${OCF_RESKEY_clientspec}:$dir"
+ if [ $? -ne 0 ]; then
+ ocf_exit_reason "exportfs failed - exportfs -v $opts ${OCF_RESKEY_clientspec}:$dir"
exit $OCF_ERR_GENERIC
+ fi
ocf_log info "directory $dir exported"
return $OCF_SUCCESS
}
exportfs_start ()
{
if exportfs_monitor; then
ocf_log debug "already exported"
return $OCF_SUCCESS
fi
ocf_log info "Exporting file system(s) ..."
forall export_one
# Restore the rmtab to ensure smooth NFS-over-TCP failover
if [ ${OCF_RESKEY_rmtab_backup} != "none" ]; then
forall restore_rmtab
fi
}
unlock_fs() {
local dir=$1
local unlockfile
unlockfile=/proc/fs/nfsd/unlock_filesystem
if [ -w ${unlockfile} ]; then
echo "$dir" > ${unlockfile}
ocf_log info "Unlocked NFS export $dir"
else
ocf_log warn "Unable to unlock NFS export $dir, ${unlockfile} not found or not writable"
fi
}
wait_for_leasetime() {
local leasetimefile
local sleeptime
leasetimefile=/proc/fs/nfsd/nfsv4leasetime
if [ -r ${leasetimefile} ]; then
sleeptime=$((`cat ${leasetimefile}`+2))
ocf_log info "Sleeping ${sleeptime} seconds to accommodate for NFSv4 lease expiry"
sleep ${sleeptime}s
else
ocf_log warn "Unable to read NFSv4 lease time from ${leasetimefile}, file not found or not readable"
fi
}
cleanup_export_cache() {
# see if the cache is blocking unexport
local contentfile=/proc/net/rpc/nfsd.export/content
local fsid_re
local i=1
fsid_re="fsid=(echo `forall get_fsid`|sed 's/ /|/g'),"
while :; do
grep -E -q "$fsid_re" $contentfile ||
break
ocf_log info "Cleanup export cache ... (try $i)"
ocf_run exportfs -f
sleep 0.5
let i=$i+1
done
}
unexport_one() {
local dir=$1
ocf_run exportfs -v -u ${OCF_RESKEY_clientspec}:$dir
}
exportfs_stop ()
{
local rc
exportfs_monitor
if [ $? -eq $OCF_NOT_RUNNING ]; then
ocf_log debug "not exported"
return $OCF_SUCCESS
fi
ocf_log info "Un-exporting file system ..."
# Backup the rmtab to ensure smooth NFS-over-TCP failover
if [ ${OCF_RESKEY_rmtab_backup} != "none" ]; then
forall backup_rmtab
fi
forall unexport_one
rc=$?
if ocf_is_true ${OCF_RESKEY_unlock_on_stop}; then
forall unlock_fs
fi
if ocf_is_true ${OCF_RESKEY_wait_for_leasetime_on_stop}; then
wait_for_leasetime
fi
if [ $rc -eq 0 ]; then
cleanup_export_cache
ocf_log info "Un-exported file system(s)"
return $OCF_SUCCESS
else
- ocf_log err "Failed to un-export file system(s)"
+ ocf_exit_reason "Failed to un-export file system(s)"
return $OCF_ERR_GENERIC
fi
}
testdir() {
if [ ! -d $1 ]; then
ocf_is_probe ||
ocf_log err "$1 does not exist or is not a directory"
return 1
fi
return 0
}
exportfs_validate_all ()
{
if [ `echo "$OCF_RESKEY_directory" | wc -w` -gt 1 ] &&
! ocf_is_decimal "$OCF_RESKEY_fsid"; then
- ocf_log err "use integer fsid when exporting multiple directories"
+ ocf_exit_reason "use integer fsid when exporting multiple directories"
return $OCF_ERR_CONFIGURED
fi
if ! forall testdir; then
return $OCF_ERR_INSTALLED
fi
}
# If someone puts a trailing slash at the end of the export directory,
# this agent is going to fail in some unexpected ways due to how
# export strings are matched. The simplest solution here is to strip off
# a trailing '/' in the directory before processing anything.
newdir=$(echo "$OCF_RESKEY_directory" | sed -n -e 's/^\(.*\)\/$/\1/p')
if [ -n "$newdir" ]; then
OCF_RESKEY_directory=$newdir
fi
OCF_REQUIRED_PARAMS="directory fsid clientspec"
OCF_REQUIRED_BINARIES="exportfs"
ocf_rarun $*
diff --git a/heartbeat/nfsnotify b/heartbeat/nfsnotify
index 2d0bbfcf4..5f72d586a 100755
--- a/heartbeat/nfsnotify
+++ b/heartbeat/nfsnotify
@@ -1,315 +1,315 @@
#!/bin/bash
#
# Copyright (c) 2014 David Vossel <dvossel@redhat.com>
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Further, this software is distributed without any warranty that it is
# free of the rightful claim of any third person regarding infringement
# or the like. Any license provided herein, whether implied or
# otherwise, applies only to this software file. Patent licenses, if
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
. ${OCF_FUNCTIONS_DIR}/ocf-directories
#######################################################################
sbindir=$HA_SBIN_DIR
if [ -z "$sbindir" ]; then
sbindir=/usr/sbin
fi
SELINUX_ENABLED=-1
NFSNOTIFY_TMP_DIR="${HA_RSCTMP}/nfsnotify_${OCF_RESOURCE_INSTANCE}/"
HA_STATD_PIDFILE="$NFSNOTIFY_TMP_DIR/rpc.statd_${OCF_RESOURCE_INSTANCE}.pid"
HA_STATD_PIDFILE_PREV="$NFSNOTIFY_TMP_DIR/rpc.statd_${OCF_RESOURCE_INSTANCE}.pid.prev"
STATD_PATH="/var/lib/nfs/statd"
SM_NOTIFY_BINARY="${sbindir}/sm-notify"
IS_RENOTIFY=0
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="nfsnotify" version="0.9">
<version>1.0</version>
<longdesc lang="en">
This agent sends NFSv3 reboot notifications to clients which informs clients to reclaim locks.
</longdesc>
<shortdesc lang="en">sm-notify reboot notifications</shortdesc>
<parameters>
<parameter name="source_host" unique="0" required="0">
<longdesc lang="en">
Comma separated list of floating IP addresses or host names that clients use
to access the nfs service. This will be used to set the source address and
mon_name of the SN_NOTIFY reboot notifications.
</longdesc>
<shortdesc lang="en">source IP addresses</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="notify_args" unique="0" required="0">
<longdesc lang="en">
Additional arguments to send to the sm-notify command. By default
this agent will always set sm-notify's '-f' option. When the
source_host option is set, the '-v' option will be used automatically
to set the proper source address. Any additional sm-notify arguments
set with this option will be used in addition to the previous default
arguments.
</longdesc>
<shortdesc lang="en">sm-notify arguments</shortdesc>
<content type="string" default="false" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="90" />
<action name="stop" timeout="90" />
<action name="monitor" timeout="90" interval="30" depth="0" />
<action name="reload" timeout="90" />
<action name="meta-data" timeout="10" />
<action name="validate-all" timeout="20" />
</actions>
</resource-agent>
END
}
v3notify_usage()
{
cat <<END
usage: $0 {start|stop|monitor|validate-all|meta-data}
Expects to have a fully populated OCF RA-compliant environment set.
END
}
v3notify_validate()
{
# check_binary will exit with OCF_ERR_INSTALLED when binary is missing
check_binary "$SM_NOTIFY_BINARY"
check_binary "pgrep"
check_binary "killall"
return $OCF_SUCCESS
}
killall_smnotify()
{
# killall sm-notify
killall -TERM $SM_NOTIFY_BINARY > /dev/null 2>&1
if [ $? -eq 0 ]; then
# it is useful to know if sm-notify processes were actually left around
# or not during the stop/start operation. Whether this condition is true
# or false does not indicate a failure. It does indicate that
# there are probably some unresponsive nfs clients out there that are keeping
# the sm-notify processes retrying.
ocf_log info "previous sm-notify processes terminated before $__OCF_ACTION action."
fi
}
v3notify_stop()
{
killall_smnotify
rm -f $HA_STATD_PIDFILE_PREV > /dev/null 2>&1
mv $HA_STATD_PIDFILE $HA_STATD_PIDFILE_PREV > /dev/null 2>&1
return $OCF_SUCCESS
}
check_statd_pidfile()
{
local binary="rpc.statd"
local pidfile="$HA_STATD_PIDFILE"
ocf_log debug "Checking status for ${binary}."
if [ -e "$pidfile" ]; then
cat /proc/$(cat $pidfile)/cmdline 2>/dev/null | grep -a "${binary}" > /dev/null 2>&1
if [ $? -eq 0 ]; then
return $OCF_SUCCESS
fi
- ocf_log err "$(cat $pidfile) for $binary is no longer running, sm-notify needs to re-notify clients"
+ ocf_exit_reason "$(cat $pidfile) for $binary is no longer running, sm-notify needs to re-notify clients"
return $OCF_ERR_GENERIC
fi
# if we don't have a pid file for rpc.statd, we have not yet sent the notifications
return $OCF_NOT_RUNNING
}
write_statd_pid()
{
local binary="rpc.statd"
local pidfile="$HA_STATD_PIDFILE"
local pid
pid=$(pgrep ${binary})
case $? in
0)
ocf_log info "PID file (pid:${pid} at $pidfile) created for ${binary}."
mkdir -p $(dirname $pidfile)
echo "$pid" > $pidfile
return $OCF_SUCCESS;;
1)
rm -f "$pidfile" > /dev/null 2>&1
ocf_log info "$binary is not running"
return $OCF_NOT_RUNNING;;
*)
rm -f "$pidfile" > /dev/null 2>&1
- ocf_log err "Error encountered detecting pid status of $binary"
+ ocf_exit_reason "Error encountered detecting pid status of $binary"
return $OCF_ERR_GENERIC;;
esac
}
copy_statd()
{
local src=$1
local dest=$2
if ! [ -d "$dest" ]; then
mkdir -p "$dest"
fi
cp -rpfn $src/sm $src/sm.bak $src/state $dest > /dev/null 2>&1
# make sure folder ownership and selinux lables stay consistent
[ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown rpcuser.rpcuser "$dest"
[ $SELINUX_ENABLED -eq 0 ] && chcon -R "$SELINUX_LABEL" "$dest"
}
v3notify_start()
{
local rc=$OCF_SUCCESS
local cur_statd
local statd_backup
local is_renotify=0
# monitor, see if we need to notify or not
v3notify_monitor
if [ $? -eq 0 ]; then
return $OCF_SUCCESS
fi
# kill off any other sm-notify processes that might already be running.
killall_smnotify
# record the pid of rpc.statd. if this pid ever changes, we have to re-notify
write_statd_pid
rc=$?
if [ $rc -ne 0 ]; then
return $rc
fi
# if the last time we ran nfs-notify, it was with the same statd process,
# consider this a re-notification. During re-notifications we do not let the
# sm-notify binary have access to the real statd directory.
if [ "$(cat $HA_STATD_PIDFILE)" = "$(cat $HA_STATD_PIDFILE_PREV 2>/dev/null)" ]; then
ocf_log info "Renotifying clients"
is_renotify=1
fi
statd_backup="$STATD_PATH/nfsnotify.bu"
copy_statd "$STATD_PATH" "$statd_backup"
if [ -z "$OCF_RESKEY_source_host" ]; then
if [ "$is_renotify" -eq 0 ]; then
cur_statd="$STATD_PATH"
else
cur_statd="$statd_backup"
fi
ocf_log info "sending notifications on default source address."
$SM_NOTIFY_BINARY -f $OCF_RESKEY_notify_args -P $cur_statd
if [ $? -ne 0 ]; then
- ocf_log err "sm-notify failed, view syslog for more information."
+ ocf_exit_reason "sm-notify execution failed, view syslog for more information"
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
fi
# do sm-notify for each ip
for ip in `echo ${OCF_RESKEY_source_host} | sed 's/,/ /g'`; do
# have the first sm-notify use the actual statd directory so the
# notify list can be managed properly.
if [ "$is_renotify" -eq 0 ]; then
cur_statd="$STATD_PATH"
# everything after the first notify we are considering a renotification
# which means we don't use the real statd directory.
is_renotify=1
else
# use our copied statd directory for the remaining ip addresses
cur_statd="$STATD_PATH/nfsnotify_${OCF_RESOURCE_INSTANCE}_${ip}"
copy_statd "$statd_backup" "$cur_statd"
fi
ocf_log info "sending notifications with source address $ip"
$SM_NOTIFY_BINARY -f $OCF_RESKEY_notify_args -v $ip -P "$cur_statd"
if [ $? -ne 0 ]; then
- ocf_log err "sm-notify with source host set to, $ip, failed. view syslog for more information"
+ ocf_exit_reason "sm-notify with source host set to [ $ip ] failed. view syslog for more information"
return $OCF_ERR_GENERIC
fi
done
return $OCF_SUCCESS
}
v3notify_monitor()
{
# verify rpc.statd is up, and that the rpc.statd pid is the same one we
# found during the start. otherwise rpc.statd recovered and we need to notify
# again.
check_statd_pidfile
}
case $__OCF_ACTION in
meta-data) meta_data
exit $OCF_SUCCESS;;
usage|help) v3notify_usage
exit $OCF_SUCCESS;;
*)
;;
esac
which restorecon > /dev/null 2>&1 && selinuxenabled
SELINUX_ENABLED=$?
if [ $SELINUX_ENABLED -eq 0 ]; then
export SELINUX_LABEL="$(ls -ldZ $STATD_PATH | cut -f4 -d' ')"
fi
case $__OCF_ACTION in
start) v3notify_start;;
stop) v3notify_stop;;
monitor) v3notify_monitor;;
validate-all) v3notify_validate;;
*) v3notify_usage
exit $OCF_ERR_UNIMPLEMENTED;;
esac
rc=$?
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
exit $rc
diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver
index e44da1c68..232bd39f6 100755
--- a/heartbeat/nfsserver
+++ b/heartbeat/nfsserver
@@ -1,784 +1,784 @@
#!/bin/sh
# nfsserver
#
# Description: Manages nfs server as OCF resource
# by hxinwei@gmail.com
# License: GNU General Public License v2 (GPLv2) and later
if [ -n "$OCF_DEBUG_LIBRARY" ]; then
. $OCF_DEBUG_LIBRARY
else
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
fi
DEFAULT_INIT_SCRIPT="/etc/init.d/nfsserver"
if ! [ -f $DEFAULT_INIT_SCRIPT ]; then
# On some systems, the script is just called nfs
DEFAULT_INIT_SCRIPT="/etc/init.d/nfs"
fi
DEFAULT_NOTIFY_CMD=`which sm-notify`
DEFAULT_NOTIFY_CMD=${DEFAULT_NOTIFY_CMD:-"/sbin/sm-notify"}
DEFAULT_NOTIFY_FOREGROUND="false"
DEFAULT_RPCPIPEFS_DIR="/var/lib/nfs/rpc_pipefs"
EXEC_MODE=0
SELINUX_ENABLED=-1
STATD_PATH="/var/lib/nfs"
STATD_DIR=""
NFS_SYSCONFIG="/etc/sysconfig/nfs"
NFS_SYSCONFIG_LOCAL_BACKUP="/etc/sysconfig/nfs.ha.bu"
NFS_SYSCONFIG_AUTOGEN_TAG="AUTOGENERATED by $0 high availability resource-agent"
nfsserver_meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="nfsserver">
<version>1.0</version>
<longdesc lang="en">
Nfsserver helps to manage the Linux nfs server as a failover-able resource in Linux-HA.
It depends on Linux specific NFS implementation details, so is considered not portable to other platforms yet.
</longdesc>
<shortdesc lang="en">Manages an NFS server</shortdesc>
<parameters>
<parameter name="nfs_init_script" unique="0" required="0">
<longdesc lang="en">
The default init script shipped with the Linux distro.
The nfsserver resource agent offloads the start/stop/monitor
work to the init script because the procedure to start/stop/monitor
nfsserver varies on different Linux distro. In the event that this
option is not set, this agent will attempt to use an init script at
this location, ${DEFAULT_INIT_SCRIPT}, or detect a systemd unit-file
to use in the event that no init script is detected.
</longdesc>
<shortdesc lang="en">
Init script for nfsserver
</shortdesc>
<content type="string" default="auto detected" />
</parameter>
<parameter name="nfs_no_notify" unique="0" required="0">
<longdesc lang="en">
Do not send reboot notifications to NFSv3 clients during server startup.
</longdesc>
<shortdesc lang="en">
Disable NFSv3 server reboot notifications
</shortdesc>
<content type="boolean" default="false" />
</parameter>
<parameter name="nfs_notify_foreground" unique="0" required="0">
<longdesc lang="en">
Keeps the sm-notify attached to its controlling terminal and running in the foreground.
</longdesc>
<shortdesc lang="en">
Keeps the notify tool running in the foreground.
</shortdesc>
<content type="boolean" default="$DEFAULT_NOTIFY_FOREGROUND" />
</parameter>
<parameter name="nfs_smnotify_retry_time" unique="0" required="0">
<longdesc lang="en">
Specifies the length of sm-notify retry time, in minutes, to continue retrying notifications to unresponsive hosts.
If this option is not specified, sm-notify attempts to send notifications for 15 minutes. Specifying a value of 0
causes sm-notify to continue sending notifications to unresponsive peers until it is manually killed.
</longdesc>
<shortdesc lang="en">
Specifies the length of sm-notify retry time (minutes).
</shortdesc>
<content type="integer" default="" />
</parameter>
<parameter name="nfs_ip" unique="0" required="0">
<longdesc lang="en">
Comma separated list of floating IP addresses used to access the nfs service
</longdesc>
<shortdesc lang="en">
IP addresses.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="nfsd_args" unique="0" required="0">
<longdesc lang="en">
Specifies what arguments to pass to the nfs daemon on startup. View the rpc.nfsd man page for information on what arguments are available.
Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file.
</longdesc>
<shortdesc lang="en">
rpc.nfsd options
</shortdesc>
<content type="string" />
</parameter>
<parameter name="lockd_udp_port" unique="0" required="0">
<longdesc lang="en">
The udp port lockd should listen on.
Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file.
</longdesc>
<shortdesc lang="en">
lockd udp port
</shortdesc>
<content type="integer" />
</parameter>
<parameter name="lockd_tcp_port" unique="0" required="0">
<longdesc lang="en">
The tcp port lockd should listen on.
Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file.
</longdesc>
<shortdesc lang="en">
lockd tcp port
</shortdesc>
<content type="integer" />
</parameter>
<parameter name="statd_outgoing_port" unique="0" required="0">
<longdesc lang="en">
The source port number sm-notify uses when sending reboot notifications.
Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file.
</longdesc>
<shortdesc lang="en">
sm-notify source port
</shortdesc>
<content type="integer" />
</parameter>
<parameter name="statd_port" unique="0" required="0">
<longdesc lang="en">
The port number used for RPC listener sockets.
Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file.
</longdesc>
<shortdesc lang="en">
rpc.statd listener port
</shortdesc>
<content type="integer" />
</parameter>
<parameter name="mountd_port" unique="0" required="0">
<longdesc lang="en">
The port number used for rpc.mountd listener sockets.
Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file.
</longdesc>
<shortdesc lang="en">
rpc.mountd listener port
</shortdesc>
<content type="integer" />
</parameter>
<parameter name="rquotad_port" unique="0" required="0">
<longdesc lang="en">
The port number used for rpc.rquotad.
Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file.
</longdesc>
<shortdesc lang="en">
rpc.rquotad port
</shortdesc>
<content type="integer" />
</parameter>
<parameter name="nfs_shared_infodir" unique="0" required="0">
<longdesc lang="en">
The nfsserver resource agent will save nfs related information in this specific directory.
And this directory must be able to fail-over before nfsserver itself.
</longdesc>
<shortdesc lang="en">
Directory to store nfs server related information.
</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="rpcpipefs_dir" unique="0" required="0">
<longdesc lang="en">
The mount point for the sunrpc file system. Default is $DEFAULT_RPCPIPEFS_DIR.
This script will mount (bind) nfs_shared_infodir on /var/lib/nfs/ (cannot be changed),
and this script will mount the sunrpc file system on $DEFAULT_RPCPIPEFS_DIR (default, can be changed by this parameter).
If you want to move only rpc_pipefs/ (e.g. to keep rpc_pipefs/ local) from default, please set this value.
</longdesc>
<shortdesc lang="en">
The mount point for the sunrpc file system.
</shortdesc>
<content type="string" default="$DEFAULT_RPCPIPEFS_DIR" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="40" />
<action name="stop" timeout="20s" />
<action name="monitor" depth="0" timeout="20s" interval="10" />
<action name="meta-data" timeout="5" />
<action name="validate-all" timeout="30" />
</actions>
</resource-agent>
END
return $OCF_SUCCESS
}
nfsserver_usage() {
cat <<END
usage: $0 {start|stop|monitor|status|validate-all|meta-data}
END
}
if [ $# -ne 1 ]; then
nfsserver_usage
exit $OCF_ERR_ARGS
fi
case $__OCF_ACTION in
meta-data) nfsserver_meta_data
exit $OCF_SUCCESS
;;
usage|help) nfsserver_usage
exit $OCF_SUCCESS
;;
*)
;;
esac
fp="$OCF_RESKEY_nfs_shared_infodir"
: ${OCF_RESKEY_nfs_notify_cmd="$DEFAULT_NOTIFY_CMD"}
: ${OCF_RESKEY_nfs_notify_foreground="$DEFAULT_NOTIFY_FOREGROUND"}
if [ -z ${OCF_RESKEY_rpcpipefs_dir} ]; then
rpcpipefs_make_dir=$fp/rpc_pipefs
rpcpipefs_umount_dir=${DEFAULT_RPCPIPEFS_DIR}
else
rpcpipefs_make_dir=${OCF_RESKEY_rpcpipefs_dir}
rpcpipefs_umount_dir=${OCF_RESKEY_rpcpipefs_dir}
fi
# Use statd folder if it exists
if [ -d "/var/lib/nfs/statd" ]; then
STATD_DIR="statd"
STATD_PATH="/var/lib/nfs/statd"
fi
# SELinux information. We are taking the permissions from
# the current statd dir and applying it to the HA one that is
# being mounted in its place.
which restorecon > /dev/null 2>&1 && selinuxenabled
SELINUX_ENABLED=$?
if [ $SELINUX_ENABLED -eq 0 ]; then
export SELINUX_LABEL="$(ls -ldZ $STATD_PATH | cut -f4 -d' ')"
fi
##
# EXEC_MODE values
# 1 user init script or default init script
# 2 systemd
#
# On error, this function will terminate the process
# with error code $OCF_ERR_INSTALLED
##
set_exec_mode()
{
##
# If EXEC_MODE is already set, we don't need to run this function again.
##
if [ $EXEC_MODE -ne 0 ]; then
return 0;
fi
##
# If the user defined an init script, It must exist for us to continue
##
if [ -n "$OCF_RESKEY_nfs_init_script" ]; then
# check_binary will exit the process if init script does not exist
check_binary ${OCF_RESKEY_nfs_init_script}
EXEC_MODE=1
return 0
fi
##
# Check to see if the default init script exists, if so we'll use that.
##
if which $DEFAULT_INIT_SCRIPT > /dev/null 2>&1; then
OCF_RESKEY_nfs_init_script=$DEFAULT_INIT_SCRIPT
EXEC_MODE=1
return 0
fi
##
# Last of all, attempt systemd.
##
if which systemctl > /dev/null 2>&1; then
if systemctl list-unit-files | grep nfs-server > /dev/null && systemctl list-unit-files | grep nfs-lock > /dev/null; then
EXEC_MODE=2
# when using systemd, the nfs-lock service file handles nfsv3 locking daemons for us.
return 0
fi
fi
- ocf_log err "No init script or systemd unit file detected for nfs server"
+ ocf_exit_reason "No init script or systemd unit file detected for nfs server"
exit $OCF_ERR_INSTALLED
}
##
# wrapper for init script and systemd calls.
##
nfs_exec()
{
local cmd=$1
set_exec_mode
case $EXEC_MODE in
1) ${OCF_RESKEY_nfs_init_script} $cmd;;
2) systemctl $cmd nfs-server.service ;;
esac
}
v3locking_exec()
{
local cmd=$1
set_exec_mode
if [ $EXEC_MODE -eq 2 ]; then
systemctl $cmd nfs-lock.service
else
case $cmd in
start) locking_start;;
stop) locking_stop;;
status) locking_status;;
esac
fi
}
nfsserver_monitor ()
{
fn=`mktemp`
nfs_exec status > $fn 2>&1
rc=$?
ocf_log debug "$(cat $fn)"
rm -f $fn
#Adapte LSB status code to OCF return code
if [ $rc -eq 0 ]; then
# don't report success if nfs servers are up
# without locking daemons.
v3locking_exec "status"
rc=$?
if [ $rc -ne 0 ]; then
- ocf_log error "NFS server is up, but the locking daemons are down"
+ ocf_exit_reason "NFS server is up, but the locking daemons are down"
rc=$OCF_ERR_GENERIC
fi
return $rc
elif [ $rc -eq 3 ]; then
return $OCF_NOT_RUNNING
else
return $OCF_ERR_GENERIC
fi
}
set_arg()
{
local key="$1"
local value="$2"
local file="$3"
local requires_sysconfig="$4"
if [ -z "$value" ]; then
return
fi
# only write to the tmp /etc/sysconfig/nfs if sysconfig exists.
# otherwise this distro does not support setting these options.
if [ -d "/etc/sysconfig" ]; then
echo "${key}=\"${value}\"" >> $file
elif [ "$requires_sysconfig" = "true" ]; then
ocf_log warn "/etc/sysconfig/nfs not found, unable to set port and nfsd args."
fi
export ${key}="${value}"
}
set_env_args()
{
local tmpconfig=$(mktemp ${HA_RSCTMP}/nfsserver-tmp-XXXXX)
local statd_args
# nfsd args
set_arg "RPCNFSDARGS" "$OCF_RESKEY_nfsd_args" "$tmpconfig" "true"
# mountd args
if [ -n "$OCF_RESKEY_mountd_port" ]; then
set_arg "RPCMOUNTDOPTS" "-p $OCF_RESKEY_mountd_port" "$tmpconfig" "true"
fi
# statd args. we always want to perform the notify using sm-notify after
# both rpc.statd and the nfsd daemons are initialized
statd_args="--no-notify"
if [ -n "$OCF_RESKEY_statd_outgoing_port" ]; then
statd_args="$statd_args -o $OCF_RESKEY_statd_outgoing_port"
fi
if [ -n "$OCF_RESKEY_statd_port" ]; then
statd_args="$statd_args -p $OCF_RESKEY_statd_port"
fi
set_arg "STATDARG" "$statd_args" "$tmpconfig" "false"
# lockd ports
set_arg "LOCKD_UDPPORT" "$OCF_RESKEY_lockd_udp_port" "$tmpconfig" "true"
set_arg "LOCKD_TCPPORT" "$OCF_RESKEY_lockd_tcp_port" "$tmpconfig" "true"
# rquotad_port
set_arg "RPCRQUOTADOPTS" "-p $OCF_RESKEY_rquotad_port" "$tmpconfig" "true"
# override local nfs config. preserve previous local config though.
if [ -s $tmpconfig ]; then
cat $NFS_SYSCONFIG | grep -e "$NFS_SYSCONFIG_AUTOGEN_TAG"
if [ $? -ne 0 ]; then
# backup local nfs config if it doesn't have our HA autogen tag in it.
mv -f $NFS_SYSCONFIG $NFS_SYSCONFIG_LOCAL_BACKUP
fi
echo "# $NFS_SYSCONFIG_AUTOGEN_TAG" > $NFS_SYSCONFIG
echo "# local config backup stored here, '$NFS_SYSCONFIG_LOCAL_BACKUP'" >> $NFS_SYSCONFIG
cat $tmpconfig >> $NFS_SYSCONFIG
fi
rm -f $tmpconfig
}
prepare_directory ()
{
if [ -z "$fp" ]; then
return
fi
[ -d "$fp" ] || mkdir -p $fp
[ -d "$rpcpipefs_make_dir" ] || mkdir -p $rpcpipefs_make_dir
[ -d "$fp/v4recovery" ] || mkdir -p $fp/v4recovery
[ -d "$fp/$STATD_DIR" ] || mkdir -p "$fp/$STATD_DIR"
[ -d "$fp/$STATD_DIR/sm" ] || mkdir -p "$fp/$STATD_DIR/sm"
[ -d "$fp/$STATD_DIR/sm.ha" ] || mkdir -p "$fp/$STATD_DIR/sm.ha"
[ -d "$fp/$STATD_DIR/sm.bak" ] || mkdir -p "$fp/$STATD_DIR/sm.bak"
[ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown -R rpcuser.rpcuser "$fp/$STATD_DIR"
[ -f "$fp/etab" ] || touch "$fp/etab"
[ -f "$fp/xtab" ] || touch "$fp/xtab"
[ -f "$fp/rmtab" ] || touch "$fp/rmtab"
dd if=/dev/urandom of=$fp/$STATD_DIR/state bs=1 count=4 &> /dev/null
[ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown rpcuser.rpcuser "$fp/$STATD_DIR/state"
[ $SELINUX_ENABLED -eq 0 ] && chcon -R "$SELINUX_LABEL" "$fp"
}
is_bound ()
{
if mount | grep -q "on $1 type"; then
return 0
fi
return 1
}
bind_tree ()
{
if [ -z "$fp" ]; then
return
fi
if is_bound /var/lib/nfs; then
ocf_log debug "$fp is already bound to /var/lib/nfs"
return 0
fi
mount --bind $fp /var/lib/nfs
[ $SELINUX_ENABLED -eq 0 ] && restorecon /var/lib/nfs
}
unbind_tree ()
{
if `mount | grep -q " on $rpcpipefs_umount_dir"`; then
umount -t rpc_pipefs $rpcpipefs_umount_dir
fi
if is_bound /var/lib/nfs; then
umount /var/lib/nfs
fi
}
binary_status()
{
local binary=$1
local pid
pid=$(pgrep ${binary})
case $? in
0)
echo "$pid"
return $OCF_SUCCESS;;
1)
return $OCF_NOT_RUNNING;;
*)
return $OCF_ERR_GENERIC;;
esac
}
locking_status()
{
binary_status "rpc.statd" > /dev/null 2>&1
}
locking_start()
{
local ret=$OCF_SUCCESS
ocf_log info "Starting rpc.statd."
rpc.statd $STATDARG
ret=$?
if [ $ret -ne 0 ]; then
ocf_log err "Failed to start rpc.statd"
return $ret
fi
touch /var/lock/subsys/nfslock
return $ret
}
terminate()
{
declare pids
declare i=0
while : ; do
pids=$(binary_status $1)
[ -z "$pids" ] && return 0
kill $pids
sleep 1
((i++))
[ $i -gt 3 ] && return 1
done
}
killkill()
{
declare pids
declare i=0
while : ; do
pids=$(binary_status $1)
[ -z "$pids" ] && return 0
kill -9 $pids
sleep 1
((i++))
[ $i -gt 3 ] && return 1
done
}
stop_process()
{
declare process=$1
ocf_log info "Stopping $process"
if terminate $process; then
ocf_log debug "$process is stopped"
else
if killkill $process; then
ocf_log debug "$process is stopped"
else
ocf_log debug "Failed to stop $process"
return 1
fi
fi
return 0
}
locking_stop()
{
ret=0
# sm-notify can prevent umount of /var/lib/nfs/statd if
# it is still trying to notify unresponsive clients.
stop_process sm-notify
if [ $? -ne 0 ]; then
ret=$OCF_ERR_GENERIC
fi
stop_process rpc.statd
if [ $? -ne 0 ]; then
ret=$OCF_ERR_GENERIC
fi
return $ret
}
notify_locks()
{
if ocf_is_true "$OCF_RESKEY_nfs_no_notify"; then
# we've been asked not to notify clients
return;
fi
# run in foreground, if requested
if ocf_is_true "$OCF_RESKEY_nfs_notify_foreground"; then
opts="-d"
fi
if [ -n "$OCF_RESKEY_nfs_smnotify_retry_time" ]; then
opts="$opts -m $OCF_RESKEY_nfs_smnotify_retry_time"
fi
if [ -n "$OCF_RESKEY_statd_outgoing_port" ]; then
opts="$opts -p $OCF_RESKEY_statd_outgoing_port"
fi
# forces re-notificaiton regardless if notifies have already gone out
opts="$opts -f"
ocf_log info "executing sm-notify"
if [ -n "$OCF_RESKEY_nfs_ip" ]; then
for ip in `echo ${OCF_RESKEY_nfs_ip} | sed 's/,/ /g'`; do
cp -rpfn $STATD_PATH/sm.ha/* $STATD_PATH/ > /dev/null 2>&1
sm-notify $opts -v $ip
done
else
sm-notify $opts
fi
}
nfsserver_start ()
{
local rc;
if nfsserver_monitor; then
ocf_log debug "NFS server is already started"
return $OCF_SUCCESS
fi
set_env_args
prepare_directory
bind_tree
# remove the sm-notify pid so sm-notify will be allowed to run again without requiring a reboot.
rm -f /var/run/sm-notify.pid
#
# Synchronize these before starting statd
#
cp -rpfn $STATD_PATH/sm.ha/* $STATD_PATH/ > /dev/null 2>&1
rm -rf $STATD_PATH/sm.ha/* > /dev/null 2>&1
cp -rpf $STATD_PATH/sm $STATD_PATH/sm.bak /var/lib/nfs/state $STATD_PATH/sm.ha > /dev/null 2>&1
ocf_log info "Starting NFS server ..."
# mounts /proc/fs/nfsd for us
lsmod | grep -q nfsd
if [ $? -ne 0 ]; then
modprobe nfsd
fi
# check to see if we need to start rpc.statd
v3locking_exec "status"
if [ $? -ne $OCF_SUCCESS ]; then
v3locking_exec "start"
rc=$?
if [ $rc -ne 0 ]; then
- ocf_log error "Failed to start NFS server locking daemons"
+ ocf_exit_reason "Failed to start NFS server locking daemons"
return $rc
fi
else
ocf_log info "rpc.statd already up"
fi
fn=`mktemp`
nfs_exec start > $fn 2>&1
rc=$?
ocf_log debug "$(cat $fn)"
rm -f $fn
if [ $rc -ne 0 ]; then
- ocf_log err "Failed to start NFS server"
+ ocf_exit_reason "Failed to start NFS server"
return $rc
fi
notify_locks
ocf_log info "NFS server started"
return $OCF_SUCCESS
}
nfsserver_stop ()
{
ocf_log info "Stopping NFS server ..."
# backup the current sm state information to the ha folder before stopping.
# the ha folder will be synced after startup, restoring the statd client state
rm -rf $STATD_PATH/sm.ha/* > /dev/null 2>&1
cp -rpf $STATD_PATH/sm $STATD_PATH/sm.bak /var/lib/nfs/state $STATD_PATH/sm.ha > /dev/null 2>&1
fn=`mktemp`
nfs_exec stop > $fn 2>&1
rc=$?
ocf_log debug "$(cat $fn)"
rm -f $fn
v3locking_exec "stop"
if [ $? -ne 0 ]; then
- ocf_log err "Failed to stop NFS locking daemons"
+ ocf_exit_reason "Failed to stop NFS locking daemons"
rc=$OCF_ERR_GENERIC
fi
if [ $rc -eq 0 ]; then
unbind_tree
ocf_log info "NFS server stopped"
- return $OCF_SUCCESS
+ else
+ ocf_exit_reason "Failed to stop NFS server"
fi
- ocf_log err "Failed to stop NFS server"
return $rc
}
nfsserver_validate ()
{
##
# set_exec_mode will exit if nfs server is not installed
##
set_exec_mode
check_binary ${OCF_RESKEY_nfs_notify_cmd}
if [ -n "$OCF_RESKEY_CRM_meta_clone" ] && [ -n "$OCF_RESKEY_nfs_shared_infodir" ]; then
- ocf_log err "This RA does not support clone mode when a shared info directory is in use."
+ ocf_exit_reason "This RA does not support clone mode when a shared info directory is in use."
exit $OCF_ERR_CONFIGURED
fi
if [ -n "$OCF_RESKEY_nfs_smnotify_retry_time" ]; then
if ! ocf_is_decimal "$OCF_RESKEY_nfs_smnotify_retry_time"; then
- ocf_log err "Invalid nfs_smnotify_retry_time [$OCF_RESKEY_nfs_smnotify_retry_time]"
+ ocf_exit_reason "Invalid nfs_smnotify_retry_time [$OCF_RESKEY_nfs_smnotify_retry_time]"
exit $OCF_ERR_CONFIGURED
fi
fi
case ${OCF_RESKEY_nfs_notify_cmd##*/} in
sm-notify|rpc.statd) ;;
*)
- ocf_log err "Invalid nfs_notify_cmd [$OCF_RESKEY_nfs_notify_cmd]"
+ ocf_exit_reason "Invalid nfs_notify_cmd [$OCF_RESKEY_nfs_notify_cmd]"
exit $OCF_ERR_CONFIGURED
;;
esac
return $OCF_SUCCESS
}
nfsserver_validate
case $__OCF_ACTION in
start) nfsserver_start
;;
stop) nfsserver_stop
;;
monitor) nfsserver_monitor
;;
validate-all) exit $OCF_SUCCESS
;;
*) nfsserver_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/heartbeat/ocf-binaries.in b/heartbeat/ocf-binaries.in
index a78a34826..cbf70dbd7 100644
--- a/heartbeat/ocf-binaries.in
+++ b/heartbeat/ocf-binaries.in
@@ -1,74 +1,74 @@
# Make sure PATH contains all the usual suspects
PATH="$PATH:/sbin:/bin:/usr/sbin:/usr/bin"
# Include /usr/ucb for finding whoami on Solaris
PATH="$PATH:/usr/ucb"
export PATH
# Binaries and binary options for use in Resource Agents
: ${AWK:=@AWK@}
: ${EGREP:="@EGREP@"}
: ${IFCONFIG_A_OPT:="@IFCONFIG_A_OPT@"}
: ${MAILCMD:=@MAILCMD@}
: ${PING:=@PING@}
: ${SH:=@SHELL@}
: ${TEST:=@TEST@}
: ${TESTPROG:=@TEST@}
# Entries that should probably be removed
: ${BASENAME:=basename}
: ${BLOCKDEV:=blockdev}
: ${CAT:=cat}
: ${FSCK:=fsck}
: ${FUSER:=fuser}
: ${GETENT:=getent}
: ${GREP:=grep}
: ${IFCONFIG:=ifconfig}
: ${IPTABLES:=iptables}
: ${IP2UTIL:=ip}
: ${MDADM:=mdadm}
: ${MODPROBE:=modprobe}
: ${MOUNT:=mount}
: ${MSGFMT:=msgfmt}
: ${NETSTAT:=netstat}
: ${PERL:=perl}
: ${PYTHON:=python}
: ${RAIDSTART:=raidstart}
: ${RAIDSTOP:=raidstop}
: ${ROUTE:=route}
: ${UMOUNT:=umount}
: ${REBOOT:=reboot}
: ${POWEROFF_CMD:=poweroff}
: ${WGET:=wget}
: ${WHOAMI:=whoami}
: ${STRINGSCMD:=strings}
: ${SCP:=scp}
: ${SSH:=ssh}
: ${SWIG:=swig}
: ${GZIP_PROG:=gzip}
: ${TAR:=tar}
: ${MD5:=md5}
: ${DRBDADM:=drbdadm}
: ${DRBDSETUP:=drbdsetup}
check_binary () {
if ! have_binary "$1"; then
if [ "$OCF_NOT_RUNNING" = 7 ]; then
# Chances are we have a fully setup OCF environment
- ocf_log err "Setup problem: couldn't find command: $1"
+ ocf_exit_reason "Setup problem: couldn't find command: $1"
else
echo "Setup problem: couldn't find command: $1"
fi
exit $OCF_ERR_INSTALLED
fi
}
have_binary () {
if [ "$OCF_TESTER_FAIL_HAVE_BINARY" = "1" ]; then
false
else
local bin=`echo $1 | sed -e 's/ -.*//'`
test -x "`which $bin 2>/dev/null`"
fi
}
diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in
index 12c889992..e24028a3e 100644
--- a/heartbeat/ocf-shellfuncs.in
+++ b/heartbeat/ocf-shellfuncs.in
@@ -1,804 +1,823 @@
#
#
# Common helper functions for the OCF Resource Agents supplied by
# heartbeat.
#
# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Brテゥe
# All Rights Reserved.
#
#
# This library 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.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Build version: $Format:%H$
# TODO: Some of this should probably split out into a generic OCF
# library for shell scripts, but for the time being, we'll just use it
# ourselves...
#
# TODO wish-list:
# - Generic function for evaluating version numbers
# - Generic function(s) to extract stuff from our own meta-data
# - Logging function which automatically adds resource identifier etc
# prefixes
# TODO: Move more common functionality for OCF RAs here.
#
# This was common throughout all legacy Heartbeat agents
unset LC_ALL; export LC_ALL
unset LANGUAGE; export LANGUAGE
__SCRIPT_NAME=`basename $0`
+# This is internal to shellfuncs.
+# When set, ha_log can be used in a way that guarantees
+# that stderr will not be printed to. This allows us to
+# use ocf_exit_reason to print a string to stderr and use
+# ha_log to print the same string to the other log facilities
+# without having duplicate messages sent to stderr.
+__ha_log_ignore_stderr_once=""
+
if [ -z "$OCF_ROOT" ]; then
: ${OCF_ROOT=@OCF_ROOT_DIR@}
fi
if [ "$OCF_FUNCTIONS_DIR" = ${OCF_ROOT}/resource.d/heartbeat ]; then # old
unset OCF_FUNCTIONS_DIR
fi
: ${OCF_FUNCTIONS_DIR:=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-binaries
. ${OCF_FUNCTIONS_DIR}/ocf-returncodes
. ${OCF_FUNCTIONS_DIR}/ocf-directories
. ${OCF_FUNCTIONS_DIR}/ocf-rarun
# Define OCF_RESKEY_CRM_meta_interval in case it isn't already set,
# to make sure that ocf_is_probe() always works
: ${OCF_RESKEY_CRM_meta_interval=0}
ocf_is_root() {
if [ X`id -u` = X0 ]; then
true
else
false
fi
}
ocf_maybe_random() {
local rnd="$RANDOM"
# Something sane-ish in case a shell doesn't support $RANDOM
[ -n "$rnd" ] || rnd=$$
echo $rnd
}
# Portability comments:
# o The following rely on Bourne "sh" pattern-matching, which is usually
# that for filename generation (note: not regexp).
# o The "*) true ;;" clause is probably unnecessary, but is included
# here for completeness.
# o The negation in the pattern uses "!". This seems to be common
# across many OSes (whereas the alternative "^" fails on some).
# o If an OS is encountered where this negation fails, then a possible
# alternative would be to replace the function contents by (e.g.):
# [ -z "`echo $1 | tr -d '[0-9]'`" ]
#
ocf_is_decimal() {
case "$1" in
""|*[!0-9]*) # empty, or at least one non-decimal
false ;;
*)
true ;;
esac
}
ocf_is_true() {
case "$1" in
yes|true|1|YES|TRUE|ja|on|ON) true ;;
*) false ;;
esac
}
ocf_is_hex() {
case "$1" in
""|*[!0-9a-fA-F]*) # empty, or at least one non-hex
false ;;
*)
true ;;
esac
}
ocf_is_octal() {
case "$1" in
""|*[!0-7]*) # empty, or at least one non-octal
false ;;
*)
true ;;
esac
}
__ocf_set_defaults() {
__OCF_ACTION="$1"
# Return to sanity for the agents...
unset LANG
LC_ALL=C
export LC_ALL
# TODO: Review whether we really should source this. Or rewrite
# to match some emerging helper function syntax...? This imports
# things which no OCF RA should be using...
# Strip the OCF_RESKEY_ prefix from this particular parameter
if [ -z "$OCF_RESKEY_OCF_CHECK_LEVEL" ]; then
: ${OCF_CHECK_LEVEL:=0}
else
: ${OCF_CHECK_LEVEL:=$OCF_RESKEY_OCF_CHECK_LEVEL}
fi
if [ ! -d "$OCF_ROOT" ]; then
ha_log "ERROR: OCF_ROOT points to non-directory $OCF_ROOT."
exit $OCF_ERR_GENERIC
fi
if [ -z "$OCF_RESOURCE_TYPE" ]; then
: ${OCF_RESOURCE_TYPE:=$__SCRIPT_NAME}
fi
if [ -z "$OCF_RA_VERSION_MAJOR" ]; then
: We are being invoked as an init script.
: Fill in some things with reasonable values.
: ${OCF_RESOURCE_INSTANCE:="default"}
return 0
fi
if [ "x$__OCF_ACTION" = "xmeta-data" ]; then
OCF_RESOURCE_INSTANCE="undef"
fi
if [ -z "$OCF_RESOURCE_INSTANCE" ]; then
ha_log "ERROR: Need to tell us our resource instance name."
exit $OCF_ERR_ARGS
fi
}
hadate() {
date "+${HA_DATEFMT}"
}
set_logtag() {
if [ -z "$HA_LOGTAG" ]; then
if [ -n "$OCF_RESOURCE_INSTANCE" ]; then
HA_LOGTAG="$__SCRIPT_NAME($OCF_RESOURCE_INSTANCE)[$$]"
else
HA_LOGTAG="$__SCRIPT_NAME[$$]"
fi
fi
}
ha_log() {
+ local ignore_stderr="$__ha_log_ignore_stderr_once"
local loglevel
+
+ # always reset this variable
+ __ha_log_ignore_stderr_once=""
+
[ none = "$HA_LOGFACILITY" ] && HA_LOGFACILITY=""
# if we're connected to a tty, then output to stderr
if tty >/dev/null; then
if [ "x$HA_debug" = "x0" -a "x$loglevel" = xdebug ] ; then
return 0
+ elif [ "$ignore_stderr" = "true" ]; then
+ # something already printed this error to stderr, so ignore
+ return 0
fi
if [ "$HA_LOGTAG" ]; then
echo "$HA_LOGTAG: $*"
else
echo "$*"
fi >&2
return 0
fi
set_logtag
if [ "x${HA_LOGD}" = "xyes" ] ; then
ha_logger -t "${HA_LOGTAG}" "$@"
if [ "$?" -eq "0" ] ; then
return 0
fi
fi
if
[ -n "$HA_LOGFACILITY" ]
then
: logging through syslog
# loglevel is unknown, use 'notice' for now
loglevel=notice
case "${*}" in
*ERROR*) loglevel=err;;
*WARN*) loglevel=warning;;
*INFO*|info) loglevel=info;;
esac
logger -t "$HA_LOGTAG" -p ${HA_LOGFACILITY}.${loglevel} "${*}"
fi
if
[ -n "$HA_LOGFILE" ]
then
: appending to $HA_LOGFILE
echo "$HA_LOGTAG: "`hadate`"${*}" >> $HA_LOGFILE
fi
if
- [ -z "$HA_LOGFACILITY" -a -z "$HA_LOGFILE" ]
+ [ -z "$HA_LOGFACILITY" -a -z "$HA_LOGFILE" ] && ! [ "$ignore_stderr" = "true" ]
then
: appending to stderr
echo `hadate`"${*}" >&2
fi
if
[ -n "$HA_DEBUGLOG" ]
then
: appending to $HA_DEBUGLOG
if [ "$HA_LOGFILE"x != "$HA_DEBUGLOG"x ]; then
echo "$HA_LOGTAG: "`hadate`"${*}" >> $HA_DEBUGLOG
fi
fi
}
ha_debug() {
if [ "x${HA_debug}" = "x0" ] ; then
return 0
fi
if tty >/dev/null; then
if [ "$HA_LOGTAG" ]; then
echo "$HA_LOGTAG: $*"
else
echo "$*"
fi >&2
return 0
fi
set_logtag
if [ "x${HA_LOGD}" = "xyes" ] ; then
ha_logger -t "${HA_LOGTAG}" -D "ha-debug" "$@"
if [ "$?" -eq "0" ] ; then
return 0
fi
fi
[ none = "$HA_LOGFACILITY" ] && HA_LOGFACILITY=""
if
[ -n "$HA_LOGFACILITY" ]
then
: logging through syslog
logger -t "$HA_LOGTAG" -p "${HA_LOGFACILITY}.debug" "${*}"
fi
if
[ -n "$HA_DEBUGLOG" ]
then
: appending to $HA_DEBUGLOG
echo "$HA_LOGTAG: "`hadate`"${*}" >> $HA_DEBUGLOG
fi
if
[ -z "$HA_LOGFACILITY" -a -z "$HA_DEBUGLOG" ]
then
: appending to stderr
echo "$HA_LOGTAG: `hadate`${*}: ${HA_LOGFACILITY}" >&2
fi
}
ha_parameter() {
local VALUE
VALUE=`sed -e 's%[ ][ ]*% %' -e 's%^ %%' -e 's%#.*%%' $HA_CF | grep -i "^$1 " | sed 's%[^ ]* %%'`
if
[ "X$VALUE" = X ]
then
case $1 in
keepalive) VALUE=2;;
deadtime)
ka=`ha_parameter keepalive`
VALUE=`expr $ka '*' 2 '+' 1`;;
esac
fi
echo $VALUE
}
ocf_log() {
# TODO: Revisit and implement internally.
if
[ $# -lt 2 ]
then
ocf_log err "Not enough arguments [$#] to ocf_log."
fi
__OCF_PRIO="$1"
shift
__OCF_MSG="$*"
case "${__OCF_PRIO}" in
crit) __OCF_PRIO="CRIT";;
err) __OCF_PRIO="ERROR";;
warn) __OCF_PRIO="WARNING";;
info) __OCF_PRIO="INFO";;
debug)__OCF_PRIO="DEBUG";;
*) __OCF_PRIO=`echo ${__OCF_PRIO}| tr '[a-z]' '[A-Z]'`;;
esac
if [ "${__OCF_PRIO}" = "DEBUG" ]; then
ha_debug "${__OCF_PRIO}: $__OCF_MSG"
else
ha_log "${__OCF_PRIO}: $__OCF_MSG"
fi
}
-
#
# ocf_exit_reason: print exit error string to stderr
# Usage: Allows the OCF script to provide a string
# describing why the exit code was returned.
# Arguments: reason - required, The string that represents why the error
# occured.
-# action_filter - optional, only record this exit string when
-# the action specified by this option is being
-# executed.
#
ocf_exit_reason()
{
- local action_filter=$2
+ local cookie="$OCF_EXIT_REASON_PREFIX"
+ local fmt=$1
+
if [ $# -lt 1 ]; then
ocf_log err "Not enough arguments [$#] to ocf_log_exit_msg."
fi
-
- if [ -z "action_filter" ] || [ "$__OCF_ACTION" = "$action_filter" ]; then
- printf "@OCF_EXIT_REASON_COOKIE@${1}" 1>&2
+ if [ -z "$cookie" ]; then
+ # use a default prefix
+ cookie="ocf-exit-reason:"
fi
+
+ shift
+ printf >&2 "%s${fmt}\n" "$cookie" "$@"
+ __ha_log_ignore_stderr_once="true"
+ ha_log "ERROR: $1"
}
#
# ocf_deprecated: Log a deprecation warning
# Usage: ocf_deprecated [param-name]
# Arguments: param-name optional, name of a boolean resource
# parameter that can be used to suppress
# the warning (default
# "ignore_deprecation")
ocf_deprecated() {
local param
param=${1:-ignore_deprecation}
# don't use ${!param} here, it's a bashism
if ! ocf_is_true $(eval echo \$OCF_RESKEY_$param); then
ocf_log warn "This resource agent is deprecated" \
"and may be removed in a future release." \
"See the man page for details." \
"To suppress this warning, set the \"${param}\"" \
"resource parameter to true."
fi
}
#
# Ocf_run: Run a script, and log its output.
# Usage: ocf_run [-q] [-info|-warn|-err] <command>
# -q: don't log the output of the command if it succeeds
# -info|-warn|-err: log the output of the command at given
# severity if it fails (defaults to err)
#
ocf_run() {
local rc
local output
local verbose=1
local loglevel=err
local var
for var in 1 2
do
case "$1" in
"-q")
verbose=""
shift 1;;
"-info"|"-warn"|"-err")
loglevel=`echo $1 | sed -e s/-//g`
shift 1;;
*)
;;
esac
done
output=`"$@" 2>&1`
rc=$?
output=`echo $output`
if [ $rc -eq 0 ]; then
if [ "$verbose" -a ! -z "$output" ]; then
ocf_log info "$output"
fi
return $OCF_SUCCESS
else
if [ ! -z "$output" ]; then
ocf_log $loglevel "$output"
else
ocf_log $loglevel "command failed: $*"
fi
return $rc
fi
}
ocf_pidfile_status() {
local pid pidfile=$1
if [ ! -e $pidfile ]; then
# Not exists
return 2
fi
pid=`cat $pidfile`
kill -0 $pid 2>&1 > /dev/null
if [ $? = 0 ]; then
return 0
fi
# Stale
return 1
}
ocf_take_lock() {
local lockfile=$1
local rnd=$(ocf_maybe_random)
sleep 0.$rnd
while
ocf_pidfile_status $lockfile
do
ocf_log info "Sleeping until $lockfile is released..."
sleep 0.$rnd
done
echo $$ > $lockfile
}
ocf_release_lock_on_exit() {
local lockfile=$1
trap "rm -f $lockfile" EXIT
}
# returns true if the CRM is currently running a probe. A probe is
# defined as a monitor operation with a monitoring interval of zero.
ocf_is_probe() {
[ "$__OCF_ACTION" = "monitor" -a "$OCF_RESKEY_CRM_meta_interval" = 0 ]
}
# returns true if the resource is configured as a clone. This is
# defined as a resource where the clone-max meta attribute is present,
# and set to greater than zero.
ocf_is_clone() {
[ ! -z "${OCF_RESKEY_CRM_meta_clone_max}" ] && [ "${OCF_RESKEY_CRM_meta_clone_max}" -gt 0 ]
}
# returns true if the resource is configured as a multistate
# (master/slave) resource. This is defined as a resource where the
# master-max meta attribute is present, and set to greater than zero.
ocf_is_ms() {
[ ! -z "${OCF_RESKEY_CRM_meta_master_max}" ] && [ "${OCF_RESKEY_CRM_meta_master_max}" -gt 0 ]
}
# version check functions
# allow . and - to delimit version numbers
# max version number is 999
# letters and such are effectively ignored
#
ocf_is_ver() {
echo $1 | grep '^[0-9][0-9.-]*[0-9]$' >/dev/null 2>&1
}
ocf_ver2num() {
echo $1 | awk -F'[.-]' '
{for(i=1; i<=NF; i++) s=s*1000+$i; print s}
'
}
ocf_ver_level(){
echo $1 | awk -F'[.-]' '{print NF}'
}
ocf_ver_complete_level(){
local ver="$1"
local level="$2"
local i=0
while [ $i -lt $level ]; do
ver=${ver}.0
i=`expr $i + 1`
done
echo $ver
}
# usage: ocf_version_cmp VER1 VER2
# version strings can contain digits, dots, and dashes
# must start and end with a digit
# returns:
# 0: VER1 smaller (older) than VER2
# 1: versions equal
# 2: VER1 greater (newer) than VER2
# 3: bad format
ocf_version_cmp() {
ocf_is_ver "$1" || return 3
ocf_is_ver "$2" || return 3
local v1=$1
local v2=$2
local v1_level=`ocf_ver_level $v1`
local v2_level=`ocf_ver_level $v2`
local level_diff
if [ $v1_level -lt $v2_level ]; then
level_diff=`expr $v2_level - $v1_level`
v1=`ocf_ver_complete_level $v1 $level_diff`
elif [ $v1_level -gt $v2_level ]; then
level_diff=`expr $v1_level - $v2_level`
v2=`ocf_ver_complete_level $v2 $level_diff`
fi
v1=`ocf_ver2num $v1`
v2=`ocf_ver2num $v2`
if [ $v1 -eq $v2 ]; then
return 1
elif [ $v1 -lt $v2 ]; then
return 0
else
return 2 # -1 would look funny in shell ;-)
fi
}
ocf_local_nodename() {
# use crm_node -n for pacemaker > 1.1.8
which pacemakerd > /dev/null 2>&1
if [ $? -eq 0 ]; then
local version=$(pacemakerd -$ | grep "Pacemaker .*" | awk '{ print $2 }')
version=$(echo $version | awk -F- '{ print $1 }')
ocf_version_cmp "$version" "1.1.8"
if [ $? -eq 2 ]; then
which crm_node > /dev/null 2>&1
if [ $? -eq 0 ]; then
crm_node -n
return
fi
fi
fi
# otherwise use uname -n
uname -n
}
# usage: dirname DIR
dirname()
{
local a
local b
[ $# = 1 ] || return 1
a="$1"
while [ 1 ]; do
b="${a%/}"
[ "$a" = "$b" ] && break
a="$b"
done
b=${a%/*}
[ -z "$b" -o "$a" = "$b" ] && b="."
echo "$b"
return 0
}
#
# pseudo_resource status tracking function...
#
# This allows pseudo resources to give correct status information. As we add
# resource monitoring, and better resource tracking in general, this will
# become essential.
#
# These scripts work because ${HA_RSCTMP} is cleaned out every time
# heartbeat is started.
#
# We create "resource-string" tracking files under ${HA_RSCTMP} in a
# very simple way:
#
# Existence of "${HA_RSCTMP}/resource-string" means that we consider
# the resource named by "resource-string" to be running.
#
# Note that "resource-string" needs to be unique. Using the resource type
# plus the resource instance arguments to make up the resource string
# is probably sufficient...
#
# usage: ha_pseudo_resource resource-string op [tracking_file]
# where op is {start|stop|monitor|status|restart|reload|print}
# print is a special op which just prints the tracking file location
# user can override our choice of the tracking file location by
# specifying it as the third arg
# Note that all operations are silent...
#
ha_pseudo_resource()
{
local ha_resource_tracking_file="${3:-${HA_RSCTMP}/$1}"
case $2 in
start|restart|reload) touch "$ha_resource_tracking_file";;
stop) rm -f "$ha_resource_tracking_file";;
status|monitor)
if
[ -f "$ha_resource_tracking_file" ]
then
return 0
else
case $2 in
status) return 3;;
*) return 7;;
esac
fi;;
print) echo "$ha_resource_tracking_file";;
*) return 3;;
esac
}
# usage: rmtempdir TMPDIR
rmtempdir()
{
[ $# = 1 ] || return 1
if [ -e "$1" ]; then
rmdir "$1" || return 1
fi
return 0
}
# usage: maketempfile [-d]
maketempfile()
{
if [ $# = 1 -a "$1" = "-d" ]; then
mktemp -d
return -0
elif [ $# != 0 ]; then
return 1
fi
mktemp
return 0
}
# usage: rmtempfile TMPFILE
rmtempfile ()
{
[ $# = 1 ] || return 1
if [ -e "$1" ]; then
rm "$1" || return 1
fi
return 0
}
# echo the first lower supported check level
# pass set of levels supported by the agent
# (in increasing order, 0 is optional)
ocf_check_level()
{
local lvl prev
lvl=0
prev=0
if ocf_is_decimal "$OCF_CHECK_LEVEL"; then
# the level list should be very short
for lvl; do
if [ "$lvl" -eq "$OCF_CHECK_LEVEL" ]; then
break
elif [ "$lvl" -gt "$OCF_CHECK_LEVEL" ]; then
lvl=$prev # the previous one
break
fi
prev=$lvl
done
fi
echo $lvl
}
# usage: ocf_stop_processes SIGNALS WAIT_TIME PIDS
#
# we send signals (use quotes for more than one!) in the order
# given; if one or more processes are still running we try KILL;
# the wait_time is the _total_ time we'll spend in this function
# this time may be slightly exceeded if the processes won't leave
#
# returns:
# 0: all processes left
# 1: some processes still running
#
# example:
#
# ocf_stop_processes TERM 5 $pids
#
ocf_stop_processes() {
local signals="$1"
local wait_time="$(($2/`echo $signals|wc -w`))"
shift 2
local pids="$*"
local sig i
test -z "$pids" &&
return 0
for sig in $signals KILL; do
kill -s $sig $pids 2>/dev/null
# try to leave early, and yet leave processes time to exit
sleep 0.2
for i in `seq $wait_time`; do
kill -s 0 $pids 2>/dev/null ||
return 0
sleep 1
done
done
return 1
}
#
# RA tracing may be turned on by setting OCF_TRACE_RA
# the trace output will be saved to OCF_TRACE_FILE, if set, or
# by default to
# $HA_VARLIB/trace_ra/<type>/<id>.<action>.<timestamp>
# e.g. $HA_VARLIB/trace_ra/oracle/db.start.2012-11-27.08:37:08
#
# OCF_TRACE_FILE:
# - FD (small integer [3-9]) in that case it is up to the callers
# to capture output; the FD _must_ be open for writing
# - absolute path
#
# NB: FD 9 may be used for tracing with bash >= v4 in case
# OCF_TRACE_FILE is set to a path.
#
ocf_is_bash4() {
echo "$SHELL" | grep bash > /dev/null &&
[ ${BASH_VERSINFO[0]} = "4" ]
}
ocf_trace_redirect_to_file() {
local dest=$1
if ocf_is_bash4; then
exec 9>$dest
BASH_XTRACEFD=9
else
exec 2>$dest
fi
}
ocf_trace_redirect_to_fd() {
local fd=$1
if ocf_is_bash4; then
BASH_XTRACEFD=$fd
else
exec 2>&$fd
fi
}
__ocf_test_trc_dest() {
local dest=$1
if ! touch $dest; then
ocf_log warn "$dest not writable, trace not going to happen"
__OCF_TRC_DEST=""
__OCF_TRC_MANAGE=""
return 1
fi
return 0
}
ocf_default_trace_dest() {
tty >/dev/null && return
if [ -n "$OCF_RESOURCE_TYPE" -a \
-n "$OCF_RESOURCE_INSTANCE" -a -n "$__OCF_ACTION" ]; then
local ts=`date +%F.%T`
__OCF_TRC_DEST=$HA_VARLIB/trace_ra/${OCF_RESOURCE_TYPE}/${OCF_RESOURCE_INSTANCE}.${__OCF_ACTION}.$ts
__OCF_TRC_MANAGE="1"
fi
}
ocf_start_trace() {
export __OCF_TRC_DEST="" __OCF_TRC_MANAGE=""
case "$OCF_TRACE_FILE" in
[3-9]) ocf_trace_redirect_to_fd "$OCF_TRACE_FILE" ;;
/*/*) __OCF_TRC_DEST=$OCF_TRACE_FILE ;;
"") ocf_default_trace_dest ;;
*)
ocf_log warn "OCF_TRACE_FILE must be set to either FD (open for writing) or absolute file path"
ocf_default_trace_dest
;;
esac
if [ "$__OCF_TRC_DEST" ]; then
mkdir -p `dirname $__OCF_TRC_DEST`
__ocf_test_trc_dest $__OCF_TRC_DEST ||
return
ocf_trace_redirect_to_file "$__OCF_TRC_DEST"
fi
PS4='+ `date +"%T"`: ${FUNCNAME[0]:+${FUNCNAME[0]}:}${LINENO}: '
set -x
}
ocf_stop_trace() {
set +x
}
__ocf_set_defaults "$@"
: ${OCF_TRACE_RA:=$OCF_RESKEY_trace_ra}
ocf_is_true "$OCF_TRACE_RA" && ocf_start_trace
diff --git a/include/agent_config.h.in b/include/agent_config.h.in
index 8e98972eb..aea63fd48 100644
--- a/include/agent_config.h.in
+++ b/include/agent_config.h.in
@@ -1,6 +1,3 @@
/* Where Resouce agents keep state files */
#undef HA_RSCTMPDIR
-/* The string delimiter used to signify the start of the exit reason string
- * in an agent's stderr output.*/
-#undef OCF_EXIT_REASON_COOKIE

File Metadata

Mime Type
text/x-diff
Expires
Wed, Feb 26, 11:38 PM (11 h, 39 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1465888
Default Alt Text
(154 KB)

Event Timeline