Page MenuHomeClusterLabs Projects

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/configure.ac b/configure.ac
index 42c1f1ee1..8d64c3bc5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,955 +1,1029 @@
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"])
AC_ARG_WITH([systemdtmpfilesdir],
AS_HELP_STRING([--with-systemdtmpfilesdir=DIR], [Directory for systemd tmp files]),
[], [with_systemdtmpfilesdir=$($PKGCONFIG --variable=tmpfilesdir systemd)])
if test "x$with_systemdtmpfilesdir" != xno; then
AC_SUBST([systemdtmpfilesdir], [$with_systemdtmpfilesdir])
fi
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdtmpfilesdir" -a "x$with_systemdtmpfilesdir" != 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_ROOT_DIR="${prefix}/lib/ocf"
AC_ARG_WITH(ocf-root,
[ --with-ocf-root=DIR directory for OCF scripts [${OCF_ROOT_DIR}]],
[ OCF_ROOT_DIR="$withval" ])
HA_RSCTMPDIR=${localstatedir}/run/resource-agents
AC_ARG_WITH(rsctmpdir,
[ --with-rsctmpdir=DIR directory for resource agents state files [${HA_RSCTMPDIR}]],
[ HA_RSCTMPDIR="$withval" ])
AC_ARG_ENABLE([libnet],
[ --enable-libnet Use libnet for ARP based funcationality, [default=try]],
[enable_libnet="$enableval"], [enable_libnet=try])
BUILD_RGMANAGER=0
BUILD_LINUX_HA=0
RASSET=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)
AC_ARG_WITH(compat-habindir,
[ --with-compat-habindir use HA_BIN directory with compatibility for the Heartbeat stack [${libexecdir}]],
[],
[with_compat_habindir=no])
AM_CONDITIONAL(WITH_COMPAT_HABINDIR, test "x$with_compat_habindir" != "xno")
dnl ===============================================
dnl General Processing
dnl ===============================================
echo Our Host OS: $host_os/$host
AC_MSG_NOTICE(Sanitizing exec_prefix: ${exec_prefix})
case $exec_prefix in
dnl For consistency with Heartbeat, map NONE->$prefix
NONE) exec_prefix=$prefix;;
prefix) exec_prefix=$prefix;;
esac
AC_MSG_NOTICE(Sanitizing INITDIR: ${INITDIR})
case $INITDIR in
prefix) INITDIR=$prefix;;
"")
AC_MSG_CHECKING(which init (rc) directory to use)
for initdir in /etc/init.d /etc/rc.d/init.d /sbin/init.d \
/usr/local/etc/rc.d /etc/rc.d
do
if
test -d $initdir
then
INITDIR=$initdir
break
fi
done
if
test -z $INITDIR
then
INITDIR=${sysconfdir}/init.d
fi
AC_MSG_RESULT($INITDIR);;
esac
AC_SUBST(INITDIR)
if test "${prefix}" = "/usr"; then
INITDIRPREFIX="$INITDIR"
else
INITDIRPREFIX="${prefix}/$INITDIR"
fi
AC_SUBST(INITDIRPREFIX)
AC_MSG_NOTICE(Sanitizing libdir: ${libdir})
case $libdir in
dnl For consistency with Heartbeat, map NONE->$prefix
*prefix*|NONE)
AC_MSG_CHECKING(which lib directory to use)
for aDir in lib64 lib
do
trydir="${exec_prefix}/${aDir}"
if
test -d ${trydir}
then
libdir=${trydir}
break
fi
done
AC_MSG_RESULT($libdir);
;;
esac
if test "x$with_compat_habindir" != "xno" ; then
libexecdir=${libdir}
fi
dnl Expand autoconf variables so that we dont end up with '${prefix}'
dnl in #defines and python scripts
dnl NOTE: Autoconf deliberately leaves them unexpanded to allow
dnl make exec_prefix=/foo install
dnl No longer being able to do this seems like no great loss to me...
eval prefix="`eval echo ${prefix}`"
eval exec_prefix="`eval echo ${exec_prefix}`"
eval bindir="`eval echo ${bindir}`"
eval sbindir="`eval echo ${sbindir}`"
eval libexecdir="`eval echo ${libexecdir}`"
eval datadir="`eval echo ${datadir}`"
eval sysconfdir="`eval echo ${sysconfdir}`"
eval sharedstatedir="`eval echo ${sharedstatedir}`"
eval localstatedir="`eval echo ${localstatedir}`"
eval libdir="`eval echo ${libdir}`"
eval includedir="`eval echo ${includedir}`"
eval oldincludedir="`eval echo ${oldincludedir}`"
eval infodir="`eval echo ${infodir}`"
eval mandir="`eval echo ${mandir}`"
dnl docdir is a recent addition to autotools
eval docdir="`eval echo ${docdir}`"
if test "x$docdir" = "x"; then
docdir="`eval echo ${datadir}/doc`"
fi
AC_SUBST(docdir)
dnl Home-grown variables
eval INITDIR="${INITDIR}"
for j in prefix exec_prefix bindir sbindir libexecdir datadir sysconfdir \
sharedstatedir localstatedir libdir includedir oldincludedir infodir \
mandir INITDIR docdir
do
dirname=`eval echo '${'${j}'}'`
if
test ! -d "$dirname"
then
AC_MSG_WARN([$j directory ($dirname) does not exist!])
fi
done
dnl This OS-based decision-making is poor autotools practice;
dnl feature-based mechanisms are strongly preferred.
dnl
dnl So keep this section to a bare minimum; regard as a "necessary evil".
REBOOT_OPTIONS="-f"
POWEROFF_OPTIONS="-f"
case "$host_os" in
*bsd*) LIBS="-L/usr/local/lib"
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
;;
*solaris*)
REBOOT_OPTIONS="-n"
POWEROFF_OPTIONS="-n"
LDFLAGS+=" -lssp -lssp_nonshared"
;;
*linux*)
AC_DEFINE_UNQUOTED(ON_LINUX, 1, Compiling for Linux platform)
POWEROFF_OPTIONS="-nf"
REBOOT_OPTIONS="-nf"
;;
darwin*)
AC_DEFINE_UNQUOTED(ON_DARWIN, 1, Compiling for Darwin platform)
LIBS="$LIBS -L${prefix}/lib"
CFLAGS="$CFLAGS -I${prefix}/include"
;;
esac
AC_DEFINE_UNQUOTED(HA_LOG_FACILITY, LOG_DAEMON, Default logging facility)
AC_MSG_NOTICE(Host CPU: $host_cpu)
case "$host_cpu" in
ppc64|powerpc64)
case $CFLAGS in
*powerpc64*) ;;
*) if test "$GCC" = yes; then
CFLAGS="$CFLAGS -m64"
fi ;;
esac
esac
AC_MSG_CHECKING(which format is needed to print uint64_t)
case "$host_cpu" in
s390x)U64T="%lu";;
*64*) U64T="%lu";;
*) U64T="%llu";;
esac
AC_MSG_RESULT($U64T)
AC_DEFINE_UNQUOTED(U64T, "$U64T", Correct printf format for logging uint64_t)
dnl Variables needed for substitution
AC_CHECK_HEADERS(heartbeat/glue_config.h)
if test "$ac_cv_header_heartbeat_glue_config_h" = "yes"; then
OCF_ROOT_DIR=`extract_header_define heartbeat/glue_config.h OCF_ROOT_DIR`
else
enable_libnet=no
fi
AC_DEFINE_UNQUOTED(OCF_ROOT_DIR,"$OCF_ROOT_DIR", OCF root directory - specified by the OCF standard)
AC_SUBST(OCF_ROOT_DIR)
GLUE_STATE_DIR=${localstatedir}/run
AC_DEFINE_UNQUOTED(GLUE_STATE_DIR,"$GLUE_STATE_DIR", Where to keep state files and sockets)
AC_SUBST(GLUE_STATE_DIR)
AC_DEFINE_UNQUOTED(HA_VARRUNDIR,"$GLUE_STATE_DIR", Where Heartbeat keeps state files and sockets - old name)
HA_VARRUNDIR="$GLUE_STATE_DIR"
AC_SUBST(HA_VARRUNDIR)
# Expand $prefix
eval HA_RSCTMPDIR="`eval echo ${HA_RSCTMPDIR}`"
AC_DEFINE_UNQUOTED(HA_RSCTMPDIR,"$HA_RSCTMPDIR", Where 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)
OCF_RA_DIR_PREFIX="$OCF_RA_DIR"
AC_SUBST(OCF_RA_DIR_PREFIX)
OCF_LIB_DIR="${OCF_ROOT_DIR}/lib"
AC_DEFINE_UNQUOTED(OCF_LIB_DIR,"$OCF_LIB_DIR", Location for shared code for OCF RAs)
AC_SUBST(OCF_LIB_DIR)
OCF_LIB_DIR_PREFIX="$OCF_LIB_DIR"
AC_SUBST(OCF_LIB_DIR_PREFIX)
dnl ===============================================
dnl rgmanager ras bits
dnl ===============================================
LOGDIR=${localstatedir}/log/cluster
CLUSTERDATA=${datadir}/cluster
AC_SUBST([LOGDIR])
AC_SUBST([CLUSTERDATA])
dnl ===============================================
dnl Program Paths
dnl ===============================================
PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin"
export PATH
AC_CHECK_PROGS(MAKE, gmake make)
+AC_PATH_PROGS(BASH_SHELL, bash)
+if test x"${BASH_SHELL}" = x""; then
+ AC_MSG_ERROR(You need bash installed in order to build ${PACKAGE})
+fi
AC_PATH_PROGS(XSLTPROC, xsltproc)
AM_CONDITIONAL(BUILD_DOC, test "x$XSLTPROC" != "x" )
if test "x$XSLTPROC" = "x"; then
AC_MSG_WARN([xsltproc not installed, unable to (re-)build manual pages])
fi
AC_SUBST(XSLTPROC)
AC_PATH_PROGS(XMLCATALOG, xmlcatalog)
AC_PATH_PROGS(SSH, ssh, /usr/bin/ssh)
AC_PATH_PROGS(SCP, scp, /usr/bin/scp)
AC_PATH_PROGS(TAR, tar)
AC_PATH_PROGS(MD5, md5)
AC_PATH_PROGS(TEST, test)
AC_PATH_PROGS(PING, ping, /bin/ping)
AC_PATH_PROGS(IFCONFIG, ifconfig, /sbin/ifconfig)
AC_PATH_PROGS(MAILCMD, mailx mail, mail)
AC_PATH_PROGS(EGREP, egrep)
+AC_SUBST(BASH_SHELL)
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
STYLESHEET_PREFIX=""
if test x"${XSLTPROC}" != x""; then
AC_MSG_CHECKING(docbook to manpage transform)
# first try to figure out correct template using xmlcatalog query,
# resort to extensive (semi-deterministic) file search if that fails
DOCBOOK_XSL_URI='http://docbook.sourceforge.net/release/xsl/current'
DOCBOOK_XSL_PATH='manpages/docbook.xsl'
STYLESHEET_PREFIX=$(${XMLCATALOG} "" ${DOCBOOK_XSL_URI} \
| sed -n 's|^file://||p;q')
if test x"${STYLESHEET_PREFIX}" = x""; then
DIRS=$(find "${datadir}" -name $(basename $(dirname ${DOCBOOK_XSL_PATH})) \
-type d | LC_ALL=C sort)
XSLT=$(basename ${DOCBOOK_XSL_PATH})
for d in ${DIRS}; do
if test -f "${d}/${XSLT}"; then
STYLESHEET_PREFIX=$(echo "${d}" | sed 's/\/manpages//')
break
fi
done
fi
+ if test x"${STYLESHEET_PREFIX}" = x""; then
+ AC_MSG_ERROR(You need docbook-style-xsl installed in order to build ${PACKAGE})
+ fi
fi
AC_MSG_RESULT($STYLESHEET_PREFIX)
AC_SUBST(STYLESHEET_PREFIX)
dnl ===============================================
dnl Libraries
dnl ===============================================
AC_CHECK_LIB(socket, socket)
AC_CHECK_LIB(gnugetopt, getopt_long) dnl if available
if test "x${enable_thread_safe}" = "xyes"; then
GPKGNAME="gthread-2.0"
else
GPKGNAME="glib-2.0"
fi
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(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 -p | fgrep " CFLAGS=" > /dev/null; then
SAVED_CFLAGS="$CFLAGS"
unset CFLAGS
CFLAGS="$SAVED_CFLAGS"
unset SAVED_CFLAGS
fi
if test "$GCC" != yes; then
CFLAGS="$CFLAGS -g"
enable_fatal_warnings=no
else
CFLAGS="$CFLAGS -ggdb3"
# We had to eliminate -Wnested-externs because of libtool changes
# Also remove -Waggregate-return because we use one libnet
# call which returns a struct
EXTRA_FLAGS="-fgnu89-inline
-fstack-protector-all
-Wall
-Wbad-function-cast
-Wcast-qual
-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 \
systemd/Makefile \
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/ocf-shellfuncs \
+ rgmanager/src/resources/svclib_nfslock \
+ rgmanager/src/resources/lvm_by_lv.sh \
+ rgmanager/src/resources/lvm_by_vg.sh \
rgmanager/src/resources/utils/Makefile \
+ rgmanager/src/resources/utils/fs-lib.sh \
+ rgmanager/src/resources/utils/messages.sh \
+ rgmanager/src/resources/utils/config-utils.sh \
+ rgmanager/src/resources/utils/member_util.sh \
+ rgmanager/src/resources/utils/ra-skelet.sh \
)
+dnl Files we output that need to be executable
+AC_CONFIG_FILES([heartbeat/AoEtarget], [chmod +x heartbeat/AoEtarget])
+AC_CONFIG_FILES([heartbeat/ManageRAID], [chmod +x heartbeat/ManageRAID])
+AC_CONFIG_FILES([heartbeat/ManageVE], [chmod +x heartbeat/ManageVE])
+AC_CONFIG_FILES([heartbeat/Squid], [chmod +x heartbeat/Squid])
+AC_CONFIG_FILES([heartbeat/SysInfo], [chmod +x heartbeat/SysInfo])
+AC_CONFIG_FILES([heartbeat/aws-vpc-route53], [chmod +x heartbeat/aws-vpc-route53])
+AC_CONFIG_FILES([heartbeat/clvm], [chmod +x heartbeat/clvm])
+AC_CONFIG_FILES([heartbeat/conntrackd], [chmod +x heartbeat/conntrackd])
+AC_CONFIG_FILES([heartbeat/dnsupdate], [chmod +x heartbeat/dnsupdate])
+AC_CONFIG_FILES([heartbeat/eDir88], [chmod +x heartbeat/eDir88])
+AC_CONFIG_FILES([heartbeat/fio], [chmod +x heartbeat/fio])
+AC_CONFIG_FILES([heartbeat/iSCSILogicalUnit], [chmod +x heartbeat/iSCSILogicalUnit])
+AC_CONFIG_FILES([heartbeat/iSCSITarget], [chmod +x heartbeat/iSCSITarget])
+AC_CONFIG_FILES([heartbeat/jira], [chmod +x heartbeat/jira])
+AC_CONFIG_FILES([heartbeat/kamailio], [chmod +x heartbeat/kamailio])
+AC_CONFIG_FILES([heartbeat/lxc], [chmod +x heartbeat/lxc])
+AC_CONFIG_FILES([heartbeat/lxd-info], [chmod +x heartbeat/lxd-info])
+AC_CONFIG_FILES([heartbeat/machine-info], [chmod +x heartbeat/machine-info])
+AC_CONFIG_FILES([heartbeat/mariadb], [chmod +x heartbeat/mariadb])
+AC_CONFIG_FILES([heartbeat/mpathpersist], [chmod +x heartbeat/mpathpersist])
+AC_CONFIG_FILES([heartbeat/nfsnotify], [chmod +x heartbeat/nfsnotify])
+AC_CONFIG_FILES([heartbeat/redis], [chmod +x heartbeat/redis])
+AC_CONFIG_FILES([heartbeat/rsyslog], [chmod +x heartbeat/rsyslog])
+AC_CONFIG_FILES([heartbeat/sg_persist], [chmod +x heartbeat/sg_persist])
+AC_CONFIG_FILES([heartbeat/slapd], [chmod +x heartbeat/slapd])
+AC_CONFIG_FILES([heartbeat/syslog-ng], [chmod +x heartbeat/syslog-ng])
+AC_CONFIG_FILES([heartbeat/vsftpd], [chmod +x heartbeat/vsftpd])
+AC_CONFIG_FILES([rgmanager/src/resources/ASEHAagent.sh], [chmod +x rgmanager/src/resources/ASEHAagent.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/apache.sh], [chmod +x rgmanager/src/resources/apache.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/bind-mount.sh], [chmod +x rgmanager/src/resources/bind-mount.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/clusterfs.sh], [chmod +x rgmanager/src/resources/clusterfs.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/db2.sh], [chmod +x rgmanager/src/resources/db2.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/drbd.sh], [chmod +x rgmanager/src/resources/drbd.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/fs.sh], [chmod +x rgmanager/src/resources/fs.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/ip.sh], [chmod +x rgmanager/src/resources/ip.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/lvm.sh], [chmod +x rgmanager/src/resources/lvm.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/mysql.sh], [chmod +x rgmanager/src/resources/mysql.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/named.sh], [chmod +x rgmanager/src/resources/named.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/netfs.sh], [chmod +x rgmanager/src/resources/netfs.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/nfsclient.sh], [chmod +x rgmanager/src/resources/nfsclient.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/nfsexport.sh], [chmod +x rgmanager/src/resources/nfsexport.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/nfsserver.sh], [chmod +x rgmanager/src/resources/nfsserver.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/openldap.sh], [chmod +x rgmanager/src/resources/openldap.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/oracledb.sh], [chmod +x rgmanager/src/resources/oracledb.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/oradg.sh], [chmod +x rgmanager/src/resources/oradg.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/orainstance.sh], [chmod +x rgmanager/src/resources/orainstance.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/oralistener.sh], [chmod +x rgmanager/src/resources/oralistener.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/postgres-8.sh], [chmod +x rgmanager/src/resources/postgres-8.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/samba.sh], [chmod +x rgmanager/src/resources/samba.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/script.sh], [chmod +x rgmanager/src/resources/script.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/service.sh], [chmod +x rgmanager/src/resources/service.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/smb.sh], [chmod +x rgmanager/src/resources/smb.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/tomcat-5.sh], [chmod +x rgmanager/src/resources/tomcat-5.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/tomcat-6.sh], [chmod +x rgmanager/src/resources/tomcat-6.sh])
+AC_CONFIG_FILES([rgmanager/src/resources/vm.sh], [chmod +x rgmanager/src/resources/vm.sh])
+
dnl Now process the entire list of files added by previous
dnl calls to AC_CONFIG_FILES()
AC_OUTPUT()
dnl *****************
dnl Configure summary
dnl *****************
AC_MSG_RESULT([])
AC_MSG_RESULT([$PACKAGE configuration:])
AC_MSG_RESULT([ Version = ${VERSION}])
AC_MSG_RESULT([ Build Version = $Format:%H$])
AC_MSG_RESULT([ 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([ HA_BIN directory prefix = ${libexecdir}])
AC_MSG_RESULT([ RA state files = ${HA_RSCTMPDIR}])
AC_MSG_RESULT([ AIS Plugins = ${LCRSODIR}])
AC_MSG_RESULT([])
AC_MSG_RESULT([ CFLAGS = ${CFLAGS}])
AC_MSG_RESULT([ Libraries = ${LIBS}])
AC_MSG_RESULT([ Stack Libraries = ${CLUSTERLIBS}])
diff --git a/heartbeat/AoEtarget b/heartbeat/AoEtarget.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/AoEtarget
rename to heartbeat/AoEtarget.in
index f6971818f..5e3f01bcc
--- a/heartbeat/AoEtarget
+++ b/heartbeat/AoEtarget.in
@@ -1,245 +1,245 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
#
# AoEtarget OCF RA.
# Manages an ATA-over-Ethernet (AoE) target utilizing the vblade utility.
#
# (c) 2009-2010 Florian Haas, Dejan Muhamedagic,
# and Linux-HA contributors
#
# 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
# Defaults
OCF_RESKEY_nic_default="eth0"
OCF_RESKEY_pid_default="${HA_RSCTMP}/AoEtarget-${OCF_RESOURCE_INSTANCE}.pid"
OCF_RESKEY_binary_default="/usr/sbin/vblade"
: ${OCF_RESKEY_nic=${OCF_RESKEY_nic_default}}
: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
#######################################################################
meta_data() {
cat <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="AoEtarget">
<version>1.0</version>
<longdesc lang="en">
This resource agent manages an ATA-over-Ethernet (AoE) target using vblade.
It exports any block device, or file, as an AoE target using the
specified Ethernet device, shelf, and slot number.
</longdesc>
<shortdesc lang="en">Manages ATA-over-Ethernet (AoE) target exports</shortdesc>
<parameters>
<parameter name="device" required="1">
<longdesc lang="en">
The local block device (or file) to export as an AoE target.
</longdesc>
<shortdesc lang="en">Device to export</shortdesc>
<content type="string"/>
</parameter>
<parameter name="nic" required="1">
<longdesc lang="en">
The local Ethernet interface to use for exporting this AoE target.
</longdesc>
<shortdesc lang="en">Ethernet interface</shortdesc>
<content type="string" default="${OCF_RESKEY_nic_default}"/>
</parameter>
<parameter name="shelf" required="0">
<longdesc lang="en">
The AoE shelf number to use when exporting this target.
</longdesc>
<shortdesc lang="en">AoE shelf number</shortdesc>
<content type="integer"/>
</parameter>
<parameter name="slot" required="1">
<longdesc lang="en">
The AoE slot number to use when exporting this target.
</longdesc>
<shortdesc lang="en">AoE slot number</shortdesc>
<content type="integer"/>
</parameter>
<parameter name="pid" required="0" unique="1">
<longdesc lang="en">
The file to record the daemon pid to.
</longdesc>
<shortdesc lang="en">Daemon pid file</shortdesc>
<content type="string" default="${OCF_RESKEY_pid_default}"/>
</parameter>
<parameter name="binary" required="0">
<longdesc lang="en">
Location of the vblade binary.
</longdesc>
<shortdesc lang="en">vblade binary</shortdesc>
<content type="string" default="${OCF_RESKEY_binary_default}"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="15s"/>
<action name="stop" timeout="15s"/>
<action name="monitor" timeout="15s" interval="10s" depth="0"/>
<action name="reload" timeout="15s"/>
<action name="meta-data" timeout="5s"/>
<action name="validate-all" timeout="15s"/>
</actions>
</resource-agent>
EOF
}
#######################################################################
AoEtarget_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
}
AoEtarget_start() {
AoEtarget_monitor
if [ $? = $OCF_SUCCESS ]; then
return $OCF_SUCCESS
fi
ocf_log info "Exporting device ${OCF_RESKEY_device} on ${OCF_RESKEY_nic} as shelf ${OCF_RESKEY_shelf}, slot ${OCF_RESKEY_slot}"
${OCF_RESKEY_binary} ${OCF_RESKEY_shelf} ${OCF_RESKEY_slot} \
${OCF_RESKEY_nic} ${OCF_RESKEY_device} 2>&1 &
rc=$?
pid=$!
if [ $rc -ne 0 ]; then
return $OCF_ERR_GENERIC
fi
echo $pid > ${OCF_RESKEY_pid} && return $OCF_SUCCESS
return $OCF_ERR_GENERIC
}
AoEtarget_stop() {
AoEtarget_monitor
if [ $? -eq $OCF_SUCCESS ]; then
ocf_log info "Unxporting device ${OCF_RESKEY_device} on ${OCF_RESKEY_nic} as shelf ${OCF_RESKEY_shelf}, slot ${OCF_RESKEY_slot}"
pid=$(cat ${OCF_RESKEY_pid})
kill -TERM $pid
# loop until we're really stopped, wait for the LRM to time us
# out if not
while AoEtarget_monitor; do
sleep 1
done
fi
# Clean up pid file
rm -f ${OCF_RESKEY_pid}
return $OCF_SUCCESS
}
AoEtarget_monitor() {
ocf_pidfile_status ${OCF_RESKEY_pid} >/dev/null 2>&1
rc=$?
if [ $rc -eq 2 ]; then
# no pid file, must assume we're not running
return $OCF_NOT_RUNNING
elif [ $rc -eq 1 ]; then
# stale pid file, assume something went wrong
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
AoEtarget_validate() {
# Is our binary executable?
if [ ! -x ${OCF_RESKEY_binary} ]; then
ocf_log error "${OCF_RESKEY_binary} not found or not executable"
return $OCF_ERR_INSTALLED
fi
# Do we have all required variables?
for var in device nic shelf slot pid; do
param="OCF_RESKEY_${var}"
if [ -z "${!param}" ]; then
ocf_log error "Missing resource parameter \"$var\"!"
return $OCF_ERR_CONFIGURED
fi
done
# Is the pid file directory writable?
pid_dir=`dirname "$OCF_RESKEY_pid"`
touch "$pid_dir/$$"
if [ $? != 0 ]; then
ocf_log error "Cannot create pid file in $pid_dir -- check directory permissions"
return $OCF_ERR_INSTALLED
fi
rm "$pid_dir/$$"
# Does the device we are trying to export exist?
if [ ! -e ${OCF_RESKEY_device} ]; then
ocf_log error "${OCF_RESKEY_device} does not exist"
return $OCF_ERR_INSTALLED
fi
return $OCF_SUCCESS
}
case $1 in
meta-data)
meta_data
exit $OCF_SUCCESS
;;
usage|help)
AoEtarget_usage
exit $OCF_SUCCESS
;;
esac
# Everything except usage and meta-data must pass the validate test
AoEtarget_validate || exit $?
case $__OCF_ACTION in
start)
AoEtarget_start
;;
stop)
AoEtarget_stop
;;
status|monitor)
AoEtarget_monitor
;;
reload)
ocf_log err "Reloading..."
AoEtarget_start
;;
validate-all)
AoEtarget_validate
;;
*)
AoEtarget_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
rc=$?
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
exit $rc
diff --git a/heartbeat/ManageRAID b/heartbeat/ManageRAID.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/ManageRAID
rename to heartbeat/ManageRAID.in
index ae1832a78..04efcb42c
--- a/heartbeat/ManageRAID
+++ b/heartbeat/ManageRAID.in
@@ -1,384 +1,384 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Name ManageRAID
# Author Matthias Dahl, m.dahl@designassembly.de
# License GPL version 2
#
# (c) 2006 The Design Assembly GmbH.
#
#
# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
#
# This resource agent is most likely function complete but not error free. Please
# consider it BETA quality for the moment until it has proven itself stable...
#
# USE AT YOUR OWN RISK.
#
# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
#
#
# partly based on/inspired by original Heartbeat2 OCF resource agents
#
# Description
#
# Manages starting, mounting, unmounting, stopping and monitoring of RAID devices
# which are preconfigured in /etc/conf.d/HB-ManageRAID.
#
#
# Created 11. Sep 2006
# Updated 18. Sep 2006
#
# rev. 1.00.2
#
# Changelog
#
# 18/Sep/06 1.00.1 more cleanup
# 12/Sep/06 1.00.1 add more functionality
# add sanity check for config parameters
# general cleanup all over the place
# 11/Sep/06 1.00.0 it's alive... muahaha... ALIVE... :-)
#
#
# TODO
#
# - check if at least one disk out of PREFIX_LOCALDISKS is still active
# in RAID otherwise consider RAID broken and stop it.
#
# The reason behind this: consider a RAID-1 which contains iSCSI devices
# shared over Ethernet which get dynamically added/removed to/from the RAID.
# Once all local disks have failed and only those iSCSI disks remain, the RAID
# should really stop to prevent bad performance and possible data loss.
#
###
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
###
# required utilities
# required files/devices
RAID_MDSTAT=/proc/mdstat
#
# check_file()
#
check_file ()
{
if [[ ! -e $1 ]]; then
ocf_log err "setup problem: file $1 does not exist."
exit $OCF_ERR_GENERIC
fi
}
#
# usage()
#
usage()
{
cat <<-EOT
usage: $0 {start|stop|status|monitor|validate-all|usage|meta-data}
EOT
}
#
# meta_data()
#
meta_data()
{
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="ManageRAID">
<version>1.00.2</version>
<longdesc lang="en">
Manages starting, stopping and monitoring of RAID devices which
are preconfigured in /etc/conf.d/HB-ManageRAID.
</longdesc>
<shortdesc lang="en">Manages RAID devices</shortdesc>
<parameters>
<parameter name="raidname" unique="0" required="1">
<longdesc lang="en">
Name (case sensitive) of RAID to manage. (preconfigured in /etc/conf.d/HB-ManageRAID)
</longdesc>
<shortdesc lang="en">RAID name</shortdesc>
<content type="string" default="" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="75s" />
<action name="stop" timeout="75s" />
<action name="status" depth="0" timeout="10s" interval="10s" />
<action name="monitor" depth="0" timeout="10s" interval="10s" />
<action name="validate-all" timeout="5s" />
<action name="meta-data" timeout="5s" />
</actions>
</resource-agent>
END
}
#
# start_raid()
#
start_raid()
{
declare -i retcode
status_raid
retcode=$?
if [[ $retcode == $OCF_SUCCESS ]]; then
return $OCF_SUCCESS
elif [[ $retcode != $OCF_NOT_RUNNING ]]; then
return $retcode
fi
for ldev in "${RAID_LOCALDISKS[@]}"; do
if [[ ! -b $ldev ]]; then
ocf_log err "$ldev is not a (local) block device."
return $OCF_ERR_ARGS
fi
done
$MDADM -A $RAID_DEVPATH -a yes -u ${!RAID_UUID} "${RAID_LOCALDISKS[@]}" &> /dev/null
if [[ $? != 0 ]]; then
ocf_log err "starting ${!RAID_DEV} with ${RAID_LOCALDISKS[*]} failed."
return $OCF_ERR_GENERIC
fi
$MOUNT -o ${!RAID_MOUNTOPTIONS} $RAID_DEVPATH ${!RAID_MOUNTPOINT} &> /dev/null
if [[ $? != 0 ]]; then
$MDADM -S $RAID_DEVPATH &> /dev/null
if [[ $? != 0 ]]; then
ocf_log err "mounting ${!RAID_DEV} to ${!RAID_MOUNTPOINT} failed as well as stopping the RAID itself."
else
ocf_log err "mounting ${!RAID_DEV} to ${!RAID_MOUNTPOINT} failed. RAID stopped again."
fi
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
#
# stop_raid()
#
stop_raid()
{
status_raid
if [[ $? == $OCF_NOT_RUNNING ]]; then
return $OCF_SUCCESS
fi
$UMOUNT ${!RAID_MOUNTPOINT} &> /dev/null
if [[ $? != 0 ]]; then
ocf_log err "unmounting ${!RAID_MOUNTPOINT} failed. not stopping ${!RAID_DEV}!"
return $OCF_ERR_GENERIC
fi
$MDADM -S $RAID_DEVPATH &> /dev/null
if [[ $? != 0 ]]; then
ocf_log err "stopping RAID ${!RAID_DEV} failed."
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
#
# status_raid()
#
status_raid()
{
declare -i retcode_raidcheck
declare -i retcode_uuidcheck
$CAT $RAID_MDSTAT | $GREP -e "${!RAID_DEV}[\ ]*:[\ ]*active" &> /dev/null
if [ $? -ne 0 ]; then
return $OCF_NOT_RUNNING
fi
if [ ! -e $RAID_DEVPATH ]; then
return $OCF_ERR_GENERIC
fi
$MDADM --detail -t $RAID_DEVPATH &> /dev/null
retcode_raidcheck=$?
$MDADM --detail -t $RAID_DEVPATH | $GREP -qEe "^[\ ]*UUID[\ ]*:[\ ]*${!RAID_UUID}" &> /dev/null
retcode_uuidcheck=$?
if [ $retcode_raidcheck -gt 3 ]; then
ocf_log err "mdadm returned error code $retcode_raidcheck while checking ${!RAID_DEV}."
return $OCF_ERR_GENERIC
elif [ $retcode_raidcheck -eq 3 ]; then
ocf_log err "${!RAID_DEV} has failed."
return $OCF_ERR_GENERIC
elif [ $retcode_raidcheck -lt 3 ] && [ $retcode_uuidcheck != 0 ]; then
ocf_log err "active RAID ${!RAID_DEV} and configured UUID (!$RAID_UUID) do not match."
return $OCF_ERR_GENERIC
fi
$MOUNT | $GREP -e "$RAID_DEVPATH on ${!RAID_MOUNTPOINT}" &> /dev/null
if [[ $? != 0 ]]; then
ocf_log err "${!RAID_DEV} seems to be no longer mounted at ${!RAID_MOUNTPOINT}"
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
#
# validate_all_raid()
#
validate_all_raid()
{
#
# since all parameters are checked every time ManageRAID is
# invoked, there not much more to check...
#
# status_raid should cover the rest.
#
declare -i retcode
status_ve
retcode=$?
if [[ $retcode != $OCF_SUCCESS && $retcode != $OCF_NOT_RUNNING ]]; then
return $retcode
fi
return $OCF_SUCCESS
}
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
## required configuration
#
[ -f /etc/conf.d/HB-ManageRAID ] || {
ocf_log err "/etc/conf.d/HB-ManageRAID missing"
exit $OCF_ERR_INSTALLED
}
. /etc/conf.d/HB-ManageRAID
#
##
#
# check relevant environment variables for sanity and security
#
declare -i retcode_test
declare -i retcode_grep
$TEST -z "$OCF_RESKEY_raidname"
retcode_test=$?
echo "$OCF_RESKEY_raidname" | $GREP -qEe "^[[:alnum:]\_]+$"
retcode_grep=$?
if [[ $retcode_test != 1 || $retcode_grep != 0 ]]; then
ocf_log err "OCF_RESKEY_raidname not set or invalid."
exit $OCF_ERR_ARGS
fi
RAID_UUID=${OCF_RESKEY_raidname}_UUID
echo ${!RAID_UUID} | $GREP -qEe "^[[:alnum:]]{8}:[[:alnum:]]{8}:[[:alnum:]]{8}:[[:alnum:]]{8}$"
if [[ $? != 0 ]]; then
ocf_log err "${OCF_RESKEY_raidname}_UUID is invalid."
exit $OCF_ERR_ARGS
fi
RAID_DEV=${OCF_RESKEY_raidname}_DEV
echo ${!RAID_DEV} | $GREP -qEe "^md[0-9]+$"
if [[ $? != 0 ]]; then
ocf_log err "${OCF_RESKEY_raidname}_DEV is invalid."
exit $OCF_ERR_ARGS
fi
RAID_DEVPATH=/dev/${!RAID_DEV/md/md\/}
RAID_MOUNTPOINT=${OCF_RESKEY_raidname}_MOUNTPOINT
echo ${!RAID_MOUNTPOINT} | $GREP -qEe "^[[:alnum:]\/\_\"\ ]+$"
if [[ $? != 0 ]]; then
ocf_log err "${OCF_RESKEY_raidname}_MOUNTPOINT is invalid."
exit $OCF_ERR_ARGS
fi
RAID_MOUNTOPTIONS=${OCF_RESKEY_raidname}_MOUNTOPTIONS
echo ${!RAID_MOUNTOPTIONS} | $GREP -qEe "^[[:alpha:]\,]+$"
if [[ $? != 0 ]]; then
ocf_log err "${OCF_RESKEY_raidname}_MOUNTOPTIONS is invalid."
exit $OCF_ERR_ARGS
fi
RAID_LOCALDISKS=${OCF_RESKEY_raidname}_LOCALDISKS[@]
RAID_LOCALDISKS=( "${!RAID_LOCALDISKS}" )
if [ ${#RAID_LOCALDISKS[@]} -lt 1 ]; then
ocf_log err "you have to specify at least one local disk."
exit $OCF_ERR_ARGS
fi
#
# check that all relevant utilities are available
#
check_binary $MDADM
check_binary $MOUNT
check_binary $UMOUNT
check_binary $GREP
check_binary $CAT
check_binary $TEST
check_binary echo
#
# check that all relevant devices are available
#
check_file $RAID_MDSTAT
#
# finally... let's see what we are ordered to do :-)
#
case "$1" in
start)
start_raid
;;
stop)
stop_raid
;;
status|monitor)
status_raid
;;
validate-all)
validate_all_raid
;;
*)
usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit $?
diff --git a/heartbeat/ManageVE b/heartbeat/ManageVE.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/ManageVE
rename to heartbeat/ManageVE.in
index b31317da7..aef69f4a2
--- a/heartbeat/ManageVE
+++ b/heartbeat/ManageVE.in
@@ -1,313 +1,313 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# ManageVE OCF RA. Manages OpenVZ Virtual Environments (VEs)
#
# (c) 2006-2010 Matthias Dahl, Florian Haas,
# and Linux-HA contributors
#
# 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.
#
#
# This OCF compliant resource agent manages OpenVZ VEs and thus requires
# a proper OpenVZ installation including a recent vzctl util.
#
# rev. 1.00.4
#
# Changelog
#
# 21/Oct/10 1.00.4 implement migrate_from/migrate_to
# 12/Sep/06 1.00.3 more cleanup
# 12/Sep/06 1.00.2 fixed some logic in start_ve
# general cleanup all over the place
# 11/Sep/06 1.00.1 fixed some typos
# 07/Sep/06 1.00.0 it's alive... muahaha... ALIVE... :-)
#
###
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
###
# required utilities
VZCTL=/usr/sbin/vzctl
#
# usage()
#
usage()
{
cat <<-EOF
usage: $0 {start|stop|status|monitor|migrate_from|migrate_to|validate-all|usage|meta-data}
EOF
}
#
# meta_data()
#
meta_data()
{
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="ManageVE">
<version>1.00.4</version>
<longdesc lang="en">
This OCF compliant resource agent manages OpenVZ VEs and thus requires
a proper OpenVZ installation including a recent vzctl util.
</longdesc>
<shortdesc lang="en">Manages an OpenVZ Virtual Environment (VE)</shortdesc>
<parameters>
<parameter name="veid" unique="0" required="1">
<longdesc lang="en">
OpenVZ ID of virtual environment (see output of vzlist -a for all assigned IDs)
</longdesc>
<shortdesc lang="en">OpenVZ ID of VE</shortdesc>
<content type="integer" default="" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="75s" />
<action name="stop" timeout="75s" />
<action name="status" depth="0" timeout="10s" interval="10s" />
<action name="monitor" depth="0" timeout="10s" interval="10s" />
<action name="migrate_to" timeout="75s" />
<action name="migrate_from" timeout="75s" />
<action name="validate-all" timeout="5s" />
<action name="meta-data" timeout="5s" />
</actions>
</resource-agent>
END
}
#
# start_ve()
#
# Starts a VE, or simply logs a message if the VE is already running.
#
start_ve()
{
if status_ve; then
ocf_log info "VE $VEID already running."
return $OCF_SUCCESS
fi
ocf_run $VZCTL start $VEID || exit $OCF_ERR_GENERIC
return $OCF_SUCCESS
}
#
# stop_ve()
#
# ATTENTION: The following code relies on vzctl's exit codes, especially:
#
# 0 : success
#
# In case any of those exit codes change, this function will need fixing.
#
stop_ve()
{
status_ve
if [ $? -eq $OCF_NOT_RUNNING ]; then
ocf_log info "VE $VEID already stopped."
return $OCF_SUCCESS
fi
ocf_run $VZCTL stop $VEID || exit $OCF_ERR_GENERIC
return $OCF_SUCCESS
}
#
# migrate_to_ve()
#
# In the process of a resource migration, checkpoints the VE. For this
# to work, vzctl must obviously create the dump file in a place which
# the migration target has access to (an NFS mount, a DRBD device,
# etc.).
#
migrate_to_ve()
{
if ! status_ve; then
ocf_log err "VE $VEID is not running, aborting"
exit $OCF_ERR_GENERIC
fi
ocf_run $VZCTL chkpnt $VEID || exit $OCF_ERR_GENERIC
return $OCF_SUCCESS
}
#
# migrate_to_ve()
#
# In the process of a resource migration, restores the VE. For this to
# work, vzctl must obviously have access to the dump file which was
# created on the migration source (on an NFS mount, a DRBD device,
# etc.).
#
migrate_from_ve()
{
ocf_run $VZCTL restore $VEID || exit $OCF_ERR_GENERIC
return $OCF_SUCCESS
}
#
# status_ve()
#
# ATTENTION: The following code relies on vzctl's status output. The fifth
# column is interpreted as the VE status (either up or down).
#
# In case the output format should change, this function will need fixing.
#
status_ve()
{
declare -i retcode
veexists=`$VZCTL status $VEID 2>/dev/null | $AWK '{print $3}'`
vestatus=`$VZCTL status $VEID 2>/dev/null | $AWK '{print $5}'`
retcode=$?
if [[ $retcode != 0 ]]; then
# log error only if expected to find running
if [ "$__OCF_ACTION" = "monitor" ] && ! ocf_is_probe; then
ocf_log err "vzctl status $VEID returned: $retcode"
fi
exit $OCF_ERR_GENERIC
fi
if [[ $veexists != "exist" ]]; then
ocf_log err "vzctl status $VEID returned: $VEID does not exist."
return $OCF_NOT_RUNNING
fi
case "$vestatus" in
running)
return $OCF_SUCCESS
;;
down)
return $OCF_NOT_RUNNING
;;
*)
ocf_log err "vzctl status $VEID, wrong output format. (5th column: $vestatus)"
exit $OCF_ERR_GENERIC
;;
esac
}
#
# validate_all_ve()
#
# ATTENTION: The following code relies on vzctl's status output. The fifth
# column is interpreted as the VE status (either up or down).
#
# In case the output format should change, this function will need fixing.
#
validate_all_ve()
{
declare -i retcode
# VEID should be a valid VE
`status_ve`
retcode=$?
if [[ $retcode != $OCF_SUCCESS && $retcode != $OCF_NOT_RUNNING ]]; then
return $retcode
fi
return $OCF_SUCCESS
}
if [[ $# != 1 ]]; then
usage
exit $OCF_ERR_ARGS
fi
case "$1" in
meta-data)
meta_data
exit $OCF_SUCCESS
;;
usage)
usage
exit $OCF_SUCCESS
;;
*)
;;
esac
#
# check relevant environment variables for sanity and security
#
# empty string?
`test -z "$OCF_RESKEY_veid"`
declare -i veidtest1=$?
# really a number?
`echo "$OCF_RESKEY_veid" | egrep -q '^[[:digit:]]+$'`
if [[ $veidtest1 != 1 || $? != 0 ]]; then
ocf_log err "OCF_RESKEY_veid not set or not a number."
exit $OCF_ERR_ARGS
fi
declare -i VEID=$OCF_RESKEY_veid
#
# check that all relevant utilities are available
#
check_binary $VZCTL
check_binary $AWK
#
# finally... let's see what we are ordered to do :-)
#
case "$1" in
start)
start_ve
;;
stop)
stop_ve
;;
status|monitor)
status_ve
;;
migrate_to)
migrate_to_ve
;;
migrate_from)
migrate_from_ve
;;
validate-all)
validate_all_ve
;;
*)
usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit $?
diff --git a/heartbeat/Squid b/heartbeat/Squid.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/Squid
rename to heartbeat/Squid.in
index 6b7e04c5b..a46d9c9e2
--- a/heartbeat/Squid
+++ b/heartbeat/Squid.in
@@ -1,446 +1,446 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Description: Manages a Squid Server provided by NTT OSSC as an
# OCF High-Availability resource under Heartbeat/LinuxHA control
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# Copyright (c) 2008 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
#
#######################################################################
# OCF parameters:
# OCF_RESKEY_squid_exe : Executable file
# OCF_RESKEY_squid_conf : Configuration file
# OCF_RESKEY_squid_pidfile: Process id file
# OCF_RESKEY_squid_port : Port number
# OCF_RESKEY_debug_mode : Debug mode
# OCF_RESKEY_debug_log : Debug log file
# OCF_RESKEY_squid_stop_timeout:
# Number of seconds to await to confirm a
# normal stop method
#
# OCF_RESKEY_squid_exe, OCF_RESKEY_squid_conf, OCF_RESKEY_squid_pidfile
# and OCF_RESKEY_squid_port must be specified. Each of the rests
# has its default value or refers OCF_RESKEY_squid_conf to make
# its value when no explicit value is given.
###############################################################################
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
usage()
{
cat <<-!
usage: $0 action
action:
start : start a new squid instance
stop : stop the running squid instance
status : return the status of squid, run or down
monitor : return TRUE if the squid appears to be working.
meta-data : show meta data message
validate-all: validate the instance parameters
!
return $OCF_ERR_ARGS
}
metadata_squid()
{
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="Squid">
<version>1.0</version>
<longdesc lang="en">
The resource agent of Squid.
This manages a Squid instance as an HA resource.
</longdesc>
<shortdesc lang="en">Manages a Squid proxy server instance</shortdesc>
<parameters>
<parameter name="squid_exe" required="1" unique="0">
<longdesc lang="en">
This is a required parameter. This parameter specifies squid's
executable file.
</longdesc>
<shortdesc lang="en">Executable file</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="squid_conf" required="1" unique="1">
<longdesc lang="en">
This is a required parameter. This parameter specifies a configuration file
for a squid instance managed by this RA.
</longdesc>
<shortdesc lang="en">Configuration file</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="squid_pidfile" required="1" unique="1">
<longdesc lang="en">
This is a required parameter. This parameter specifies a process id file
for a squid instance managed by this RA.
</longdesc>
<shortdesc lang="en">Pidfile</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="squid_port" required="1" unique="1">
<longdesc lang="en">
This is a required parameter. This parameter specifies a port number
for a squid instance managed by this RA. If plural ports are used,
you must specifiy the only one of them.
</longdesc>
<shortdesc lang="en">Port number</shortdesc>
<content type="integer" default=""/>
</parameter>
<parameter name="squid_stop_timeout" unique="0">
<longdesc lang="en">
On stop, a squid shutdown is invoked first. If the resource
doesn't stop within this timeout, we resort to stopping
processes by sending signals and finally KILLing them.
</longdesc>
<shortdesc lang="en">how long to wait for squid shutdown to stop the
instance before resorting to kill</shortdesc>
<content type="integer" default="10"/>
</parameter>
<parameter name="debug_mode" unique="0">
<longdesc lang="en">
This is an optional parameter.
This RA runs in debug mode when this parameter includes 'x' or 'v'.
If 'x' is included, both of STDOUT and STDERR redirect to the logfile
specified by "debug_log", and then the builtin shell option 'x' is turned on.
It is similar about 'v'.
</longdesc>
<shortdesc lang="en">Debug mode</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="debug_log" unique="0">
<longdesc lang="en">
This is an optional and omittable parameter.
This parameter specifies a destination file for debug logs
and works only if this RA run in debug mode. Refer to "debug_mode"
about debug mode. If no value is given but it's requied, it's made by the
following rules: "/var/log/" as a directory part, the basename of
the configuration file given by "syslog_ng_conf" as a basename part,
".log" as a suffix.
</longdesc>
<shortdesc lang="en">A destination of the debug log</shortdesc>
<content type="string" default=""/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="60s" />
<action name="stop" timeout="120s" />
<action name="status" timeout="60s" />
<action name="monitor" depth="0" timeout="30s" interval="10s" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="5s"/>
</actions>
</resource-agent>
END
return $OCF_SUCCESS
}
get_pids()
{
SQUID_PIDS=( )
# Seek by pattern
SQUID_PIDS[0]=$(pgrep -f "$PROCESS_PATTERN")
# Seek by pidfile
SQUID_PIDS[1]=$(awk '1{print $1}' $SQUID_PIDFILE 2>/dev/null)
if [[ -n "${SQUID_PIDS[1]}" ]]; then
typeset exe
exe=$(ls -l "/proc/${SQUID_PIDS[1]}/exe")
if [[ $? = 0 ]]; then
exe=${exe##*-> }
if ! [[ "$exe" = $SQUID_EXE ]]; then
SQUID_PIDS[1]=""
fi
else
SQUID_PIDS[1]=""
fi
fi
# Seek by port
SQUID_PIDS[2]=$(
netstat -apn |
awk '/tcp.*:'$SQUID_PORT' .*LISTEN/ && $7~/^[1-9]/ {
sub("\\/.*", "", $7); print $7; exit}')
}
are_all_pids_found()
{
if
[[ -n "${SQUID_PIDS[0]}" ]] &&
[[ -n "${SQUID_PIDS[1]}" ]] &&
[[ -n "${SQUID_PIDS[2]}" ]]
then
return 0
else
return 1
fi
}
are_pids_sane()
{
if [[ "${SQUID_PIDS[1]}" = "${SQUID_PIDS[2]}" ]]; then
return $OCF_SUCCESS
else
ocf_exit_reason "$SQUID_NAME:Pid unmatch"
return $OCF_ERR_GENERIC
fi
}
is_squid_dead()
{
if
[[ -z "${SQUID_PIDS[0]}" ]] &&
[[ -z "${SQUID_PIDS[2]}" ]]
then
return 0
else
return 1
fi
}
monitor_squid()
{
typeset trialcount=0
while true; do
get_pids
if are_all_pids_found; then
are_pids_sane
return $OCF_SUCCESS
fi
if is_squid_dead; then
return $OCF_NOT_RUNNING
fi
ocf_log info "$SQUID_NAME:Inconsistent processes:" \
"${SQUID_PIDS[0]},${SQUID_PIDS[1]},${SQUID_PIDS[2]}"
(( trialcount = trialcount + 1 ))
if (( trialcount > SQUID_CONFIRM_TRIALCOUNT )); then
ocf_exit_reason "$SQUID_NAME:Inconsistency of processes remains unsolved"
return $OCF_ERR_GENERIC
fi
sleep 1
done
}
start_squid()
{
typeset status
monitor_squid
status=$?
if [[ $status != $OCF_NOT_RUNNING ]]; then
return $status
fi
set -- "$SQUID_OPTS"
ocf_run $SQUID_EXE -f "$SQUID_CONF" "$@"
status=$?
if [[ $status != $OCF_SUCCESS ]]; then
return $OCF_ERR_GENERIC
fi
while true; do
get_pids
if are_all_pids_found && are_pids_sane; then
return $OCF_SUCCESS
fi
ocf_log info "$SQUID_NAME:Waiting for squid to be invoked"
sleep 1
done
return $OCF_ERR_GENERIC
}
stop_squid()
{
typeset lapse_sec
if ocf_run $SQUID_EXE -f $SQUID_CONF -k shutdown; then
lapse_sec=0
while true; do
get_pids
if is_squid_dead; then
rm -f $SQUID_PIDFILE
return $OCF_SUCCESS
fi
(( lapse_sec = lapse_sec + 1 ))
if (( lapse_sec > SQUID_STOP_TIMEOUT )); then
break
fi
sleep 1
ocf_log info "$SQUID_NAME:$FUNCNAME:$LINENO: " \
"stop NORM $lapse_sec/$SQUID_STOP_TIMEOUT"
done
fi
while true; do
get_pids
ocf_log info "$SQUID_NAME:$FUNCNAME:$LINENO: " \
"try to stop by SIGKILL:${SQUID_PIDS[0]} ${SQUID_PIDS[2]}"
kill -KILL ${SQUID_PIDS[0]} ${SQUID_PIDS[2]}
sleep 1
if is_squid_dead; then
rm -f $SQUID_PIDFILE
return $OCF_SUCCESS
fi
done
return $OCF_ERR_GENERIC
}
status_squid()
{
return $OCF_SUCCESS
}
validate_all_squid()
{
ocf_log info "validate_all_squid[$SQUID_NAME]"
return $OCF_SUCCESS
}
: === Debug ${0##*/} $1 ===
if [[ "$1" = "meta-data" ]]; then
metadata_squid
exit $?
fi
SQUID_CONF="${OCF_RESKEY_squid_conf}"
if [[ -z "$SQUID_CONF" ]]; then
ocf_exit_reason "SQUID_CONF is not defined"
exit $OCF_ERR_CONFIGURED
fi
SQUID_NAME="${SQUID_CONF##*/}"
SQUID_NAME="${SQUID_NAME%.*}"
DEBUG_LOG="${OCF_RESKEY_debug_log-/var/log/squid_${SQUID_NAME}_debug}.log"
DEBUG_MODE=""
case $OCF_RESKEY_debug_mode in
*x*) DEBUG_MODE="${DEBUG_MODE}x";;
esac
case $OCF_RESKEY_debug_mode in
*v*) DEBUG_MODE="${DEBUG_MODE}v";;
esac
if [ -n "$DEBUG_MODE" ]; then
PS4='\d \t \h '"${1-unknown} "
export PS4
exec 1>>$DEBUG_LOG 2>&1
set -$DEBUG_MODE
fi
SQUID_EXE="${OCF_RESKEY_squid_exe}"
if [[ -z "$SQUID_EXE" ]]; then
ocf_exit_reason "SQUID_EXE is not defined"
exit $OCF_ERR_CONFIGURED
fi
if [[ ! -x "$SQUID_EXE" ]]; then
ocf_exit_reason "$SQUID_EXE is not found"
exit $OCF_ERR_CONFIGURED
fi
SQUID_PIDFILE="${OCF_RESKEY_squid_pidfile}"
if [[ -z "$SQUID_PIDFILE" ]]; then
ocf_exit_reason "SQUID_PIDFILE is not defined"
exit $OCF_ERR_CONFIGURED
fi
SQUID_PORT="${OCF_RESKEY_squid_port}"
if [[ -z "$SQUID_PORT" ]]; then
ocf_exit_reason "SQUID_PORT is not defined"
exit $OCF_ERR_CONFIGURED
fi
SQUID_OPTS="${OCF_RESKEY_squid_opts}"
SQUID_PIDS=( )
SQUID_CONFIRM_TRIALCOUNT="${OCF_RESKEY_squid_confirm_trialcount-3}"
SQUID_STOP_TIMEOUT="${OCF_RESKEY_squid_stop_timeout-10}"
SQUID_SUSPEND_TRIALCOUNT="${OCF_RESKEY_squid_suspend_trialcount-10}"
PROCESS_PATTERN="$SQUID_EXE -f $SQUID_CONF"
COMMAND=$1
case "$COMMAND" in
start)
ocf_log debug "[$SQUID_NAME] Enter squid start"
start_squid
func_status=$?
ocf_log debug "[$SQUID_NAME] Leave squid start $func_status"
exit $func_status
;;
stop)
ocf_log debug "[$SQUID_NAME] Enter squid stop"
stop_squid
func_status=$?
ocf_log debug "[$SQUID_NAME] Leave squid stop $func_status"
exit $func_status
;;
status)
status_squid
exit $?
;;
monitor)
#ocf_log debug "[$SQUID_NAME] Enter squid monitor"
monitor_squid
func_status=$?
#ocf_log debug "[$SQUID_NAME] Leave squid monitor $func_status"
exit $func_status
;;
validate-all)
validate_all_squid
exit $?
;;
*)
usage
;;
esac
# vim: set sw=4 ts=4 :
diff --git a/heartbeat/SysInfo b/heartbeat/SysInfo.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/SysInfo
rename to heartbeat/SysInfo.in
index 92289fe25..61f5d5757
--- a/heartbeat/SysInfo
+++ b/heartbeat/SysInfo.in
@@ -1,364 +1,364 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
#
# SysInfo OCF Resource Agent
# It records (in the CIB) various attributes of a node
#
# Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Bree
# 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="SysInfo">
<version>1.0</version>
<longdesc lang="en">
This is a SysInfo Resource Agent.
It records (in the CIB) various attributes of a node
Sample Linux output:
arch: i686
os: Linux-2.4.26-gentoo-r14
free_swap: 1999
cpu_info: Intel(R) Celeron(R) CPU 2.40GHz
cpu_speed: 4771.02
cpu_cores: 1
cpu_load: 0.00
ram_total: 513
ram_free: 117
root_free: 2.4
Sample Darwin output:
arch: i386
os: Darwin-8.6.2
cpu_info: Intel Core Duo
cpu_speed: 2.16
cpu_cores: 2
cpu_load: 0.18
ram_total: 2016
ram_free: 787
root_free: 13
Units:
free_swap: Mb
ram_*: Mb
root_free: Gb
cpu_speed (Linux): bogomips
cpu_speed (Darwin): Ghz
</longdesc>
<shortdesc lang="en">Records various node attributes in the CIB</shortdesc>
<parameters>
<parameter name="pidfile" unique="0">
<longdesc lang="en">PID file</longdesc>
<shortdesc lang="en">PID file</shortdesc>
<content type="string" default="$OCF_RESKEY_pidfile" />
</parameter>
<parameter name="delay" unique="0">
<longdesc lang="en">Interval to allow values to stabilize</longdesc>
<shortdesc lang="en">Dampening Delay</shortdesc>
<content type="string" default="0s" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="20s" />
<action name="stop" timeout="20s" />
<action name="monitor" timeout="20s" interval="60s"/>
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="20s" />
</actions>
</resource-agent>
END
}
#######################################################################
UpdateStat() {
name=$1; shift
value="$*"
echo -e "$name:\t$value"
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -S status -n $name -v "$value"
}
SysInfoStats() {
UpdateStat arch "`uname -m`"
UpdateStat os "`uname -s`-`uname -r`"
case `uname -s` in
"Darwin")
mem=`top -l 1 | grep Mem: | awk '{print $10}'`
mem_used=`top -l 1 | grep Mem: | awk '{print $8}'`
mem=`SysInfo_mem_units $mem`
mem_used=`SysInfo_mem_units $mem_used`
mem_total=`expr $mem_used + $mem`
cpu_type=`system_profiler SPHardwareDataType | grep "CPU Type:"`
cpu_type=${cpu_type/*: /}
cpu_speed=`system_profiler SPHardwareDataType | grep "CPU Speed:" | awk '{print $3}'`
cpu_cores=`system_profiler SPHardwareDataType | grep "Number Of"`
cpu_cores=${cpu_cores/*: /}
;;
"Linux")
if [ -f /proc/cpuinfo ]; then
cpu_type=`grep "model name" /proc/cpuinfo | head -n 1`
cpu_type=${cpu_type/*: /}
cpu_speed=`grep "bogomips" /proc/cpuinfo | head -n 1`
cpu_speed=${cpu_speed/*: /}
cpu_cores=`grep "^processor" /proc/cpuinfo | wc -l`
fi
if [ -f /proc/meminfo ]; then
# meminfo results are in kB
mem=`grep "SwapFree" /proc/meminfo | awk '{print $2"k"}'`
if [ ! -z $mem ]; then
UpdateStat free_swap `SysInfo_mem_units $mem`
fi
mem=`grep "Inactive" /proc/meminfo | awk '{print $2"k"}'`
mem_total=`grep "MemTotal" /proc/meminfo | awk '{print $2"k"}'`
else
mem=`top -n 1 | grep Mem: | awk '{print $7}'`
fi
;;
*)
esac
if [ x != x"$cpu_type" ]; then
UpdateStat cpu_info "$cpu_type"
fi
if [ x != x"$cpu_speed" ]; then
UpdateStat cpu_speed "$cpu_speed"
fi
if [ x != x"$cpu_cores" ]; then
UpdateStat cpu_cores "$cpu_cores"
fi
loads=`uptime`
load15=`echo ${loads} | awk '{print $10}'`
UpdateStat cpu_load $load15
if [ ! -z "$mem" ]; then
# Massage the memory values
UpdateStat ram_total `SysInfo_mem_units $mem_total`
UpdateStat ram_free `SysInfo_mem_units $mem`
fi
# Portability notes:
# o df: -h flag not available on Solaris 8. (OK on 9, 10, ...) #FIXME#
# o tail: explicit "-n" not available in Solaris; instead simplify
# 'tail -n <c>' to the equivalent 'tail -<c>'.
disk=`df -h / | tail -1 | awk '{print $4}'`
if [ x != x"$disk" ]; then
UpdateStat root_free `SysInfo_hdd_units $disk`
fi
}
SysInfo_mem_units() {
mem=$1
if [ -z $1 ]; then
return
fi
memlen=`expr ${#mem} - 1`
memlen_alt=`expr ${#mem} - 2`
if [ ${mem:$memlen:1} = "G" ]; then
mem="${mem:0:$memlen}"
if [ $mem != ${mem/./} ]; then
mem_before=${mem/.*/}
mem_after=${mem/*./}
mem=$[mem_before*1024]
if [ ${#mem_after} = 0 ]; then
:
elif [ ${#mem_after} = 1 ]; then
mem=$[mem+100*$mem_after]
elif [ ${#mem_after} = 2 ]; then
mem=$[mem+10*$mem_after]
elif [ ${#mem_after} = 3 ]; then
mem=$[mem+$mem_after]
else
mem_after=${mem_after:0:3}
mem=$[mem+$mem_after]
fi
fi
elif [ ${mem:$memlen:1} = "M" ]; then
mem=${mem/.*/}
mem="${mem:0:$memlen}"
elif [ ${mem:$memlen:1} = "k" ]; then
mem="${mem:0:$memlen}"
mem=${mem/.*/}
mem=`expr $mem / 1024`
elif [ ${mem:$memlen_alt:2} = "kB" ]; then
mem="${mem:0:$memlen_alt}"
mem=${mem/.*/}
mem=`expr $mem / 1024`
elif [ ${mem:$memlen_alt:2} = "Mb" ]; then
mem="${mem:0:$memlen_alt}"
mem=${mem/.*/}
elif [ ${mem:$memlen_alt:2} = "MB" ]; then
mem="${mem:0:$memlen_alt}"
mem=${mem/.*/}
fi
# Round to the next multiple of 50
memlen=`expr ${#mem} - 2`
mem_round="${mem:$memlen:2}"
if [ x$mem_round = x ]; then
:
elif [ $mem_round = "00" ]; then
:
else
mem_round=`echo $mem_round | sed 's/^0//'`
if [ $mem_round -lt "50" ]; then
mem=$[mem+50]
mem=$[mem-$mem_round]
else
mem=$[mem+100]
mem=$[mem-$mem_round]
fi
fi
echo $mem
}
SysInfo_hdd_units() {
disk=$1
disklen=`expr ${#disk} - 1`
disklen_alt=`expr ${#disk} - 2`
if [ ${disk:$disklen:1} = "G" ]; then
disk="${disk:0:$disklen}"
elif [ ${disk:$disklen:1} = "M" ]; then
disk="${disk:0:$disklen}"
disk=${disk/.*/}
disk=`expr $disk / 1024`
elif [ ${disk:$disklen:1} = "k" ]; then
disk="${disk:0:$disklen}"
disk=${disk/.*/}
disk=`expr $disk / 1048576`
elif [ ${disk:$disklen_alt:2} = "kB" ]; then
disk="${disk:0:$disklen_alt}"
disk=${disk/.*/}
disk=`expr $disk / 1048576`
elif [ ${disk:$disklen_alt:2} = "Mb" ]; then
disk="${disk:0:$disklen_alt}"
disk=${disk/.*/}
disk=`expr $disk / 1024`
elif [ ${disk:$disklen_alt:2} = "MB" ]; then
disk="${disk:0:$disklen_alt}"
disk=${disk/.*/}
disk=`expr $disk / 1024`
fi
echo $disk
}
SysInfo_usage() {
cat <<END
usage: $0 {start|stop|monitor|validate-all|meta-data}
Expects to have a fully populated OCF RA-compliant environment set.
END
}
SysInfo_start() {
echo $OCF_RESKEY_clone > $OCF_RESKEY_pidfile
SysInfoStats
exit $OCF_SUCCESS
}
SysInfo_stop() {
rm $OCF_RESKEY_pidfile
exit $OCF_SUCCESS
}
SysInfo_monitor() {
if [ -f $OCF_RESKEY_pidfile ]; then
clone=`cat $OCF_RESKEY_pidfile`
fi
if [ x$clone = x ]; then
rm $OCF_RESKEY_pidfile
exit $OCF_NOT_RUNNING
elif [ $clone = $OCF_RESKEY_clone ]; then
SysInfoStats
exit $OCF_SUCCESS
elif [ x$OCF_RESKEY_CRM_meta_globally_unique = xtrue ] ||
[ x$OCF_RESKEY_CRM_meta_globally_unique = xTrue ] ||
[ x$OCF_RESKEY_CRM_meta_globally_unique = xyes ] ||
[ x$OCF_RESKEY_CRM_meta_globally_unique = xYes ]; then
SysInfoStats
exit $OCF_SUCCESS
fi
exit $OCF_NOT_RUNNING
}
SysInfo_validate() {
return $OCF_SUCCESS
}
if [ $# -ne 1 ]; then
SysInfo_usage
exit $OCF_ERR_ARGS
fi
: ${OCF_RESKEY_pidfile:="$HA_RSCTMP/SysInfo-${OCF_RESOURCE_INSTANCE}"}
: ${OCF_RESKEY_clone:="0"}
if [ x != x${OCF_RESKEY_delay} ]; then
OCF_RESKEY_delay="-d ${OCF_RESKEY_delay}"
fi
case $__OCF_ACTION in
meta-data) meta_data
exit $OCF_SUCCESS
;;
start) SysInfo_start
;;
stop) SysInfo_stop
;;
monitor) SysInfo_monitor
;;
validate-all) SysInfo_validate
;;
usage|help) SysInfo_usage
exit $OCF_SUCCESS
;;
*) SysInfo_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit $?
diff --git a/heartbeat/aws-vpc-route53 b/heartbeat/aws-vpc-route53.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/aws-vpc-route53
rename to heartbeat/aws-vpc-route53.in
index 59cb672d7..69f06ba48
--- a/heartbeat/aws-vpc-route53
+++ b/heartbeat/aws-vpc-route53.in
@@ -1,302 +1,302 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright 2017 Amazon.com, Inc. and its affiliates. All Rights Reserved.
# Licensed under the MIT License.
#
# Copyright 2017 Amazon.com, Inc. and its affiliates
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
#
#
# OCF resource agent to move an IP address within a VPC in the AWS
# Written by Stefan Schneider , Martin Tegmeier (AWS)
# Based on code of Markus Guertler#
#
#
# OCF resource agent to move an IP address within a VPC in the AWS
# Written by Stefan Schneider (AWS) , Martin Tegmeier (AWS)
# Based on code of Markus Guertler (SUSE)
#
# Mar. 15, 2017, vers 1.0.2
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
OCF_RESKEY_ttl_default=10
: ${OCF_RESKEY_ttl:=${OCF_RESKEY_ttl_default}}
#######################################################################
usage() {
cat <<-EOT
usage: $0 {start|stop|status|monitor|validate-all|meta-data}
EOT
}
metadata() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="aws-vpc-route53">
<version>1.0</version>
<longdesc lang="en">
Update Route53 record of Amazon Webservices EC2 by updating an entry in a
hosted zone ID table.
AWS instances will require policies which allow them to update Route53 ARecords:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1471878724000",
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets",
"route53:GetChange",
"route53:ListResourceRecordSets",
],
"Resource": [
"*"
]
}
]
}
Example Cluster Configuration:
Use a configuration in "crm configure edit" which looks as follows. Replace
hostedzoneid, fullname and profile with the appropriate values:
primitive res_route53 ocf:heartbeat:aws-vpc-route53 \
params hostedzoneid=EX4MPL3EX4MPL3 fullname=service.cloud.example.corp. profile=cluster \
op start interval=0 timeout=180 \
op stop interval=0 timeout=180 \
op monitor interval=300 timeout=180 \
meta target-role=Started
</longdesc>
<shortdesc lang="en">Update Route53 VPC record for AWS EC2</shortdesc>
<parameters>
<parameter name="hostedzoneid" required="1">
<longdesc lang="en">
Hosted zone ID of Route 53. This is the table of
the Route 53 record.
</longdesc>
<shortdesc lang="en">AWS hosted zone ID</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="fullname" required="1">
<longdesc lang="en">
The full name of the service which will host the IP address.
Example: service.cloud.example.corp.
Note: The trailing dot is important to Route53!
</longdesc>
<shortdesc lang="en">Full service name</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="ttl" required="0">
<longdesc lang="en">
Time to live for Route53 ARECORD
</longdesc>
<shortdesc lang="en">ARECORD TTL</shortdesc>
<content type="string" default="${OCF_RESKEY_ttl_default}" />
</parameter>
<parameter name="profile" required="1">
<longdesc lang="en">
The name of the AWS CLI profile of the root account. This
profile will have to use the "text" format for CLI output.
The file /root/.aws/config should have an entry which looks
like:
[profile cluster]
region = us-east-1
output = text
"cluster" is the name which has to be used in the cluster
configuration. The region has to be the current one. The
output has to be "text".
</longdesc>
<shortdesc lang="en">AWS Profile Name</shortdesc>
<content type="string" default="" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="180s" />
<action name="stop" timeout="180s" />
<action name="monitor" depth="0" timeout="180s" interval="300s" />
<action name="validate-all" timeout="5s" />
<action name="meta-data" timeout="5s" />
</actions>
</resource-agent>
END
}
ec2ip_validate() {
ocf_log debug "function: validate"
# Full name
[[ -z "$OCF_RESKEY_fullname" ]] && ocf_log error "Full name parameter not set $OCF_RESKEY_fullname!" && exit $OCF_ERR_CONFIGURED
# Hosted Zone ID
[[ -z "$OCF_RESKEY_hostedzoneid" ]] && ocf_log error "Hosted Zone ID parameter not set $OCF_RESKEY_hostedzoneid!" && exit $OCF_ERR_CONFIGURED
# profile
[[ -z "$OCF_RESKEY_profile" ]] && ocf_log error "AWS CLI profile not set $OCF_RESKEY_profile!" && exit $OCF_ERR_CONFIGURED
# TTL
[[ -z "$OCF_RESKEY_ttl" ]] && ocf_log error "TTL not set $OCF_RESKEY_ttl!" && exit $OCF_ERR_CONFIGURED
ocf_log debug "Testing aws command"
aws --version 2>&1
if [ "$?" -gt 0 ]; then
ocf_log error "Error while executing aws command as user root! Please check if AWS CLI tools (Python flavor) are properly installed and configured." && exit $OCF_ERR_INSTALLED
fi
ocf_log debug "ok"
if [ -n "$OCF_RESKEY_profile" ]; then
AWS_PROFILE_OPT="--profile $OCF_RESKEY_profile"
else
AWS_PROFILE_OPT="--profile default"
fi
return $OCF_SUCCESS
}
ec2ip_monitor() {
ec2ip_validate
ocf_log debug "Checking Route53 record sets"
IPADDRESS="$(ec2metadata aws ip | grep local-ipv4 | /usr/bin/awk '{ print $2 }')"
ARECORD="$(aws $AWS_PROFILE_OPT route53 list-resource-record-sets --hosted-zone-id $OCF_RESKEY_hostedzoneid --query "ResourceRecordSets[?Name=='$OCF_RESKEY_fullname']" | grep RESOURCERECORDS | /usr/bin/awk '{ print $2 }' )"
ocf_log debug "Found IP address: $ARECORD ."
if [ "${ARECORD}" == "${IPADDRESS}" ]; then
ocf_log debug "ARECORD $ARECORD found"
return $OCF_SUCCESS
else
ocf_log debug "No ARECORD found"
return $OCF_NOT_RUNNING
fi
return $OCF_SUCCESS
}
_update_record() {
update_action="$1"
IPADDRESS="$2"
ocf_log info "Updating Route53 $OCF_RESKEY_hostedzoneid with $IPADDRESS for $OCF_RESKEY_fullname"
ROUTE53RECORD="$(maketempfile)"
if [ $? -ne 0 ] || [ -z "$ROUTE53RECORD" ]; then
ocf_exit_reason "Failed to create temporary file for record update"
exit $OCF_ERR_GENERIC
fi
cat >>"${ROUTE53RECORD}" <<-EOF
{
"Comment": "Update record to reflect new IP address for a system ",
"Changes": [
{
"Action": "${update_action}",
"ResourceRecordSet": {
"Name": "${OCF_RESKEY_fullname}",
"Type": "A",
"TTL": ${OCF_RESKEY_ttl},
"ResourceRecords": [
{
"Value": "${IPADDRESS}"
}
]
}
}
]
}
EOF
cmd="aws --profile ${OCF_RESKEY_profile} route53 change-resource-record-sets --hosted-zone-id ${OCF_RESKEY_hostedzoneid} \
--change-batch file://${ROUTE53RECORD} "
ocf_log debug "Executing command: $cmd"
CHANGEID=$($cmd | grep CHANGEINFO | /usr/bin/awk -F'\t' '{ print $3 }' )
ocf_log debug "Change id: ${CHANGEID}"
rmtempfile ${ROUTE53RECORD}
CHANGEID=$(echo $CHANGEID |cut -d'/' -f 3 |cut -d'"' -f 1 )
ocf_log debug "Change id: ${CHANGEID}"
STATUS="PENDING"
MYSECONDS=2
while [ "$STATUS" = 'PENDING' ]; do
sleep ${MYSECONDS}
STATUS="$(aws --profile ${OCF_RESKEY_profile} route53 get-change --id $CHANGEID | grep CHANGEINFO | /usr/bin/awk -F'\t' '{ print $4 }' |cut -d'"' -f 2 )"
ocf_log debug "Waited for ${MYSECONDS} seconds and checked execution of Route 53 update status: ${STATUS} "
done
}
ec2ip_stop() {
ocf_log info "Bringing down Route53 agent. (Will remove ARECORD)"
IPADDRESS="$(ec2metadata aws ip | grep local-ipv4 | /usr/bin/awk '{ print $2 }')"
ARECORD="$(aws $AWS_PROFILE_OPT route53 list-resource-record-sets --hosted-zone-id $OCF_RESKEY_hostedzoneid --query "ResourceRecordSets[?Name=='$OCF_RESKEY_fullname']" | grep RESOURCERECORDS | /usr/bin/awk '{ print $2 }' )"
ocf_log debug "Found IP address: $ARECORD ."
if [ ${ARECORD} != ${IPADDRESS} ]; then
ocf_log debug "No ARECORD found"
return $OCF_SUCCESS
else
# determine IP address
IPADDRESS="$(ec2metadata aws ip | grep local-ipv4 | /usr/bin/awk '{ print $2 }')"
# Patch file
ocf_log debug "Deleting IP address to ${IPADDRESS}"
return $OCF_SUCCESS
fi
_update_record "DELETE" "$IPADDRESS"
return $OCF_SUCCESS
}
ec2ip_start() {
IPADDRESS="$(ec2metadata aws ip | grep local-ipv4 | /usr/bin/awk '{ print $2 }')"
_update_record "UPSERT" "$IPADDRESS"
return $OCF_SUCCESS
}
###############################################################################
case $__OCF_ACTION in
usage|help)
usage
exit $OCF_SUCCESS
;;
meta-data)
metadata
exit $OCF_SUCCESS
;;
monitor)
ec2ip_monitor
;;
stop)
ec2ip_stop
;;
validate-all)
ec2ip_validate
;;
start)
ec2ip_start
;;
*)
usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/heartbeat/clvm b/heartbeat/clvm.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/clvm
rename to heartbeat/clvm.in
index 35544fb9a..5197b50f4
--- a/heartbeat/clvm
+++ b/heartbeat/clvm.in
@@ -1,433 +1,433 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (c) 2014 David Vossel <davidvossel@gmail.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
#######################################################################
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="clvm">
<version>1.0</version>
<longdesc lang="en">
This agent manages the clvmd daemon.
</longdesc>
<shortdesc lang="en">clvmd</shortdesc>
<parameters>
<parameter name="with_cmirrord" unique="0" required="0">
<longdesc lang="en">
Start with cmirrord (cluster mirror log daemon).
</longdesc>
<shortdesc lang="en">activate cmirrord</shortdesc>
<content type="boolean" default="false" />
</parameter>
<parameter name="daemon_options" unique="0">
<longdesc lang="en">
Options to clvmd. Refer to clvmd.8 for detailed descriptions.
</longdesc>
<shortdesc lang="en">Daemon Options</shortdesc>
<content type="string" default="-d0"/>
</parameter>
<parameter name="activate_vgs" unique="0">
<longdesc lang="en">
Whether or not to activate all cluster volume groups after starting
the clvmd or not. Note that clustered volume groups will always be
deactivated before the clvmd stops regardless of what this option
is set to.
</longdesc>
<shortdesc lang="en">Activate volume groups</shortdesc>
<content type="boolean" default="true"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="90s" />
<action name="stop" timeout="90s" />
<action name="monitor" timeout="90s" interval="30s" depth="0" />
<action name="meta-data" timeout="10s" />
<action name="validate-all" timeout="20s" />
</actions>
</resource-agent>
END
}
#######################################################################
: ${OCF_RESKEY_daemon_options:="-d0"}
: ${OCF_RESKEY_activate_vgs:="true"}
sbindir=$HA_SBIN_DIR
if [ -z $sbindir ]; then
sbindir=/usr/sbin
fi
DAEMON="clvmd"
CMIRROR="cmirrord"
DAEMON_PATH="${sbindir}/clvmd"
CMIRROR_PATH="${sbindir}/cmirrord"
LVMCONF="${sbindir}/lvmconf"
LOCK_FILE="/var/lock/subsys/$DAEMON"
# attempt to detect where the vg tools are located
# for some reason this isn't consistent with sbindir
# in some distros.
vgtoolsdir=$(dirname $(which vgchange 2> /dev/null) 2> /dev/null)
if [ -z "$vgtoolsdir" ]; then
vgtoolsdir="$sbindir"
fi
LVM_VGCHANGE=${vgtoolsdir}/vgchange
LVM_VGDISPLAY=${vgtoolsdir}/vgdisplay
LVM_VGSCAN=${vgtoolsdir}/vgscan
# Leaving this in for legacy. We do not want to advertize
# the abilty to set options in the systconfig exists, we want
# to expand the OCF style options as necessary instead.
[ -f /etc/sysconfig/cluster ] && . /etc/sysconfig/cluster
[ -f /etc/sysconfig/$DAEMON ] && . /etc/sysconfig/$DAEMON
CLVMD_TIMEOUT="90"
if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
CLVMD_TIMEOUT=$(($OCF_RESKEY_CRM_meta_timeout/1000))
fi
clvmd_usage()
{
cat <<END
usage: $0 {start|stop|monitor|validate-all|meta-data}
Expects to have a fully populated OCF RA-compliant environment set.
END
}
clvmd_validate()
{
# check_binary will exit with OCF_ERR_INSTALLED
# when binary is missing
check_binary "pgrep"
check_binary $DAEMON_PATH
if ocf_is_true $OCF_RESKEY_with_cmirrord; then
check_binary $CMIRROR_PATH
fi
if [ "$__OCF_ACTION" != "monitor" ]; then
check_binary "killall"
check_binary $LVM_VGCHANGE
check_binary $LVM_VGDISPLAY
check_binary $LVM_VGSCAN
fi
# Future validation checks here.
return $OCF_SUCCESS
}
check_process()
{
local binary=$1
local pidfile="${HA_RSCTMP}/${binary}-${OCF_RESOURCE_INSTANCE}.pid"
local pid
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
# shortcut without requiring pgrep to search through all procs
return $OCF_SUCCESS
fi
fi
pid=$(pgrep ${binary})
case $? in
0)
ocf_log info "PID file (pid:${pid} at $pidfile) created for ${binary}."
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_exit_reason "Error encountered detecting pid status of $binary"
return $OCF_ERR_GENERIC;;
esac
}
clvmd_status()
{
local rc
local mirror_rc
clvmd_validate
if [ $? -ne $OCF_SUCCESS ]; then
ocf_exit_reason "Unable to monitor, Environment validation failed."
return $?
fi
check_process $DAEMON
rc=$?
mirror_rc=$rc
if ocf_is_true $OCF_RESKEY_with_cmirrord; then
check_process $CMIRROR
mirror_rc=$?
fi
# If these ever don't match, return error to force recovery
if [ $mirror_rc -ne $rc ]; then
return $OCF_ERR_GENERIC
fi
return $rc
}
# NOTE: replace this with vgs, once display filter per attr is implemented.
clustered_vgs() {
${LVM_VGDISPLAY} 2>/dev/null | awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}'
}
wait_for_process()
{
local binary=$1
local timeout=$2
local count=0
ocf_log info "Waiting for $binary to exit"
while [ $count -le $timeout ]; do
check_process $binary
if [ $? -eq $OCF_NOT_RUNNING ]; then
ocf_log info "$binary terminated"
return $OCF_SUCCESS
fi
sleep 1
count=$((count+1))
done
return $OCF_ERR_GENERIC
}
time_left()
{
local end=$1
local default=$2
local now=$SECONDS
local result=0
result=$(( $end - $now ))
if [ $result -lt $default ]; then
return $default
fi
return $result
}
clvmd_stop()
{
local LVM_VGS
local rc=$OCF_SUCCESS
local end=$(( $SECONDS + $CLVMD_TIMEOUT ))
clvmd_status
if [ $? -eq $OCF_NOT_RUNNING ]; then
return $OCF_SUCCESS
fi
check_process $DAEMON
if [ $? -ne $OCF_NOT_RUNNING ]; then
LVM_VGS="$(clustered_vgs)"
if [ -n "$LVM_VGS" ]; then
ocf_log info "Deactivating clustered VG(s):"
ocf_run ${LVM_VGCHANGE} -anl $LVM_VGS
if [ $? -ne 0 ]; then
ocf_exit_reason "Failed to deactivate volume groups, cluster vglist = $LVM_VGS"
return $OCF_ERR_GENERIC
fi
fi
ocf_log info "Signaling $DAEMON to exit"
killall -TERM $DAEMON
if [ $? != 0 ]; then
ocf_exit_reason "Failed to signal -TERM to $DAEMON"
return $OCF_ERR_GENERIC
fi
wait_for_process $DAEMON $CLVMD_TIMEOUT
rc=$?
if [ $rc -ne $OCF_SUCCESS ]; then
ocf_exit_reason "$DAEMON failed to exit"
return $rc
fi
rm -f $LOCK_FILE
fi
check_process $CMIRROR
if [ $? -ne $OCF_NOT_RUNNING ] && ocf_is_true $OCF_RESKEY_with_cmirrord; then
local timeout
ocf_log info "Signaling $CMIRROR to exit"
killall -INT $CMIRROR
time_left $end 10; timeout=$?
wait_for_process $CMIRROR $timeout
rc=$?
if [ $rc -ne $OCF_SUCCESS ]; then
killall -KILL $CMIRROR
time_left $end 10; timeout=$?
wait_for_process $CMIRROR $(time_left $end 10)
rc=$?
fi
fi
return $rc
}
start_process()
{
local binary_path=$1
local opts=$2
check_process "$(basename $binary_path)"
if [ $? -ne $OCF_SUCCESS ]; then
ocf_log info "Starting $binary_path: "
ocf_run $binary_path $opts
rc=$?
if [ $rc -ne 0 ]; then
ocf_exit_reason "Failed to launch $binary_path, exit code $rc"
exit $OCF_ERR_GENERIC
fi
fi
return $OCF_SUCCESS
}
clvmd_activate_all()
{
if ! ocf_is_true "$OCF_RESKEY_activate_vgs"; then
ocf_log info "skipping vg activation, activate_vgs is set to $OCF_RESKEY_activate_vgs"
return $OCF_SUCCESS
fi
# Activate all volume groups by leaving the
# "volume group name" parameter empty
ocf_run ${LVM_VGCHANGE} -aay
if [ $? -ne 0 ]; then
ocf_log info "Failed to activate VG(s):"
clvmd_stop
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
clvmd_start()
{
local rc=0
local CLVMDOPTS="-T${CLVMD_TIMEOUT} $OCF_RESKEY_daemon_options"
clvmd_validate
if [ $? -ne $OCF_SUCCESS ]; then
ocf_exit_reason "Unable to start, Environment validation failed."
return $?
fi
# systemd drop-in to stop process before storage services during
# shutdown/reboot
if systemd_is_running ; then
systemd_drop_in "99-clvmd" "After" "blk-availability.service"
fi
clvmd_status
if [ $? -eq $OCF_SUCCESS ]; then
ocf_log debug "$DAEMON already started"
clvmd_activate_all
return $?;
fi
# autoset locking type to clusted when lvmconf tool is available
if [ -x "$LVMCONF" ]; then
$LVMCONF --enable-cluster > /dev/null 2>&1
fi
# if either of these fail, script will exit OCF_ERR_GENERIC
if ocf_is_true $OCF_RESKEY_with_cmirrord; then
start_process $CMIRROR_PATH
fi
start_process $DAEMON_PATH "$CLVMDOPTS"
# Refresh local cache.
#
# It's possible that new PVs were added to this, or other VGs
# while this node was down. So we run vgscan here to avoid
# any potential "Missing UUID" messages with subsequent
# LVM commands.
# The following step would be better and more informative to the user:
# 'action "Refreshing VG(s) local cache:" ${LVM_VGSCAN}'
# but it could show warnings such as:
# 'clvmd not running on node x-y-z Unable to obtain global lock.'
# and the action would be shown as FAILED when in reality it didn't.
# Ideally vgscan should have a startup mode that would not print
# unnecessary warnings.
${LVM_VGSCAN} > /dev/null 2>&1
touch $LOCK_FILE
clvmd_activate_all
clvmd_status
return $?
}
case $__OCF_ACTION in
meta-data) meta_data
exit $OCF_SUCCESS;;
start) clvmd_start;;
stop) clvmd_stop;;
monitor) clvmd_status;;
validate-all) clvmd_validate;;
usage|help) clvmd_usage;;
*) clvmd_usage
exit $OCF_ERR_UNIMPLEMENTED;;
esac
rc=$?
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
exit $rc
diff --git a/heartbeat/conntrackd b/heartbeat/conntrackd.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/conntrackd
rename to heartbeat/conntrackd.in
index 0fb8c98ce..aa6d3b8c9
--- a/heartbeat/conntrackd
+++ b/heartbeat/conntrackd.in
@@ -1,335 +1,335 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
#
# An OCF RA for conntrackd
# http://conntrack-tools.netfilter.org/
#
# Copyright (c) 2011 Dominik Klein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Further, this software is distributed without any warranty that it is
# free of the rightful claim of any third person regarding infringement
# or the like. Any license provided herein, whether implied or
# otherwise, applies only to this software file. Patent licenses, if
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
#######################################################################
OCF_RESKEY_binary_default=conntrackd
OCF_RESKEY_config_default=/etc/conntrackd/conntrackd.conf
# For users of versions prior to 1.2:
# Map renamed parameter "conntrackd" to "binary" if in use
: ${OCF_RESKEY_binary=${OCF_RESKEY_conntrackd-${OCF_RESKEY_binary_default}}}
: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}}
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="conntrackd">
<version>1.2</version>
<longdesc lang="en">
Master/Slave OCF Resource Agent for conntrackd
</longdesc>
<shortdesc lang="en">This resource agent manages conntrackd</shortdesc>
<parameters>
<parameter name="binary">
<longdesc lang="en">Name of the conntrackd executable.
If conntrackd is installed and available in the default PATH, it is sufficient to configure the name of the binary
For example "my-conntrackd-binary-version-0.9.14"
If conntrackd is installed somewhere else, you may also give a full path
For example "/packages/conntrackd-0.9.14/sbin/conntrackd"
</longdesc>
<shortdesc lang="en">Name of the conntrackd executable</shortdesc>
<content type="string" default="$OCF_RESKEY_binary_default"/>
</parameter>
<parameter name="config">
<longdesc lang="en">Full path to the conntrackd.conf file.
For example "/packages/conntrackd-0.9.14/etc/conntrackd/conntrackd.conf"</longdesc>
<shortdesc lang="en">Path to conntrackd.conf</shortdesc>
<content type="string" default="$OCF_RESKEY_config_default"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="30s" />
<action name="promote" timeout="30s" />
<action name="demote" timeout="30s" />
<action name="notify" timeout="30s" />
<action name="stop" timeout="30s" />
<action name="monitor" timeout="20s" interval="20s" role="Slave" />
<action name="monitor" timeout="20s" interval="10s" role="Master" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="30s" />
</actions>
</resource-agent>
END
}
meta_expect_eq()
{
local what=$1 whatvar=OCF_RESKEY_CRM_meta_${1//-/_} expect=$2
local val=${!whatvar}
if [[ -n $val ]]; then
# [, not [[, or it won't work ;)
[ $val = $expect ] && return
fi
ocf_exit_reason "meta parameter misconfigured, expected $what $op $expect, but found ${val:-unset}."
exit $OCF_ERR_CONFIGURED
}
conntrackd_is_master() {
# You can't query conntrackd whether it is master or slave. It can be both at the same time.
# This RA creates a statefile during promote and enforces master-max=1 and clone-node-max=1
ha_pseudo_resource $statefile monitor
}
conntrackd_set_master_score() {
${HA_SBIN_DIR}/crm_master -Q -l reboot -v $1
}
conntrackd_monitor() {
rc=$OCF_NOT_RUNNING
# It does not write a PID file, so check the socket exists after
# extracting its path from the configuration file
local conntrack_socket=$(awk '/^[ \t]*UNIX[ \t]*{/,/^[ \t]*}/ { if ($1 == "Path") { print $2 } }' $OCF_RESKEY_config)
[ -S "$conntrack_socket" ] && rc=$OCF_SUCCESS
if [ "$rc" -eq "$OCF_SUCCESS" ]; then
# conntrackd is running
# now see if it acceppts queries
if ! $OCF_RESKEY_binary -C $OCF_RESKEY_config -s > /dev/null 2>&1; then
rc=$OCF_ERR_GENERIC
ocf_exit_reason "conntrackd is running but not responding to queries"
fi
if conntrackd_is_master; then
rc=$OCF_RUNNING_MASTER
# Restore master setting on probes
if [ $OCF_RESKEY_CRM_meta_interval -eq 0 ]; then
conntrackd_set_master_score $master_score
fi
else
# Restore master setting on probes
if [ $OCF_RESKEY_CRM_meta_interval -eq 0 ]; then
conntrackd_set_master_score $slave_score
fi
fi
fi
return $rc
}
conntrackd_start() {
rc=$OCF_ERR_GENERIC
# Keep trying to start the resource;
# wait for the CRM to time us out if this fails
while :; do
conntrackd_monitor
status=$?
case "$status" in
$OCF_SUCCESS)
conntrackd_set_master_score $slave_score
# -n = request resync from the others
if ! $OCF_RESKEY_binary -C $OCF_RESKEY_config -n; then
ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -n failed during start."
rc=$OCF_ERR_GENERIC
else
rc=$OCF_SUCCESS
fi
break
;;
$OCF_NOT_RUNNING)
ocf_log info "Starting conntrackd"
$OCF_RESKEY_binary -C $OCF_RESKEY_config -d
;;
$OCF_RUNNING_MASTER)
ocf_log warn "conntrackd already in master mode, demoting."
ha_pseudo_resource $statefile stop
;;
$OCF_ERR_GENERIC)
ocf_exit_reason "conntrackd start failed"
rc=$OCF_ERR_GENERIC
break
;;
esac
done
return $rc
}
conntrackd_stop() {
rc=$OCF_ERR_GENERIC
# Keep trying to bring down the resource;
# wait for the CRM to time us out if this fails
while :; do
conntrackd_monitor
status=$?
case "$status" in
$OCF_SUCCESS|$OCF_ERR_GENERIC)
ocf_log info "Stopping conntrackd"
$OCF_RESKEY_binary -C $OCF_RESKEY_config -k
;;
$OCF_NOT_RUNNING)
rc=$OCF_SUCCESS
break
;;
$OCF_RUNNING_MASTER)
ocf_log warn "conntrackd still master"
;;
esac
done
return $rc
}
conntrackd_validate_all() {
check_binary "$OCF_RESKEY_binary"
if ! [ -e "$OCF_RESKEY_config" ]; then
ocf_exit_reason "Config FILE $OCF_RESKEY_config does not exist"
return $OCF_ERR_INSTALLED
fi
meta_expect_eq master-node-max 1
meta_expect_eq master-max 1
meta_expect_eq clone-node-max 1
return $OCF_SUCCESS
}
conntrackd_promote() {
rc=$OCF_SUCCESS
if ! conntrackd_is_master; then
# -c = Commit the external cache to the kernel
# -f = Flush internal and external cache
# -R = resync with the kernel table
# -B = send a bulk update on the line
for parm in c f R B; do
if ! $OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm; then
ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm failed during promote."
rc=$OCF_ERR_GENERIC
break
fi
done
ha_pseudo_resource $statefile start
conntrackd_set_master_score $master_score
fi
return $rc
}
conntrackd_demote() {
rc=$OCF_SUCCESS
if conntrackd_is_master; then
# -t = shorten kernel timers to remove zombies
# -n = request a resync from the others
for parm in t n; do
if ! $OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm; then
ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm failed during demote."
rc=$OCF_ERR_GENERIC
break
fi
done
ha_pseudo_resource $statefile stop
conntrackd_set_master_score $slave_score
fi
return $rc
}
conntrackd_notify() {
hostname=$(hostname)
# OCF_RESKEY_CRM_meta_notify_master_uname is a whitespace separated list of master hostnames
for master in $OCF_RESKEY_CRM_meta_notify_master_uname; do
# if we are the master and an instance was just started on another node:
# send a bulk update to allow failback
if [ "$hostname" = "$master" -a "$OCF_RESKEY_CRM_meta_notify_type" = "post" -a "$OCF_RESKEY_CRM_meta_notify_operation" = "start" -a "$OCF_RESKEY_CRM_meta_notify_start_uname" != "$hostname" ]; then
ocf_log info "Sending bulk update in post start to peers to allow failback"
$OCF_RESKEY_binary -C $OCF_RESKEY_config -B
fi
done
for tobepromoted in $OCF_RESKEY_CRM_meta_notify_promote_uname; do
# if there is a promote action to be executed on another node:
# send a bulk update to allow failback
if [ "$hostname" != "$tobepromoted" -a "$OCF_RESKEY_CRM_meta_notify_type" = "pre" -a "$OCF_RESKEY_CRM_meta_notify_operation" = "promote" ]; then
ocf_log info "Sending bulk update in pre promote to peers to allow failback"
$OCF_RESKEY_binary -C $OCF_RESKEY_config -B
fi
done
}
conntrackd_usage() {
cat <<EOF
usage: $0 {start|stop|promote|demote|monitor|validate-all|meta-data}
Expects to have a fully populated OCF RA-compliant environment set.
EOF
}
statefile=conntrackd.${OCF_RESOURCE_INSTANCE//:[0-9]*}.master
master_score=1000
slave_score=100
if [ $# -ne 1 ]; then
conntrackd_usage
exit $OCF_ERR_ARGS
fi
case $__OCF_ACTION in
meta-data)
meta_data
exit $OCF_SUCCESS
;;
usage)
conntrackd_usage
exit $OCF_SUCCESS
esac
# Everything except usage and meta-data must pass the validate test
conntrackd_validate_all || exit
case $__OCF_ACTION in
start)
conntrackd_start
;;
stop)
conntrackd_stop
;;
promote)
conntrackd_promote
;;
demote)
conntrackd_demote
;;
status|monitor)
conntrackd_monitor
;;
notify)
conntrackd_notify
;;
validate-all)
;;
*)
conntrackd_usage
exit $OCF_ERR_UNIMPLEMENTED
esac
# exit code is the exit code (return code) of the last command (shell function)
diff --git a/heartbeat/dnsupdate b/heartbeat/dnsupdate.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/dnsupdate
rename to heartbeat/dnsupdate.in
index 399c6fdbd..1ecbadf18
--- a/heartbeat/dnsupdate
+++ b/heartbeat/dnsupdate.in
@@ -1,276 +1,276 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
#
# Support: users@clusterlabs.org
# License: GNU General Public License v2
#
# Copyright (c) 2014 SUSE Linux Products GmbH, Lars Marowsky-Brée
# All Rights Reserved.
#
#######################################################################
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
#######################################################################
# TODO:
# - Should setting CNAMEs be supported?
# - Should multiple A records be supported?
usage() {
cat <<-!
usage: $0 {start|stop|status|monitor|meta-data|validate-all}
!
}
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="dnsupdate">
<version>1.0</version>
<longdesc lang="en">
This resource agent manages IP take-over via dynamic DNS updates.
</longdesc>
<shortdesc lang="en">IP take-over via dynamic DNS update</shortdesc>
<parameters>
<parameter name="hostname" unique="1" required="1">
<longdesc lang="en">
The hostname whose IP address will need to be updated.
</longdesc>
<shortdesc lang="en">Hostname to update</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="ip" unique="0" required="1">
<longdesc lang="en">
IP address to set.
</longdesc>
<shortdesc lang="en">IP address to set</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="ttl" unique="0" required="0">
<longdesc lang="en">
Time to live, in seconds, for the DNS record. This
affects how soon DNS updates propagate. It should be
a reasonable compromise between update speed and DNS
server load.
If using booth, the ticket timeout is a good start.
</longdesc>
<shortdesc lang="en">TTL for the DNS record</shortdesc>
<content type="integer" default="300" />
</parameter>
<parameter name="keyfile" unique="0" required="0">
<longdesc lang="en">
The file containing the shared secret needed to update
the DNS record. Please see the nsupdate man page for
the exact syntax.
</longdesc>
<shortdesc lang="en">nsupdate key file</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="server" unique="0" required="0">
<longdesc lang="en">
Which DNS server to send these updates for. When no
server is provided, this defaults to the master server
for the correct zone.
</longdesc>
<shortdesc lang="en">DNS server to contact</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="serverport" unique="0" required="0">
<longdesc lang="en">
Port number on the DNS server.
Note: due to a limitation in the nsupdate command, this option will only
take effect if you also specify the DNS server!
</longdesc>
<shortdesc lang="en">Port number on the DNS server</shortdesc>
<content type="integer" default="53" />
</parameter>
<parameter name="nsupdate_opts" unique="0" required="0">
<longdesc lang="en">
Additional options to be passed to nsupdate.
</longdesc>
<shortdesc lang="en">Additional nsupdate options</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="unregister_on_stop" unique="0" required="0">
<longdesc lang="en">
Whether or not to actively remove records on stop. This is not needed
for normal operation, since the site taking over the IP address will
delete all previous records.
</longdesc>
<shortdesc lang="en">Remove A record on stop</shortdesc>
<content type="boolean" default="false" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="30s" />
<action name="stop" timeout="30s" />
<action name="status" depth="0" timeout="30s" interval="10s" />
<action name="monitor" depth="0" timeout="30s" interval="10s" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="5s" />
</actions>
</resource-agent>
END
}
dnsupdate_status() {
# The resource is considered active if the current IP
# address is returned as the only response.
local record=$(dig ${dig_opts} ${hostname}. A +short 2>/dev/null)
if [ "$record" = "$ip" ]; then
return $OCF_SUCCESS
fi
return $OCF_NOT_RUNNING
}
dnsupdate_monitor() {
if ocf_is_probe ; then
#
return $OCF_NOT_RUNNING
fi
dnsupdate_status
}
dnsupdate_start() {
if dnsupdate_status ; then
ocf_log info "$hostname already resolves to $ip"
return $OCF_SUCCESS
fi
ocf_log info "Updating DNS records for $hostname"
(
if [ -n "$dns_server" ]; then
echo "server ${dns_server} ${dns_serverport}"
fi
echo "update delete $hostname A"
echo "update add $hostname ${OCF_RESKEY_ttl} A $ip"
echo "send"
) | nsupdate ${nsupdate_opts}
dnsupdate_monitor
return $?
}
dnsupdate_stop() {
if ocf_is_true "${OCF_RESKEY_unregister_on_stop}" && dnsupdate_status ; then
ocf_log info "Unregistering $hostname with $ip from DNS server"
(
if [ -n "$dns_server" ]; then
echo "server ${dns_server} ${dns_serverport}"
fi
echo "update delete $hostname A $ip"
echo "send"
) | nsupdate ${nsupdate_opts}
dnsupdate_monitor
if [ $? -ne $OCF_NOT_RUNNING ]; then
ocf_log warn "Unregistering failed!"
# There's no point in invoking a stop failure
# here. If another site takes over the record,
# it'll delete all previous entries anyway.
fi
fi
return $OCF_SUCCESS
}
dnsupdate_validate() {
hostname=${OCF_RESKEY_hostname}
ip=${OCF_RESKEY_ip}
dig_opts=""
dns_server=${OCF_RESKEY_server}
: ${OCF_RESKEY_serverport:="53"}
dns_serverport=${OCF_RESKEY_serverport}
: ${OCF_RESKEY_ttl:="300"}
nsupdate_opts=${OCF_RESKEY_nsupdate_opts}
if [ -z "$nsupdate_opts" -a -n "$OCF_RESKEY_opts" ]; then
nsupdate_opts=${OCF_RESKEY_opts}
ocf_log warn "opts was never an advertised parameter, please use nsupdate_opts"
fi
if [ -z "$hostname" ]; then
ocf_log err "No hostname specified."
exit $OCF_ERR_CONFIGURED
fi
if [ -z "$ip" ]; then
ocf_log err "No IP specified."
exit $OCF_ERR_CONFIGURED
fi
if ! ocf_is_decimal $OCF_RESKEY_ttl ; then
ocf_log err "ttl $OCF_RESKEY_ttl is not valid"
exit $OCF_ERR_CONFIGURED
fi
if ! ocf_is_decimal $dns_serverport ; then
ocf_log err "serverport $dns_serverport is not valid"
exit $OCF_ERR_CONFIGURED
fi
dig_opts+=" -p ${dns_serverport}"
if [ -n "$dns_server" ]; then
dig_opts+=" @${dns_server}"
fi
if [ -n "$OCF_RESKEY_keyfile" ]; then
if [ ! -f ${OCF_RESKEY_keyfile} ]; then
ocf_log err "keyfile $OCF_RESKEY_keyfile does not exist"
exit $OCF_ERR_CONFIGURED
fi
nsupdate_opts+=" -k $OCF_RESKEY_keyfile"
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
check_binary dig
check_binary nsupdate
dnsupdate_validate
case $1 in
start) dnsupdate_start
;;
stop) dnsupdate_stop
;;
monitor) dnsupdate_monitor
;;
status) dnsupdate_status
;;
validate-all) # We've already run this
exit $OCF_SUCCESS
;;
*) usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit $?
diff --git a/heartbeat/eDir88 b/heartbeat/eDir88.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/eDir88
rename to heartbeat/eDir88.in
index afad0be22..eb740afcf
--- a/heartbeat/eDir88
+++ b/heartbeat/eDir88.in
@@ -1,460 +1,460 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# eDirectory Resource Agent (RA) for Heartbeat.
# This script is only compatible with eDirectory 8.8 and later
#
# Copyright (c) 2007 Novell Inc, Yan Fitterer
# 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.
#
#
# OCF parameters:
# OCF_RESKEY_eDir_config_file - full filename to instance configuration file
# OCF_RESKEY_eDir_monitor_ldap - Should we monitor LDAP (0/1 - 1 is true)
# OCF_RESKEY_eDir_monitor_idm - Should we monitor IDM (0/1 - 1 is true)
# OCF_RESKEY_eDir_jvm_initial_heap - Value of the DHOST_INITIAL_HEAP java env var
# OCF_RESKEY_eDir_jvm_max_heap - Value of the DHOST_MAX_HEAP java env var
# OCF_RESKEY_eDir_jvm_options - Value of the DHOST_OPTIONS java env var
###############################################################################
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
test -f /opt/novell/eDirectory/bin/ndspath &&
. /opt/novell/eDirectory/bin/ndspath 2>/dev/null >/dev/null
#######################################################################
usage() {
ME=$(basename "$0")
cat <<-EOFA
usage: $ME start|stop|status|monitor|validate-all
$ME manages an eDirectory instance as an HA resource.
The 'start' operation starts the instance.
The 'stop' operation stops the instance.
The 'status' operation reports if the instance is running.
The 'monitor' operation reports if the instance is running, and runs additional checks.
The 'validate-all' operation checks the validity of the arguments (environment variables).
EOFA
}
eDir_meta_data() {
cat <<-EOFB
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="eDir88">
<version>1.0</version>
<longdesc lang="en">
Resource script for managing an eDirectory instance. Manages a single instance
of eDirectory as an HA resource. The "multiple instances" feature or
eDirectory has been added in version 8.8. This script will not work for any
version of eDirectory prior to 8.8. This RA can be used to load multiple
eDirectory instances on the same host.
It is very strongly recommended to put eDir configuration files (as per the
eDir_config_file parameter) on local storage on each node. This is necessary for
this RA to be able to handle situations where the shared storage has become
unavailable. If the eDir configuration file is not available, this RA will fail,
and heartbeat will be unable to manage the resource. Side effects include
STONITH actions, unmanageable resources, etc...
Setting a high action timeout value is _very_ _strongly_ recommended. eDir
with IDM can take in excess of 10 minutes to start. If heartbeat times out
before eDir has had a chance to start properly, mayhem _WILL ENSUE_.
The LDAP module seems to be one of the very last to start. So this script will
take even longer to start on installations with IDM and LDAP if the monitoring
of IDM and/or LDAP is enabled, as the start command will wait for IDM and LDAP
to be available.
</longdesc>
<shortdesc lang="en">Manages a Novell eDirectory directory server</shortdesc>
<parameters>
<parameter name="eDir_config_file" unique="1" required="0">
<longdesc lang="en">
Path to configuration file for eDirectory instance.
</longdesc>
<shortdesc lang="en">eDir config file</shortdesc>
<content type="string" default="/etc/opt/novell/eDirectory/conf/nds.conf" />
</parameter>
<parameter name="eDir_monitor_ldap" required="0">
<longdesc lang="en">
Should we monitor if LDAP is running for the eDirectory instance?
</longdesc>
<shortdesc lang="en">eDir monitor ldap</shortdesc>
<content type="boolean" default="0" />
</parameter>
<parameter name="eDir_monitor_idm" required="0">
<longdesc lang="en">
Should we monitor if IDM is running for the eDirectory instance?
</longdesc>
<shortdesc lang="en">eDir monitor IDM</shortdesc>
<content type="boolean" default="0" />
</parameter>
<parameter name="eDir_jvm_initial_heap" required="0">
<longdesc lang="en">
Value for the DHOST_INITIAL_HEAP java environment variable. If unset, java defaults will be used.
</longdesc>
<shortdesc lang="en">DHOST_INITIAL_HEAP value</shortdesc>
<content type="integer" default="" />
</parameter>
<parameter name="eDir_jvm_max_heap" required="0">
<longdesc lang="en">
Value for the DHOST_MAX_HEAP java environment variable. If unset, java defaults will be used.
</longdesc>
<shortdesc lang="en">DHOST_MAX_HEAP value</shortdesc>
<content type="integer" default="" />
</parameter>
<parameter name="eDir_jvm_options" required="0">
<longdesc lang="en">
Value for the DHOST_OPTIONS java environment variable. If unset, original values will be used.
</longdesc>
<shortdesc lang="en">DHOST_OPTIONS value</shortdesc>
<content type="string" default="" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="600s" />
<action name="stop" timeout="600s" />
<action name="monitor" timeout="60s" interval="30s" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="5s" />
</actions>
</resource-agent>
EOFB
return $OCF_SUCCESS
}
#
# eDir_start: Start eDirectory instance
#
eDir_start() {
if eDir_status ; then
ocf_log info "eDirectory is already running ($NDSCONF)."
return $OCF_SUCCESS
fi
# Start eDirectory instance
if [ -n "$OCF_RESKEY_eDir_jvm_initial_heap" ]; then
DHOST_JVM_INITIAL_HEAP=$OCF_RESKEY_eDir_jvm_initial_heap
export DHOST_JVM_INITIAL_HEAP
fi
if [ -n "$OCF_RESKEY_eDir_jvm_max_heap" ]; then
DHOST_JVM_MAX_HEAP=$OCF_RESKEY_eDir_jvm_max_heap
export DHOST_JVM_MAX_HEAP
fi
if [ -n "$OCF_RESKEY_eDir_jvm_options" ]; then
DHOST_JVM_OPTIONS=$OCF_RESKEY_eDir_jvm_options
export DHOST_JVM_OPTIONS
fi
$NDSMANAGE start --config-file "$NDSCONF" > /dev/null 2>&1
if [ $? -eq 0 ]; then
ocf_log info "eDir start command sent for $NDSCONF."
else
echo "ERROR: Can't start eDirectory for $NDSCONF."
return $OCF_ERR_GENERIC
fi
CNT=0
while ! eDir_monitor ; do
# Apparently, LDAP will only start after all other services
# Startup time can be in excess of 10 minutes.
# Leave a very long heartbeat timeout on the start action
# We're relying on heartbeat to bail us out...
let CNT=$CNT+1
ocf_log info "eDirectory start waiting for ${CNT}th retry for $NDSCONF."
sleep 10
done
ocf_log info "eDirectory start verified for $NDSCONF."
return $OCF_SUCCESS
}
#
# eDir_stop: Stop eDirectory instance
# This action is written in such a way that even when run
# on a node were things are broken (no binaries, no config
# etc...) it will try to stop any running ndsd processes
# and report success if none are running.
#
eDir_stop() {
if ! eDir_status ; then
return $OCF_SUCCESS
fi
$NDSMANAGE stop --config-file "$NDSCONF" >/dev/null 2>&1
if eDir_status ; then
# eDir failed to stop.
ocf_log err "eDirectory instance failed to stop for $NDSCONF"
return $OCF_ERR_GENERIC
else
ocf_log info "eDirectory stop verified for $NDSCONF."
return $OCF_SUCCESS
fi
}
#
# eDir_status: is eDirectory instance up ?
#
eDir_status() {
if [ ! -r "$NDSCONF" ] ; then
ocf_log err "Config file missing ($NDSCONF)."
exit $OCF_ERR_GENERIC
fi
# Find how many ndsd processes have open listening sockets
# with the IP of this eDir instance
IFACE=$(grep -i "n4u.server.interfaces" $NDSCONF | cut -f2 -d= | tr '@' ':')
if [ -z "$IFACE" ] ; then
ocf_log err "Cannot retrieve interfaces from $NDSCONF. eDirectory may not be correctly configured."
exit $OCF_ERR_GENERIC
fi
# In case of multiple IP's split into an array
# and check all of them
IFS=', ' read -a IFACE2 <<< "$IFACE"
ocf_log debug "Found ${#IFACE2[@]} interfaces from $NDSCONF."
counter=${#IFACE2[@]}
for IFACE in "${IFACE2[@]}"
do
ocf_log debug "Checking ndsd instance for $IFACE"
NDSD_SOCKS=$(netstat -ntlp | grep -ce "$IFACE.*ndsd")
if [ "$NDSD_SOCKS" -eq 1 ] ; then
let counter=counter-1
ocf_log debug "Found ndsd instance for $IFACE"
elif [ "$NDSD_SOCKS" -gt 1 ] ; then
ocf_log err "More than 1 ndsd listening socket matched. Likely misconfiguration of eDirectory."
exit $OCF_ERR_GENERIC
fi
done
if [ $counter -eq 0 ] ; then
# Correct ndsd instance is definitely running
ocf_log debug "All ndsd instances found."
return 0;
elif [ $counter -lt ${#IFACE2[@]} ]; then
ocf_log err "Only some ndsd listening sockets matched, something is very wrong."
exit $OCF_ERR_GENERIC
fi
# No listening socket. Make sure we don't have the process running...
PIDDIR=$(grep -i "n4u.server.vardir" "$NDSCONF" | cut -f2 -d=)
if [ -z "$PIDDIR" ] ; then
ocf_log err "Cannot get vardir from nds config ($NDSCONF). Probable eDir configuration error."
exit $OCF_ERR_GENERIC
fi
NDSD_PID=$(cat $PIDDIR/ndsd.pid 2>/dev/null)
if [ -z "$NDSD_PID" ] ; then
# PID file unavailable or empty.
# This will happen if the PIDDIR is not available
# on this node at this time.
return 1
fi
RC=$(ps -p "$NDSD_PID" | grep -c ndsd)
if [ "$RC" -gt 0 ] ; then
# process found but no listening socket. ndsd likely not operational
ocf_log err "ndsd process found, but no listening socket. Something's gone wrong ($NDSCONF)"
exit $OCF_ERR_GENERIC
fi
ocf_log debug "ndsd instance is not running, but no other error detected."
return 1
}
#
# eDir_monitor: Do more in-depth checks to ensure that eDirectory is fully functional
# LDAP and IDM checks are only done if reqested.
#
#
eDir_monitor() {
if ! eDir_status ; then
ocf_log info "eDirectory instance is down ($NDSCONF)"
return $OCF_NOT_RUNNING
fi
# We know the right ndsd is running locally, check health
$NDSSTAT --config-file "$NDSCONF" >/dev/null 2>&1
if [ $? -ne 0 ] ; then
return 1
fi
# Monitor IDM first, as it will start before LDAP
if [ $MONITOR_IDM -eq 1 ]; then
RET=$($NDSTRACE --config-file "$NDSCONF" -c modules | egrep -i '^vrdim.*Running' | awk '{print $1}')
if [ "$RET" != "vrdim" ]; then
ocf_log err "eDirectory IDM engine isn't running ($NDSCONF)."
return $OCF_ERR_GENERIC
fi
fi
if [ $MONITOR_LDAP -eq 1 ] ; then
$NDSNLDAP -c --config-file "$NDSCONF" >/dev/null 2>&1
if [ $? -ne 0 ]; then
ocf_log err "eDirectory LDAP server isn't running ($NDSCONF)."
return $OCF_ERR_GENERIC
fi
fi
ocf_log debug "eDirectory monitor success ($NDSCONF)"
return $OCF_SUCCESS
}
#
# eDir_validate: Validate environment
#
eDir_validate() {
declare rc=$OCF_SUCCESS
# Script must be run as root
if ! ocf_is_root ; then
ocf_log err "$0 must be run as root"
rc=$OCF_ERR_GENERIC
fi
# ndsmanage must be available and runnable
check_binary $NDSMANAGE
# ndsstat must be available and runnable
check_binary $NDSSTAT
# Config file must be readable
if [ ! -r "$NDSCONF" ] ; then
ocf_log err "eDirectory configuration file [$NDSCONF] is not readable"
rc=$OCF_ERR_ARGS
fi
# monitor_ldap must be unambiguously resolvable to a truth value
MONITOR_LDAP=$(echo "$MONITOR_LDAP" | tr [A-Z] [a-z])
case "$MONITOR_LDAP" in
yes|true|1)
MONITOR_LDAP=1;;
no|false|0)
MONITOR_LDAP=0;;
*)
ocf_log err "Configuration parameter eDir_monitor_ldap has invalid value [$MONITOR_LDAP]"
rc=$OCF_ERR_ARGS;;
esac
# monitor_idm must be unambiguously resolvable to a truth value
MONITOR_IDM=$(echo "$MONITOR_IDM" | tr [A-Z] [a-z])
case "$MONITOR_IDM" in
yes|true|1)
MONITOR_IDM=1;;
no|false|0)
MONITOR_IDM=0;;
*)
ocf_log err "Configuration parameter eDir_monitor_idm has invalid value [$MONITOR_IDM]"
rc=$OCF_ERR_ARGS;;
esac
# eDir_jvm_initial_heap must be blank or numeric
if [ -n "$OCF_RESKEY_eDir_jvm_initial_heap" ] ; then
if ! ocf_is_decimal "$OCF_RESKEY_eDir_jvm_initial_heap" ; then
ocf_log err "Configuration parameter eDir_jvm_initial_heap has invalid" \
"value [$OCF_RESKEY_eDir_jvm_initial_heap]"
rc=$OCF_ERR_ARGS
fi
fi
# eDir_jvm_max_heap must be blank or numeric
if [ -n "$OCF_RESKEY_eDir_jvm_max_heap" ] ; then
if ! ocf_is_decimal "$OCF_RESKEY_eDir_jvm_max_heap" ; then
ocf_log err "Configuration parameter eDir_jvm_max_heap has invalid" \
"value [$OCF_RESKEY_eDir_jvm_max_heap]"
rc=$OCF_ERR_ARGS
fi
fi
if [ $rc -ne $OCF_SUCCESS ] ; then
ocf_log err "Invalid environment"
fi
return $rc
}
#
# Start of main logic
#
ocf_log debug "$0 started with arguments \"$*\""
NDSBASE=/opt/novell/eDirectory
NDSNLDAP=$NDSBASE/sbin/nldap
NDSMANAGE=$NDSBASE/bin/ndsmanage
NDSSTAT=$NDSBASE/bin/ndsstat
NDSTRACE=$NDSBASE/bin/ndstrace
NDSCONF=${OCF_RESKEY_eDir_config_file:-/etc/opt/novell/eDirectory/conf/nds.conf}
MONITOR_LDAP=${OCF_RESKEY_eDir_monitor_ldap:-0}
MONITOR_IDM=${OCF_RESKEY_eDir_monitor_idm:-0}
# What kind of method was invoked?
case "$1" in
validate-all) eDir_validate; exit $?;;
meta-data) eDir_meta_data; exit $OCF_SUCCESS;;
status) if eDir_status ; then
ocf_log info "eDirectory instance is up ($NDSCONF)"
exit $OCF_SUCCESS
else
ocf_log info "eDirectory instance is down ($NDSCONF)"
exit $OCF_NOT_RUNNING
fi;;
start) : skip;;
stop) : skip;;
monitor) : skip;;
usage) usage; exit $OCF_SUCCESS;;
*) ocf_log err "Invalid argument [$1]"
usage; exit $OCF_ERR_ARGS;;
esac
# From now on we must have a valid environment to continue.
# stop goes in the list above as it should ideally be able to
# clean up after a start that failed due to bad args
eDir_validate
RC=$?
if [ $RC -ne $OCF_SUCCESS ]; then
exit $RC
fi
case "$1" in
start) eDir_start;;
stop) eDir_stop;;
monitor) eDir_monitor;;
esac
exit $?
diff --git a/heartbeat/fio b/heartbeat/fio.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/fio
rename to heartbeat/fio.in
index 0380be15e..68a123983
--- a/heartbeat/fio
+++ b/heartbeat/fio.in
@@ -1,172 +1,172 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# fio RA
#
# Copyright (c) 2010 SUSE Linux Products GmbH, 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.
#
#######################################################################
# 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="fio">
<version>1.0</version>
<longdesc lang="en">
fio is a generic I/O load generator. This RA allows start/stop of fio
instances to simulate load on a cluster without configuring complex
services.
</longdesc>
<shortdesc lang="en">fio IO load generator</shortdesc>
<parameters>
<parameter name="args">
<longdesc lang="en">
Arguments to the fio client. Minimally, this should be a (list of) job
descriptions to run.
</longdesc>
<shortdesc lang="en">fio arguments</shortdesc>
<content type="string" default="" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="60s" />
<action name="stop" timeout="60s" />
<action name="monitor" timeout="60s" interval="10s" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="20s" />
</actions>
</resource-agent>
END
}
#######################################################################
fio_usage() {
cat <<END
usage: $0 {start|stop|monitor|validate-all|meta-data}
END
}
fio_start() {
fio_monitor ; rc=$?
if [ $rc = $OCF_SUCCESS ]; then
ocf_log info "fio already running."
exit $OCF_SUCCESS
fi
if [ $rc != $OCF_NOT_RUNNING ]; then
ocf_log info "fio apparently dead; cleaning up before restart"
fio_stop
fi
fio $OCF_RESKEY_args >/dev/null 2>&1 </dev/null &
fio_pid=`jobs -p`
echo $fio_pid >${fio_state_file}
ocf_log info "fio started as pid=$fio_pid"
exit $OCF_SUCCESS
}
fio_stop() {
for sig in SIGINT SIGTERM SIGKILL ; do
fio_monitor ; rc=$?
case $rc in
$OCF_NOT_RUNNING)
ocf_log info "fio already stopped."
exit $OCF_SUCCESS
;;
$OCF_ERR_GENERIC)
rm $fio_state_file
ocf_log info "fio stopped and cleaned up."
exit $OCF_SUCCESS
;;
$OCF_SUCCESS)
if [ -n "$fio_pid" ]; then
ocf_log info "Sending $sig to fio (pid=$fio_pid)"
kill -$sig $fio_pid
sleep 3
continue
fi
ocf_log err "Internal logic failure in fio RA."
;;
*) ocf_log err "Internal logic failure in fio RA."
;;
esac
done
ocf_log err "fio did not stop! Perhaps hung on IO?"
exit $OCF_ERR_GENERIC
}
fio_monitor() {
fio_state_file="${HA_RSCTMP}/fio-${OCF_RESOURCE_INSTANCE}.state"
if [ ! -e $fio_state_file ]; then
return $OCF_NOT_RUNNING
fi
fio_pid=`cat $fio_state_file`
if [ -z "$fio_pid" ]; then
ocf_log err "State file found, but empty. Assuming stopped."
return $OCF_NOT_RUNNING
fi
ps=`ps h -o comm $fio_pid 2>&1`
if [ "$ps" != "fio" ]; then
fio_pid=""
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
fio_validate() {
return $OCF_SUCCESS
}
case $__OCF_ACTION in
meta-data) meta_data
exit $OCF_SUCCESS
;;
validate-all) fio_validate;;
usage|help) fio_usage
exit $OCF_SUCCESS
;;
esac
ocf_is_probe || check_binary fio
case $__OCF_ACTION in
start) fio_start;;
stop) fio_stop;;
monitor) fio_monitor;;
*) fio_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/heartbeat/iSCSILogicalUnit b/heartbeat/iSCSILogicalUnit.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/iSCSILogicalUnit
rename to heartbeat/iSCSILogicalUnit.in
index 9286b4071..5838c8738
--- a/heartbeat/iSCSILogicalUnit
+++ b/heartbeat/iSCSILogicalUnit.in
@@ -1,739 +1,739 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
#
# iSCSILogicalUnit OCF RA. Exports and manages iSCSI Logical Units.
#
# (c) 2013 LINBIT, Lars Ellenberg
# (c) 2009-2010 Florian Haas, Dejan Muhamedagic,
# and Linux-HA contributors
#
#
# 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
# Defaults
# Set a default implementation based on software installed
if have_binary ietadm; then
OCF_RESKEY_implementation_default="iet"
elif have_binary tgtadm; then
OCF_RESKEY_implementation_default="tgt"
elif have_binary lio_node; then
OCF_RESKEY_implementation_default="lio"
elif have_binary targetcli; then
OCF_RESKEY_implementation_default="lio-t"
fi
: ${OCF_RESKEY_implementation=${OCF_RESKEY_implementation_default}}
# Use a default SCSI ID and SCSI SN that is unique across the cluster,
# and persistent in the event of resource migration.
# SCSI IDs are limited to 24 bytes, but only 16 bytes are known to be
# supported by all iSCSI implementations this RA cares about. Thus,
# for a default, use the first 16 characters of
# $OCF_RESOURCE_INSTANCE.
OCF_RESKEY_scsi_id_default="${OCF_RESOURCE_INSTANCE:0:16}"
: ${OCF_RESKEY_scsi_id=${OCF_RESKEY_scsi_id_default}}
# To have a reasonably unique default SCSI SN, use the first 8 bytes
# of an MD5 hash of of $OCF_RESOURCE_INSTANCE
sn=`echo -n "${OCF_RESOURCE_INSTANCE}" | md5sum | sed -e 's/ .*//'`
OCF_RESKEY_scsi_sn_default=${sn:0:8}
: ${OCF_RESKEY_scsi_sn=${OCF_RESKEY_scsi_sn_default}}
# set 0 as a default value for lio iblock device number
OCF_RESKEY_lio_iblock_default=0
OCF_RESKEY_lio_iblock=${OCF_RESKEY_lio_iblock:-$OCF_RESKEY_lio_iblock_default}
## tgt specifics
# tgt has "backing store type" and "backing store open flags",
# as well as device-type.
#
# suggestions how to make this generic accross all supported implementations?
# how should they be named, how should they be mapped to implementation specifics?
#
# OCF_RESKEY_tgt_bstype
# OCF_RESKEY_tgt_bsoflags
# OCF_RESKEY_tgt_bsopts
# OCF_RESKEY_tgt_device_type
# targetcli: iSCSITarget and iSCSILogicalUnit must use the same lockfile
TARGETLOCKFILE=${HA_RSCTMP}/targetcli.lock
#######################################################################
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="iSCSILogicalUnit">
<version>0.9</version>
<longdesc lang="en">
Manages iSCSI Logical Unit. An iSCSI Logical unit is a subdivision of
an SCSI Target, exported via a daemon that speaks the iSCSI protocol.
</longdesc>
<shortdesc lang="en">Manages iSCSI Logical Units (LUs)</shortdesc>
<parameters>
<parameter name="implementation" required="0" unique="0">
<longdesc lang="en">
The iSCSI target daemon implementation. Must be one of "iet", "tgt",
"lio", or "lio-t". If unspecified, an implementation is selected based on the
availability of management utilities, with "iet" being tried first,
then "tgt", then "lio", then "lio-t".
</longdesc>
<shortdesc lang="en">iSCSI target daemon implementation</shortdesc>
<content type="string" default="${OCF_RESKEY_implementation_default}"/>
</parameter>
<parameter name="target_iqn" required="1" unique="0">
<longdesc lang="en">
The iSCSI Qualified Name (IQN) that this Logical Unit belongs to.
</longdesc>
<shortdesc lang="en">iSCSI target IQN</shortdesc>
<content type="string" />
</parameter>
<parameter name="lun" required="1" unique="0">
<longdesc lang="en">
The Logical Unit number (LUN) exposed to initiators.
</longdesc>
<shortdesc lang="en">Logical Unit number (LUN)</shortdesc>
<content type="integer" />
</parameter>
<parameter name="path" required="1" unique="0">
<longdesc lang="en">
The path to the block device exposed. Some implementations allow this
to be a regular file, too.
</longdesc>
<shortdesc lang="en">Block device (or file) path</shortdesc>
<content type="string" />
</parameter>
<parameter name="scsi_id" required="0" unique="1">
<longdesc lang="en">
The SCSI ID to be configured for this Logical Unit. The default
is the resource name, truncated to 24 bytes.
</longdesc>
<shortdesc lang="en">SCSI ID</shortdesc>
<content type="string" default="${OCF_RESKEY_scsi_id_default}"/>
</parameter>
<parameter name="scsi_sn" required="0" unique="1">
<longdesc lang="en">
The SCSI serial number to be configured for this Logical Unit.
The default is a hash of the resource name, truncated to 8 bytes.
</longdesc>
<shortdesc lang="en">SCSI serial number</shortdesc>
<content type="string" default="${OCF_RESKEY_scsi_sn_default}"/>
</parameter>
<parameter name="emulate_tpu" required="0" unique="0">
<longdesc lang="en">
The SCSI UNMAP command to be configured for this Logical Unit.
Setting this integer to 1 will enable TPU IOCTL emulation.
</longdesc>
<shortdesc lang="en">SCSI UNMAP (for TRIM / DISCARD)</shortdesc>
<content type="integer" />
</parameter>
<parameter name="emulate_3pc" required="0" unique="0">
<longdesc lang="en">
The SCSI EXTENDED COPY command to be configured for this Logical Unit.
Setting this integer to 1 will enable 3PC IOCTL emulation.
</longdesc>
<shortdesc lang="en">SCSI extended write</shortdesc>
<content type="integer" />
</parameter>
<parameter name="emulate_caw" required="0" unique="0">
<longdesc lang="en">
The SCSI Compare and Write command to be configured for this Logical Unit.
Setting this integer to 1 will enable CAW IOCTL emulation.
</longdesc>
<shortdesc lang="en">SCSI compare and write</shortdesc>
<content type="integer" />
</parameter>
<parameter name="vendor_id" required="0" unique="0">
<longdesc lang="en">
The SCSI vendor ID to be configured for this Logical Unit.
</longdesc>
<shortdesc lang="en">SCSI vendor ID</shortdesc>
<content type="string" />
</parameter>
<parameter name="product_id" required="0" unique="0">
<longdesc lang="en">
The SCSI product ID to be configured for this Logical Unit.
</longdesc>
<shortdesc lang="en">SCSI product ID</shortdesc>
<content type="string" />
</parameter>
<parameter name="tgt_bstype" required="0" unique="0">
<longdesc lang="en">
TGT specific backing store type. If you want to use aio,
make sure your tgtadm is built against libaio.
See tgtadm(8).
</longdesc>
<shortdesc lang="en">TGT backing store type</shortdesc>
<content type="string" />
</parameter>
<parameter name="tgt_bsoflags" required="0" unique="0">
<longdesc lang="en">
TGT specific backing store open flags (direct|sync).
See tgtadm(8).
</longdesc>
<shortdesc lang="en">TGT backing store open flags</shortdesc>
<content type="string" />
</parameter>
<parameter name="tgt_bsopts" required="0" unique="0">
<longdesc lang="en">
TGT specific backing store options.
See tgtadm(8).
</longdesc>
<shortdesc lang="en">TGT backing store options</shortdesc>
<content type="string" />
</parameter>
<parameter name="tgt_device_type" required="0" unique="0">
<longdesc lang="en">
TGT specific device type.
See tgtadm(8).
</longdesc>
<shortdesc lang="en">TGT device type</shortdesc>
<content type="string" />
</parameter>
<parameter name="additional_parameters" required="0" unique="0">
<longdesc lang="en">
Additional LU parameters. A space-separated list of "name=value" pairs
which will be passed through to the iSCSI daemon's management
interface. The supported parameters are implementation
dependent. Neither the name nor the value may contain whitespace.
</longdesc>
<shortdesc lang="en">List of iSCSI LU parameters</shortdesc>
<content type="string" />
</parameter>
<parameter name="allowed_initiators" required="0" unique="0">
<longdesc lang="en">
Allowed initiators. A space-separated list of initiators allowed to
connect to this lun. Initiators may be listed in any syntax
the target implementation allows. If this parameter is empty or
not set, access to this lun will not be allowed from any initiator,
if target is not in demo mode.
This parameter is only necessary when using LIO.
</longdesc>
<shortdesc lang="en">List of iSCSI initiators allowed to connect
to this lun.</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="lio_iblock" required="0" unique="0">
<longdesc lang="en">
LIO iblock device name, a number starting from 0.
Using distinct values here avoids a warning in LIO "LEGACY: SHARED HBA";
and it is necessary when using multiple LUNs started at the same time
(eg. on node failover) to prevent a race condition in tcm_core on mkdir()
in /sys/kernel/config/target/core/.
</longdesc>
<shortdesc lang="en">LIO iblock device number</shortdesc>
<content type="integer" default="0"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="10s" />
<action name="stop" timeout="10s" />
<action name="status" timeout="10s" interval="10s" depth="0" />
<action name="monitor" timeout="10s" interval="10s" depth="0" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="10s" />
</actions>
</resource-agent>
END
}
#######################################################################
iSCSILogicalUnit_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
}
iSCSILogicalUnit_start() {
iSCSILogicalUnit_monitor
if [ $? = $OCF_SUCCESS ]; then
return $OCF_SUCCESS
fi
local params
case $OCF_RESKEY_implementation in
iet)
params="Path=${OCF_RESKEY_path}"
# use blockio if path points to a block device, fileio
# otherwise.
if [ -b "${OCF_RESKEY_path}" ]; then
params="${params} Type=blockio"
else
params="${params} Type=fileio"
fi
# in IET, we have to set LU parameters on creation
if [ -n "${OCF_RESKEY_scsi_id}" ]; then
params="${params} ScsiId=${OCF_RESKEY_scsi_id}"
fi
if [ -n "${OCF_RESKEY_scsi_sn}" ]; then
params="${params} ScsiSN=${OCF_RESKEY_scsi_sn}"
fi
params="${params} ${OCF_RESKEY_additional_parameters}"
ocf_run ietadm --op new \
--tid=${TID} \
--lun=${OCF_RESKEY_lun} \
--params ${params// /,} || exit $OCF_ERR_GENERIC
;;
tgt)
# tgt requires that we create the LU first, then set LU
# parameters
params=""
local var
local envar
for var in scsi_id scsi_sn vendor_id product_id; do
envar="OCF_RESKEY_${var}"
if [ -n "${!envar}" ]; then
params="${params} ${var}=${!envar}"
fi
done
params="${params} ${OCF_RESKEY_additional_parameters}"
# cleanup: tgt (as of tgtadm version 1.0.24) does not like an explicit "bsoflags=direct"
# when used with "bstype=aio" (which always uses O_DIRECT)
[[ $OCF_RESKEY_tgt_bstype/$OCF_RESKEY_tgt_bsoflags = "aio/direct" ]] && OCF_RESKEY_tgt_bsoflags=""
tgt_args=""
[[ $OCF_RESKEY_tgt_bstype ]] && tgt_args="$tgt_args --bstype=$OCF_RESKEY_tgt_bstype"
[[ $OCF_RESKEY_tgt_bsoflags ]] && tgt_args="$tgt_args --bsoflags=$OCF_RESKEY_tgt_bsoflags"
[[ $OCF_RESKEY_tgt_bsopts ]] && tgt_args="$tgt_args --bsopts=$OCF_RESKEY_tgt_bsopts"
[[ $OCF_RESKEY_tgt_device_type ]] && tgt_args="$tgt_args --device-type=$OCF_RESKEY_tgt_device_type"
ocf_run tgtadm --lld iscsi --op new --mode logicalunit \
--tid=${TID} \
--lun=${OCF_RESKEY_lun} \
$tgt_args \
--backing-store ${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC
if [ -z "$params" ]; then
return $OCF_SUCCESS
else
ocf_run tgtadm --lld iscsi --op update --mode logicalunit \
--tid=${TID} \
--lun=${OCF_RESKEY_lun} \
--params ${params// /,} || exit $OCF_ERR_GENERIC
fi
;;
lio)
# For lio, we first have to create a target device, then
# add it to the Target Portal Group as an LU.
block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/udev_path"
if [ ! -e "${block_configfs_path}" ]; then
ocf_run tcm_node --createdev=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} \
${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC
elif [ -e "$block_configfs_path" ] && [ $(cat "$block_configfs_path") != "${OCF_RESKEY_path}" ]; then
ocf_exit_reason "Existing iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} has incorrect path: $(cat "$block_configfs_path") != ${OCF_RESKEY_path}"
exit $OCF_ERR_GENERIC
else
ocf_log info "iscsi iblock already exists: ${block_configfs_path}"
fi
if [ -n "${OCF_RESKEY_scsi_sn}" ]; then
ocf_run tcm_node --setunitserial=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} \
${OCF_RESKEY_scsi_sn} || exit $OCF_ERR_GENERIC
fi
lun_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/${OCF_RESOURCE_INSTANCE}/udev_path"
if [ ! -e "${lun_configfs_path}" ]; then
ocf_run lio_node --addlun=${OCF_RESKEY_target_iqn} 1 ${OCF_RESKEY_lun} \
${OCF_RESOURCE_INSTANCE} iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC
else
ocf_log info "iscsi lun already exists: ${lun_configfs_path}"
fi
if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then
for initiator in ${OCF_RESKEY_allowed_initiators}; do
acl_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/acls/${initiator}/lun_${OCF_RESKEY_lun}"
if [ ! -e "${acl_configfs_path}" ]; then
ocf_run lio_node --addlunacl=${OCF_RESKEY_target_iqn} 1 \
${initiator} ${OCF_RESKEY_lun} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC
else
ocf_log info "iscsi acl already exists: ${acl_configfs_path}"
fi
done
fi
;;
lio-t)
ocf_take_lock $TARGETLOCKFILE
ocf_release_lock_on_exit $TARGETLOCKFILE
iblock_attrib_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/attrib"
# For lio, we first have to create a target device, then
# add it to the Target Portal Group as an LU.
ocf_run targetcli /backstores/block create name=${OCF_RESOURCE_INSTANCE} dev=${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC
if [ -n "${OCF_RESKEY_scsi_sn}" ]; then
echo ${OCF_RESKEY_scsi_sn} > /sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/wwn/vpd_unit_serial
fi
ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/luns create /backstores/block/${OCF_RESOURCE_INSTANCE} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC
if $(ip a | grep -q inet6); then
ocf_run -q targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/portals delete 0.0.0.0 3260
ocf_run -q targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/portals create ::0
fi
if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then
for initiator in ${OCF_RESKEY_allowed_initiators}; do
ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls create ${initiator} add_mapped_luns=False || exit $OCF_ERR_GENERIC
ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls/${initiator} create ${OCF_RESKEY_lun} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC
done
fi
if [ -n "${OCF_RESKEY_emulate_tpu}" ]; then
echo ${OCF_RESKEY_emulate_tpu} > ${iblock_attrib_path}/emulate_tpu || exit $OCF_ERR_GENERIC
fi
if [ -n "${OCF_RESKEY_emulate_3pc}" ]; then
echo ${OCF_RESKEY_emulate_3pc} > ${iblock_attrib_path}/emulate_3pc || exit $OCF_ERR_GENERIC
fi
if [ -n "${OCF_RESKEY_emulate_caw}" ]; then
echo ${OCF_RESKEY_emulate_caw} > ${iblock_attrib_path}/emulate_caw || exit $OCF_ERR_GENERIC
fi
;;
esac
# Force the monitor operation to pass before start is considered a success.
iSCSILogicalUnit_monitor
}
iSCSILogicalUnit_stop() {
iSCSILogicalUnit_monitor
if [ $? -eq $OCF_NOT_RUNNING ]; then
return $OCF_SUCCESS
fi
case $OCF_RESKEY_implementation in
iet)
# IET allows us to remove LUs while they are in use
ocf_run ietadm --op delete \
--tid=${TID} \
--lun=${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC
;;
tgt)
# tgt will fail to remove an LU while it is in use,
# but at the same time does not allow us to
# selectively shut down a connection that is using a
# specific LU. Thus, we need to loop here until tgtd
# decides that the LU is no longer in use, or we get
# timed out by the LRM.
while ! ocf_run -warn tgtadm --lld iscsi --op delete --mode logicalunit \
--tid ${TID} \
--lun=${OCF_RESKEY_lun}; do
sleep 1
done
;;
lio)
acls_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/acls"
for initiatorpath in ${acls_configfs_path}/*; do
initiator=$(basename "${initiatorpath}")
if [ -e "${initiatorpath}/lun_${OCF_RESKEY_lun}" ]; then
ocf_log info "deleting acl at ${initiatorpath}/lun_${OCF_RESKEY_lun}"
ocf_run lio_node --dellunacl=${OCF_RESKEY_target_iqn} 1 \
${initiator} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC
fi
done
lun_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/"
if [ -e "${lun_configfs_path}" ]; then
ocf_run lio_node --dellun=${OCF_RESKEY_target_iqn} 1 ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC
fi
block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/udev_path"
if [ -e "${block_configfs_path}" ]; then
ocf_run tcm_node --freedev=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC
fi
;;
lio-t)
ocf_take_lock $TARGETLOCKFILE
ocf_release_lock_on_exit $TARGETLOCKFILE
# "targetcli delete" will fail if the LUN is already
# gone. Log a warning and still push ahead.
ocf_run -warn targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/luns delete ${OCF_RESKEY_lun}
if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then
for initiator in ${OCF_RESKEY_allowed_initiators}; do
if targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls/${initiator} status | grep "Mapped LUNs: 0" >/dev/null ; then
ocf_run -warn targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls/ delete ${initiator}
fi
done
fi
# If we've proceeded down to here and we're unable to
# delete the backstore, then something is seriously
# wrong and we need to fail the stop operation
# (potentially causing fencing)
ocf_run targetcli /backstores/block delete ${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC
;;
esac
return $OCF_SUCCESS
}
iSCSILogicalUnit_monitor() {
if [ x"${OCF_RESKEY_tgt_bstype}" != x"rbd" ]; then
# If our backing device (or file) doesn't even exist, we're not running
[ -e ${OCF_RESKEY_path} ] || return $OCF_NOT_RUNNING
fi
case $OCF_RESKEY_implementation in
iet)
# Figure out and set the target ID
TID=`sed -ne "s/tid:\([[:digit:]]\+\) name:${OCF_RESKEY_target_iqn}$/\1/p" < /proc/net/iet/volume`
if [ -z "${TID}" ]; then
# Our target is not configured, thus we're not
# running.
return $OCF_NOT_RUNNING
fi
# FIXME: this looks for a matching LUN and path, but does
# not actually test for the correct target ID.
grep -E -q "[[:space:]]+lun:${OCF_RESKEY_lun}.*path:${OCF_RESKEY_path}$" /proc/net/iet/volume && return $OCF_SUCCESS
;;
tgt)
# Figure out and set the target ID
TID=`tgtadm --lld iscsi --op show --mode target \
| sed -ne "s/^Target \([[:digit:]]\+\): ${OCF_RESKEY_target_iqn}$/\1/p"`
if [ -z "$TID" ]; then
# Our target is not configured, thus we're not
# running.
return $OCF_NOT_RUNNING
fi
# This only looks for the backing store, but does not test
# for the correct target ID and LUN.
tgtadm --lld iscsi --op show --mode target \
| grep -E -q "[[:space:]]+Backing store.*: ${OCF_RESKEY_path}$" && return $OCF_SUCCESS
;;
lio)
configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/${OCF_RESOURCE_INSTANCE}/udev_path"
[ -e ${configfs_path} ] && [ `cat ${configfs_path}` = "${OCF_RESKEY_path}" ] && return $OCF_SUCCESS
# if we aren't activated, is a block device still left over?
block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/udev_path"
[ -e ${block_configfs_path} ] && ocf_log warn "existing block without an active lun: ${block_configfs_path}"
[ -e ${block_configfs_path} ] && return $OCF_ERR_GENERIC
;;
lio-t)
configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/*/udev_path"
[ -e ${configfs_path} ] && [ `cat ${configfs_path}` = "${OCF_RESKEY_path}" ] && return $OCF_SUCCESS
# if we aren't activated, is a block device still left over?
block_configfs_path="/sys/kernel/config/target/core/iblock_*/${OCF_RESOURCE_INSTANCE}/udev_path"
[ -e ${block_configfs_path} ] && ocf_log warn "existing block without an active lun: ${block_configfs_path}"
[ -e ${block_configfs_path} ] && return $OCF_ERR_GENERIC
;;
esac
return $OCF_NOT_RUNNING
}
iSCSILogicalUnit_validate() {
# Do we have all required variables?
for var in target_iqn lun path; do
param="OCF_RESKEY_${var}"
if [ -z "${!param}" ]; then
ocf_exit_reason "Missing resource parameter \"$var\"!"
exit $OCF_ERR_CONFIGURED
fi
done
# Is the configured implementation supported?
case "$OCF_RESKEY_implementation" in
"iet"|"tgt"|"lio"|"lio-t")
;;
"")
# The user didn't specify an implementation, and we were
# unable to determine one from installed binaries (in
# other words: no binaries for any supported
# implementation could be found)
ocf_exit_reason "Undefined iSCSI target implementation"
exit $OCF_ERR_INSTALLED
;;
*)
ocf_exit_reason "Unsupported iSCSI target implementation \"$OCF_RESKEY_implementation\"!"
exit $OCF_ERR_CONFIGURED
;;
esac
# Do we have a valid LUN?
case $OCF_RESKEY_implementation in
iet)
# IET allows LUN 0 and up
[ $OCF_RESKEY_lun -ge 0 ]
case $? in
0)
# OK
;;
1)
ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be a non-negative integer)."
exit $OCF_ERR_CONFIGURED
;;
*)
ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be an integer)."
exit $OCF_ERR_CONFIGURED
;;
esac
;;
tgt)
# tgt reserves LUN 0 for its own purposes
[ $OCF_RESKEY_lun -ge 1 ]
case $? in
0)
# OK
;;
1)
ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be greater than 0)."
exit $OCF_ERR_CONFIGURED
;;
*)
ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be an integer)."
exit $OCF_ERR_CONFIGURED
;;
esac
;;
esac
# Do we have any configuration parameters that the current
# implementation does not support?
local unsupported_params
local var
local envar
case $OCF_RESKEY_implementation in
iet)
# IET does not support setting the vendor and product ID
# (it always uses "IET" and "VIRTUAL-DISK")
unsupported_params="vendor_id product_id allowed_initiators lio_iblock tgt_bstype tgt_bsoflags tgt_bsopts tgt_device_type emulate_tpu emulate_3pc emulate_caw"
;;
tgt)
unsupported_params="allowed_initiators lio_iblock emulate_tpu emulate_3pc emulate_caw"
;;
lio)
unsupported_params="scsi_id vendor_id product_id tgt_bstype tgt_bsoflags tgt_bsopts tgt_device_type emulate_tpu emulate_3pc emulate_caw"
;;
lio-t)
unsupported_params="scsi_id vendor_id product_id tgt_bstype tgt_bsoflags tgt_bsopts tgt_device_type lio_iblock"
;;
esac
for var in ${unsupported_params}; do
envar=OCF_RESKEY_${var}
defvar=OCF_RESKEY_${var}_default
if [ -n "${!envar}" ]; then
if [[ "${!envar}" != "${!defvar}" ]];then
case "$__OCF_ACTION" in
start|validate-all)
ocf_log warn "Configuration parameter \"${var}\"" \
"is not supported by the iSCSI implementation" \
"and will be ignored." ;;
esac
fi
fi
done
if ! ocf_is_probe; then
# Do we have all required binaries?
case $OCF_RESKEY_implementation in
iet)
check_binary ietadm
;;
tgt)
check_binary tgtadm
;;
lio)
check_binary tcm_node
check_binary lio_node
;;
lio-t)
check_binary targetcli
;;
esac
# Is the required kernel functionality available?
case $OCF_RESKEY_implementation in
iet)
[ -d /proc/net/iet ]
if [ $? -ne 0 ]; then
ocf_log err "/proc/net/iet does not exist or is not a directory -- check if required modules are loaded."
exit $OCF_ERR_INSTALLED
fi
;;
tgt)
# tgt is userland only
;;
esac
fi
return $OCF_SUCCESS
}
case $1 in
meta-data)
meta_data
exit $OCF_SUCCESS
;;
usage|help)
iSCSILogicalUnit_usage
exit $OCF_SUCCESS
;;
esac
# Everything except usage and meta-data must pass the validate test
iSCSILogicalUnit_validate
case $__OCF_ACTION in
start) iSCSILogicalUnit_start;;
stop) iSCSILogicalUnit_stop;;
monitor|status) iSCSILogicalUnit_monitor;;
reload) ocf_log err "Reloading..."
iSCSILogicalUnit_start
;;
validate-all) ;;
*) iSCSILogicalUnit_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
rc=$?
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
exit $rc
diff --git a/heartbeat/iSCSITarget b/heartbeat/iSCSITarget.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/iSCSITarget
rename to heartbeat/iSCSITarget.in
index f6d6ae6a0..cc3db8f29
--- a/heartbeat/iSCSITarget
+++ b/heartbeat/iSCSITarget.in
@@ -1,690 +1,690 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
#
# iSCSITarget OCF RA. Exports and manages iSCSI targets.
#
# (c) 2009-2010 Florian Haas, Dejan Muhamedagic,
# and Linux-HA contributors
#
# 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
# Defaults
# Set a default implementation based on software installed
if have_binary ietadm; then
OCF_RESKEY_implementation_default="iet"
elif have_binary tgtadm; then
OCF_RESKEY_implementation_default="tgt"
elif have_binary lio_node; then
OCF_RESKEY_implementation_default="lio"
elif have_binary targetcli; then
OCF_RESKEY_implementation_default="lio-t"
fi
: ${OCF_RESKEY_implementation=${OCF_RESKEY_implementation_default}}
# Listen on 0.0.0.0:3260 by default
OCF_RESKEY_portals_default="0.0.0.0:3260"
: ${OCF_RESKEY_portals=${OCF_RESKEY_portals_default}}
# Lockfile, used for selecting a target ID
LOCKFILE=${HA_RSCTMP}/iSCSITarget-${OCF_RESKEY_implementation}.lock
# targetcli: iSCSITarget and iSCSILogicalUnit must use the same lockfile
TARGETLOCKFILE=${HA_RSCTMP}/targetcli.lock
#######################################################################
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="iSCSITarget">
<version>0.9</version>
<longdesc lang="en">
Manages iSCSI targets. An iSCSI target is a collection of SCSI Logical
Units (LUs) exported via a daemon that speaks the iSCSI protocol.
</longdesc>
<shortdesc lang="en">iSCSI target export agent</shortdesc>
<parameters>
<parameter name="implementation" required="0" unique="0">
<longdesc lang="en">
The iSCSI target daemon implementation. Must be one of "iet", "tgt",
"lio", or "lio-t". If unspecified, an implementation is selected based on the
availability of management utilities, with "iet" being tried first,
then "tgt", then "lio", then "lio-t".
</longdesc>
<shortdesc lang="en">Specifies the iSCSI target implementation
("iet", "tgt", "lio", or "lio-t").</shortdesc>
<content type="string" default="${OCF_RESKEY_implementation_default}"/>
</parameter>
<parameter name="iqn" required="1" unique="1">
<longdesc lang="en">
The target iSCSI Qualified Name (IQN). Should follow the conventional
"iqn.yyyy-mm.&lt;reversed domain name&gt;[:identifier]" syntax.
</longdesc>
<shortdesc lang="en">iSCSI target IQN</shortdesc>
<content type="string" />
</parameter>
<parameter name="tid" required="0" unique="1">
<longdesc lang="en">
The iSCSI target ID. Required for tgt.
</longdesc>
<shortdesc lang="en">iSCSI target ID</shortdesc>
<content type="integer" />
</parameter>
<parameter name="portals" required="0" unique="0">
<longdesc lang="en">
iSCSI network portal addresses. Not supported by all
implementations. If unset, the default is to create one portal that
listens on ${OCF_RESKEY_portal_default}.
</longdesc>
<shortdesc lang="en">iSCSI portal addresses</shortdesc>
<content type="string" default="${OCF_RESKEY_portals_default}"/>
</parameter>
<parameter name="iser_portals" required="0" unique="0">
<longdesc lang="en">
iSCSI iSER network portal addresses. Not supported by all
implementations.
</longdesc>
<shortdesc lang="en">iSCSI iSER enabled portal addresses</shortdesc>
<content type="string"/>
</parameter>
<parameter name="allowed_initiators" required="0" unique="0">
<longdesc lang="en">
Allowed initiators. A space-separated list of initiators allowed to
connect to this target. Initiators may be listed in any syntax
the target implementation allows. If this parameter is empty or
not set, access to this target will be allowed from any initiator.
</longdesc>
<shortdesc lang="en">List of iSCSI initiators allowed to connect
to this target</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="incoming_username" required="0" unique="1">
<longdesc lang="en">
A username used for incoming initiator authentication. If unspecified,
allowed initiators will be able to log in without authentication.
This is a unique parameter, as it not allowed to re-use a single
username across multiple target instances.
</longdesc>
<shortdesc lang="en">Incoming account username</shortdesc>
<content type="string"/>
</parameter>
<parameter name="incoming_password" required="0" unique="0">
<longdesc lang="en">
A password used for incoming initiator authentication.
</longdesc>
<shortdesc lang="en">Incoming account password</shortdesc>
<content type="string"/>
</parameter>
<parameter name="additional_parameters" required="0" unique="0">
<longdesc lang="en">
Additional target parameters. A space-separated list of "name=value"
pairs which will be passed through to the iSCSI daemon's management
interface. The supported parameters are implementation
dependent. Neither the name nor the value may contain whitespace.
</longdesc>
<shortdesc lang="en">List of iSCSI target parameters</shortdesc>
<content type="string" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="10s" />
<action name="stop" timeout="10s" />
<action name="status" timeout="10s" interval="10s" depth="0" />
<action name="monitor" timeout="10s" interval="10s" depth="0" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="10s" />
</actions>
</resource-agent>
END
}
#######################################################################
iSCSITarget_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
}
iSCSITarget_start() {
iSCSITarget_monitor
if [ $? = $OCF_SUCCESS ]; then
return $OCF_SUCCESS
fi
local param
local name
local value
local initiator
local portal
case $OCF_RESKEY_implementation in
iet)
local lasttid
local tid
if [ "${OCF_RESKEY_tid}" ]; then
tid="${OCF_RESKEY_tid}"
else
# Figure out the last used target ID, add 1 to get the new
# target ID.
ocf_take_lock $LOCKFILE
ocf_release_lock_on_exit $LOCKFILE
lasttid=`sed -ne "s/tid:\([[:digit:]]\+\) name:.*/\1/p" < /proc/net/iet/volume | sort -n | tail -n1`
[ -z "${lasttid}" ] && lasttid=0
tid=$((++lasttid))
fi
# Create the target.
ocf_run ietadm --op new \
--tid=${tid} \
--params Name=${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC
# Set additional parameters.
for param in ${OCF_RESKEY_additional_parameters}; do
name=${param%=*}
value=${param#*=}
ocf_run ietadm --op update \
--tid=${tid} \
--params ${name}=${value} || exit $OCF_ERR_GENERIC
done
# Legacy versions of IET allow targets by default, current
# versions deny. To be safe we manage both the .allow and
# .deny files.
if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then
echo "${OCF_RESKEY_iqn} ALL" >> /etc/initiators.deny
echo "${OCF_RESKEY_iqn} ${OCF_RESKEY_allowed_initiators// /,}" >> /etc/initiators.allow
else
echo "${OCF_RESKEY_iqn} ALL" >> /etc/initiators.allow
fi
# In iet, adding a new user and assigning it to a target
# is one operation.
if [ -n "${OCF_RESKEY_incoming_username}" ]; then
ocf_run ietadm --op new --user \
--tid=${tid} \
--params=IncomingUser=${OCF_RESKEY_incoming_username},Password=${OCF_RESKEY_incoming_password} \
|| exit $OCF_ERR_GENERIC
fi
;;
tgt)
local tid
tid="${OCF_RESKEY_tid}"
# Create the target.
ocf_run tgtadm --lld iscsi --op new --mode target \
--tid=${tid} \
--targetname ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC
# Set parameters.
for param in ${OCF_RESKEY_additional_parameters}; do
name=${param%=*}
value=${param#*=}
ocf_run tgtadm --lld iscsi --op update --mode target \
--tid=${tid} \
--name=${name} --value=${value} || exit $OCF_ERR_GENERIC
done
# For tgt, we always have to add access per initiator;
# access to targets is denied by default. If
# "allowed_initiators" is unset, we must use the special
# keyword ALL.
for initiator in ${OCF_RESKEY_allowed_initiators=ALL}; do
ocf_run tgtadm --lld iscsi --op bind --mode target \
--tid=${tid} \
--initiator-address=${initiator} || exit $OCF_ERR_GENERIC
done
# In tgt, we must first create a user account, then assign
# it to a target using the "bind" operation.
if [ -n "${OCF_RESKEY_incoming_username}" ]; then
ocf_run tgtadm --lld iscsi --mode account --op new \
--user=${OCF_RESKEY_incoming_username} \
--password=${OCF_RESKEY_incoming_password} || exit $OCF_ERR_GENERIC
ocf_run tgtadm --lld iscsi --mode account --op bind \
--tid=${tid} \
--user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC
fi
;;
lio)
# lio distinguishes between targets and target portal
# groups (TPGs). We will always create one TPG, with the
# number 1. In lio, creating a network portal
# automatically creates the corresponding target if it
# doesn't already exist.
for portal in ${OCF_RESKEY_portals}; do
ocf_run lio_node --addnp ${OCF_RESKEY_iqn} 1 \
${portal} || exit $OCF_ERR_GENERIC
done
# in lio, we can set target parameters by manipulating
# the appropriate configfs entries
for param in ${OCF_RESKEY_additional_parameters}; do
name=${param%=*}
value=${param#*=}
configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/param/${name}"
if [ -e ${configfs_path} ]; then
echo ${value} > ${configfs_path} || exit $OCF_ERR_GENERIC
else
ocf_log warn "Unsupported iSCSI target parameter ${name}: will be ignored."
fi
done
# lio does per-initiator filtering by default. To disable
# this, we need to switch the target to "permissive mode".
if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then
for initiator in ${OCF_RESKEY_allowed_initiators}; do
ocf_run lio_node --addnodeacl ${OCF_RESKEY_iqn} 1 \
${initiator} || exit $OCF_ERR_GENERIC
done
else
ocf_run lio_node --permissive ${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC
# permissive mode enables read-only access by default,
# so we need to change that to RW to be in line with
# the other implementations.
echo 0 > "/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/attrib/demo_mode_write_protect"
if [ `cat /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/attrib/demo_mode_write_protect` -ne 0 ]; then
ocf_log err "Failed to disable write protection for target ${OCF_RESKEY_iqn}."
exit $OCF_ERR_GENERIC
fi
fi
# TODO: add CHAP authentication support when it gets added
# back into LIO
ocf_run lio_node --disableauth ${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC
# Finally, we need to enable the target to allow
# initiators to connect
ocf_run lio_node --enabletpg=${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC
;;
lio-t)
# lio distinguishes between targets and target portal
# groups (TPGs). We will always create one TPG, with the
# number 1. In lio, creating a network portal
# automatically creates the corresponding target if it
# doesn't already exist.
ocf_take_lock $TARGETLOCKFILE
ocf_release_lock_on_exit $TARGETLOCKFILE
ocf_run targetcli /iscsi set global auto_add_default_portal=false || exit $OCF_ERR_GENERIC
ocf_run targetcli /iscsi create ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC
for portal in ${OCF_RESKEY_portals}; do
if [ $portal != ${OCF_RESKEY_portals_default} ] ; then
IFS=':' read -a sep_portal <<< "$portal"
ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/portals create "${sep_portal[0]}" "${sep_portal[1]}" || exit $OCF_ERR_GENERIC
else
ocf_run targetcli /iscsi create ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC
fi
done
# in lio, we can set target parameters by manipulating
# the appropriate configfs entries
for param in ${OCF_RESKEY_additional_parameters}; do
name=${param%=*}
value=${param#*=}
configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/param/${name}"
if [ -e ${configfs_path} ]; then
echo ${value} > ${configfs_path} || exit $OCF_ERR_GENERIC
else
ocf_log warn "Unsupported iSCSI target parameter ${name}: will be ignored."
fi
done
# allow iSER enabled portal
for iser_portal in ${OCF_RESKEY_iser_portals}; do
configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/np/${iser_portal}\:*/iser"
if [ -f ${configfs_path} ]; then
echo "1" > ${configfs_path} || exit $OCF_ERR_GENERIC
else
ocf_log warn "Unable to set iSER on: $iser_portal"
fi
done
# lio does per-initiator filtering by default. To disable
# this, we need to switch the target to "permissive mode".
if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then
for initiator in ${OCF_RESKEY_allowed_initiators}; do
ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/acls create ${initiator} || exit $OCF_ERR_GENERIC
done
else
ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/ set attribute authentication=0 demo_mode_write_protect=0 generate_node_acls=1 cache_dynamic_acls=1 || exit $OCF_ERR_GENERIC
fi
# TODO: add CHAP authentication support when it gets added
# back into LIO
ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/ set attribute authentication=0 || exit $OCF_ERR_GENERIC
# ocf_run targetcli /iscsi
;;
esac
iSCSITarget_monitor
}
iSCSITarget_stop() {
iSCSITarget_monitor
if [ $? -eq $OCF_NOT_RUNNING ]; then
return $OCF_SUCCESS
fi
local tid
case $OCF_RESKEY_implementation in
iet)
# Figure out the target ID
tid=`sed -ne "s/tid:\([[:digit:]]\+\) name:${OCF_RESKEY_iqn}/\1/p" < /proc/net/iet/volume`
if [ -z "${tid}" ]; then
ocf_log err "Failed to retrieve target ID for IQN ${OCF_RESKEY_iqn}"
exit $OCF_ERR_GENERIC
fi
# Close existing connections. There is no other way to
# do this in IET than to parse the contents of
# /proc/net/iet/session.
set -- $(sed -ne '/^tid:'${tid}' /,/^tid/ {
/^[[:space:]]*sid:\([0-9]\+\)/ {
s/^[[:space:]]*sid:\([0-9]*\).*/--sid=\1/; h;
};
/^[[:space:]]*cid:\([0-9]\+\)/ {
s/^[[:space:]]*cid:\([0-9]*\).*/--cid=\1/; G; p;
};
}' < /proc/net/iet/session)
while [[ -n $2 ]]; do
# $2 $1 looks like "--sid=X --cid=Y"
ocf_run ietadm --op delete \
--tid=${tid} $2 $1
shift 2
done
# In iet, unassigning a user from a target and
# deleting the user account is one operation.
if [ -n "${OCF_RESKEY_incoming_username}" ]; then
ocf_run ietadm --op delete --user \
--tid=${tid} \
--params=IncomingUser=${OCF_RESKEY_incoming_username} \
|| exit $OCF_ERR_GENERIC
fi
# Loop on delete. Keep trying until we time out, if
# necessary.
while true; do
if ietadm --op delete --tid=${tid}; then
ocf_log debug "Removed target ${OCF_RESKEY_iqn}."
break
else
ocf_log warn "Failed to remove target ${OCF_RESKEY_iqn}, retrying."
sleep 1
fi
done
# Avoid stale /etc/initiators.{allow,deny} entries
# for this target
if [ -e /etc/initiators.deny ]; then
ocf_run sed -e "/^${OCF_RESKEY_iqn}[[:space:]]/d" \
-i /etc/initiators.deny
fi
if [ -e /etc/initiators.allow ]; then
ocf_run sed -e "/^${OCF_RESKEY_iqn}[[:space:]]/d" \
-i /etc/initiators.allow
fi
;;
tgt)
tid="${OCF_RESKEY_tid}"
# Close existing connections. There is no other way to
# do this in tgt than to parse the output of "tgtadm --op
# show".
set -- $(tgtadm --lld iscsi --op show --mode target \
| sed -ne '/^Target '${tid}':/,/^Target/ {
/^[[:space:]]*I_T nexus: \([0-9]\+\)/ {
s/^.*: \([0-9]*\).*/--sid=\1/; h;
};
/^[[:space:]]*Connection: \([0-9]\+\)/ {
s/^.*: \([0-9]*\).*/--cid=\1/; G; p;
};
/^[[:space:]]*LUN information:/ q;
}')
while [[ -n $2 ]]; do
# $2 $1 looks like "--sid=X --cid=Y"
ocf_run tgtadm --lld iscsi --op delete --mode connection \
--tid=${tid} $2 $1
shift 2
done
# In tgt, we must first unbind the user account from
# the target, then remove the account itself.
if [ -n "${OCF_RESKEY_incoming_username}" ]; then
ocf_run tgtadm --lld iscsi --mode account --op unbind \
--tid=${tid} \
--user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC
ocf_run tgtadm --lld iscsi --mode account --op delete \
--user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC
fi
# Loop on delete. Keep trying until we time out, if
# necessary.
while true; do
if tgtadm --lld iscsi --op delete --mode target --tid=${tid}; then
ocf_log debug "Removed target ${OCF_RESKEY_iqn}."
break
else
ocf_log warn "Failed to remove target ${OCF_RESKEY_iqn}, retrying."
sleep 1
fi
done
# In tgt, we don't have to worry about our ACL
# entries. They are automatically removed upon target
# deletion.
;;
lio)
# In lio, removing a target automatically removes all
# associated TPGs, network portals, and LUNs.
ocf_run lio_node --deliqn ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC
;;
lio-t)
ocf_take_lock $TARGETLOCKFILE
ocf_release_lock_on_exit $TARGETLOCKFILE
ocf_run targetcli /iscsi delete ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC
;;
esac
return $OCF_SUCCESS
}
iSCSITarget_monitor() {
case $OCF_RESKEY_implementation in
iet)
grep -Eq "tid:[0-9]+ name:${OCF_RESKEY_iqn}" /proc/net/iet/volume && return $OCF_SUCCESS
;;
tgt)
tgtadm --lld iscsi --op show --mode target \
| grep -Eq "Target [0-9]+: ${OCF_RESKEY_iqn}" && return $OCF_SUCCESS
;;
lio | lio-t)
# if we have no configfs entry for the target, it's
# definitely stopped
[ -d /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn} ] || return $OCF_NOT_RUNNING
# if the target is there, but its TPG is not enabled, then
# we also consider it stopped
[ `cat /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/enable` -eq 1 ] || return $OCF_NOT_RUNNING
return $OCF_SUCCESS
;;
esac
return $OCF_NOT_RUNNING
}
iSCSITarget_validate() {
# Do we have all required variables?
local required_vars
case $OCF_RESKEY_implementation in
iet)
required_vars="iqn"
;;
tgt)
required_vars="iqn tid"
;;
esac
for var in ${required_vars}; do
param="OCF_RESKEY_${var}"
if [ -z "${!param}" ]; then
ocf_exit_reason "Missing resource parameter \"$var\"!"
exit $OCF_ERR_CONFIGURED
fi
done
# Is the configured implementation supported?
case "$OCF_RESKEY_implementation" in
"iet"|"tgt"|"lio"|"lio-t")
;;
"")
# The user didn't specify an implementation, and we were
# unable to determine one from installed binaries (in
# other words: no binaries for any supported
# implementation could be found)
ocf_exit_reason "Undefined iSCSI target implementation"
exit $OCF_ERR_INSTALLED
;;
*)
ocf_exit_reason "Unsupported iSCSI target implementation \"$OCF_RESKEY_implementation\"!"
exit $OCF_ERR_CONFIGURED
;;
esac
# Do we have any configuration parameters that the current
# implementation does not support?
local unsupported_params
local var
local envar
case $OCF_RESKEY_implementation in
iet|tgt)
# IET and tgt do not support binding a target portal to a
# specific IP address.
unsupported_params="portals"
;;
lio|lio-t)
# TODO: Remove incoming_username and incoming_password
# from this check when LIO 3.0 gets CHAP authentication
unsupported_params="tid incoming_username incoming_password"
;;
esac
for var in ${unsupported_params}; do
envar=OCF_RESKEY_${var}
defvar=OCF_RESKEY_${var}_default
if [ -n "${!envar}" ]; then
if [[ "${!envar}" != "${!defvar}" ]];then
case "$__OCF_ACTION" in
start|validate-all)
ocf_log warn "Configuration parameter \"${var}\"" \
"is not supported by the iSCSI implementation" \
"and will be ignored." ;;
esac
fi
fi
done
if ! ocf_is_probe; then
# Do we have all required binaries?
case $OCF_RESKEY_implementation in
iet)
check_binary ietadm
;;
tgt)
check_binary tgtadm
;;
lio)
check_binary tcm_node
check_binary lio_node
;;
lio-t)
check_binary targetcli
;;
esac
# Is the required kernel functionality available?
case $OCF_RESKEY_implementation in
iet)
[ -d /proc/net/iet ]
if [ $? -ne 0 ]; then
ocf_log err "/proc/net/iet does not exist or is not a directory -- check if required modules are loaded."
exit $OCF_ERR_INSTALLED
fi
;;
tgt)
# tgt is userland only
;;
lio)
# lio needs configfs to be mounted
if ! grep -Eq "^.*/sys/kernel/config[[:space:]]+configfs" /proc/mounts; then
ocf_log err "configfs not mounted at /sys/kernel/config -- check if required modules are loaded."
exit $OCF_ERR_INSTALLED
fi
# check for configfs entries created by target_core_mod
if [ ! -d /sys/kernel/config/target ]; then
ocf_log err "/sys/kernel/config/target does not exist or is not a directory -- check if required modules are loaded."
exit $OCF_ERR_INSTALLED
fi
;;
lio-t)
#targetcli loads the needed kernel modules
;;
esac
fi
return $OCF_SUCCESS
}
case $1 in
meta-data)
meta_data
exit $OCF_SUCCESS
;;
usage|help)
iSCSITarget_usage
exit $OCF_SUCCESS
;;
esac
# Everything except usage and meta-data must pass the validate test
iSCSITarget_validate
case $__OCF_ACTION in
start) iSCSITarget_start;;
stop) iSCSITarget_stop;;
monitor|status) iSCSITarget_monitor;;
reload) ocf_log err "Reloading..."
iSCSITarget_start
;;
validate-all) ;;
*) iSCSITarget_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
rc=$?
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
exit $rc
diff --git a/heartbeat/jira b/heartbeat/jira.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/jira
rename to heartbeat/jira.in
index b01cfc394..b9d6abed3
--- a/heartbeat/jira
+++ b/heartbeat/jira.in
@@ -1,281 +1,281 @@
-#! /bin/bash
+#!@BASH_SHELL@
#
####################################################################
# Description: OCF Resource Agent to manage JIRA software.
# Author : Saleh A. (saleh.abbas.saber@gmail.com)
#
# License : WTFPL 2
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# Version 2, December 2004
#
# Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
#
# Everyone is permitted to copy and distribute verbatim or modified
# copies of this license document, and changing it is allowed as long
# as the name is changed.
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
# 0. You just DO WHAT THE FUCK YOU WANT TO.
#
####################################################################
# Parameters:
# OCF_RESKEY_statusurl : Status URL to monitor JIRA
# (default: http://localhost:8080/status)
# OCF_RESKEY_java_home : Java Home
# (default: /usr/lib/jvm/jre)
# OCF_RESKEY_jira_installation : Jira installtion directory
# OCF_RESKEY_jira_user : User running Jira software
# (by default: jira)
####################################################################
# Initialization
# Source ocf-shellfuncs
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
# Usage
jira_usage() {
cat <<_EOF
Usage: $0 action
Supported Actions:
start : start jira
stop : stop jira
monitor : show jira status
meta-data : show the meta-data
validate-all: validate the RA configuration
_EOF
}
# Start
jira_start() {
# exit immediately if configuration is not valid
jira_validate_all || exit $?
# if resource is already running, bail out early
if jira_monitor; then
ocf_log info "Resource is already running"
return $OCF_SUCCESS
fi
# Starting Jira
waittime=300
su -m $jira_user -c "$jira_installation/bin/startup.sh &> /dev/null"
while [[ $waittime -gt 0 ]]; do
if $(curl --connect-timeout 1 --max-time 3 -s ${statusurl} | grep '{"state":"RUNNING"}' > /dev/null); then
waittime=0
else
sleep 1
waittime=$(($waittime - 1))
fi
done
# Verify jira is running
jira_monitor
rc=$?
return $?
}
# Stop
jira_stop() {
local rc
# exit immediately if configuration is not valid
jira_validate_all || exit $?
jira_monitor
rc=$?
case "$rc" in
"$OCF_SUCCESS")
# Currently running. Normal, expected behavior.
ocf_log debug "Resource is currently running"
;;
"$OCF_NOT_RUNNING")
# Currently not running. Nothing to do.
ocf_log info "Resource is already stopped"
return $OCF_SUCCESS
;;
esac
# Stopping Jira
waittime=300
su -m $jira_user -c "$jira_installation/bin/shutdown.sh &> /dev/null"
while [[ $waittime -gt 0 ]]; do
if $(kill -0 $(cat ${jira_installation}/work/catalina.pid 2> /dev/null) 2> /dev/null) ; then
sleep 1
waittime=$(($waittime - 1))
else
waittime=0
fi
done
# Stop JIRA forcely if it failed
if $(kill -0 $(cat ${jira_installation}/work/catalina.pid 2> /dev/null) 2> /dev/null) ; then
kill -9 $(cat ${jira_installation}/work/catalina.pid)
sleep 1
fi
# Verify jira is stopped
jira_monitor
rc=$?
return $rc
}
# Monitor
jira_monitor() {
local rc
# exit immediately if configuration is not valid
jira_validate_all || exit $?
if $(kill -0 $(cat ${jira_installation}/work/catalina.pid 2> /dev/null) 2> /dev/null) ; then
# Is jira working
if $(curl --connect-timeout 1 --max-time 3 -s ${statusurl} | grep '{"state":"RUNNING"}' > /dev/null) ; then
rc=0
else
# Jira has a problem
rc=2
fi
else
# Tomcat is stopped (and Jira)
rc=1
fi
case "$rc" in
0)
rc=$OCF_SUCCESS
ocf_log debug "Resource is running"
;;
1)
rc=$OCF_NOT_RUNNING
ocf_log debug "Resource is not running"
;;
*)
ocf_log err "Resource has failed"
exit $OCF_ERR_GENERIC
esac
return $rc
}
# Validat All
jira_validate_all() {
# Check if java is installed
if ! [ -d $OCF_RESKEY_java_home ]; then
ocf_log err "$OCF_RESKEY_java_home does not exist. \
Please ensure that Java is installed and configured correctly"
exit $OCF_ERR_INSTALLED
fi
# Check if JIRA installation directory exists
if ! [ -d $OCF_RESKEY_jira_installation ]; then
ocf_log err "$OCF_RESKEY_jira_installation does not exist."
exit $OCF_ERR_INSTALLED
fi
return $OCF_SUCCESS
}
# Meta-data
jira_meta_data(){
cat <<EOF
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="jira">
<version>0.1</version>
<longdesc lang="en">
OCF Resource Agent to manage JIRA software
</longdesc>
<shortdesc lang="en">JIRA OCF RA</shortdesc>
<parameters>
<parameter name="statusurl" unique="0" required="0">
<longdesc lang="en">
Status URL for JIRA monitoring
</longdesc>
<shortdesc lang="en">JIRA status url</shortdesc>
<content type="string" default="http://localhost:8080/status"/>
</parameter>
<parameter name="java_home" unique="0" required="0">
<longdesc lang="en">
Java Home in the Linux instance
</longdesc>
<shortdesc lang="en">Java Home</shortdesc>
<content type="string" default="/usr/lib/jvm/jre"/>
</parameter>
<parameter name="jira_installation" unique="0" required="1">
<longdesc lang="en">
JIRA installation directory (binaries, ... etc)
</longdesc>
<shortdesc lang="en">JIRA installation directory</shortdesc>
<content type="string"/>
</parameter>
<parameter name="jira_user" unique="0" required="0">
<longdesc lang="en">
User to run Jira software with
</longdesc>
<shortdesc lang="en">Jira user</shortdesc>
<content type="string" default="jira"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="300s" />
<action name="stop" timeout="300s" />
<action name="monitor" timeout="30s"
interval="10s" depth="0" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="20s" />
</actions>
</resource-agent>
EOF
}
# Execution
# Set vars from defined OCF env vars
statusurl=${OCF_RESKEY_statusurl-http://localhost:8080/status}
java_home=${OCF_RESKEY_java_home-/usr/lib/jvm/jre}
jira_installation=${OCF_RESKEY_jira_installation}
jira_user=${OCF_RESKEY_jira_user-jira}
# Export JAVA_HOME env variable
export JAVA_HOME=${OCF_RESKEY_java_home}
# Make sure meta-data and usage always succeed
case $__OCF_ACTION in
meta-data) jira_meta_data
exit $OCF_SUCCESS
;;
usage|help) jira_usage
exit $OCF_SUCCESS
;;
esac
# Anything other than meta-data and usage must pass validation
jira_validate_all || exit $?
# Translate each action into the appropriate function call
case $__OCF_ACTION in
start) jira_start;;
stop) jira_stop;;
status|monitor) jira_monitor;;
validate-all) ;;
*) jira_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
rc=$?
exit $rc
diff --git a/heartbeat/kamailio b/heartbeat/kamailio.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/kamailio
rename to heartbeat/kamailio.in
index 12dcede06..5a401926f
--- a/heartbeat/kamailio
+++ b/heartbeat/kamailio.in
@@ -1,741 +1,741 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# OCF resource agent for Kamailio for pacemaker
#
# Copyright (c) 2013 FREQUENTIS AG,
# Authors: Stefan Wenk
# Rainer Brestan
#
# 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.
#
# OCF input parameters:
# OCF_RESKEY_binary
# OCF_RESKEY_conffile
# OCF_RESKEY_pidfile
# OCF_RESKEY_monitoring_ip
# OCF_RESKEY_listen_address
# OCF_RESKEY_port
# OCF_RESKEY_proto
# OCF_RESKEY_sipsak
# OCF_RESKEY_kamctl
# OCF_RESKEY_kamctlrc
# OCF_RESKEY_kamuser
# OCF_RESKEY_kamgroup
# OCF_RESKEY_extra_options
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
#######################################################################
# Defaults
RESKEY_binary_default="/usr/sbin/kamailio"
RESKEY_conffile_default="/etc/kamailio/kamailio.cfg"
RESKEY_pidfile_default="/var/run/kamailio_${OCF_RESOURCE_INSTANCE}/kamailio.pid"
RESKEY_monitoring_ip_default=127.0.0.1
RESKEY_port_default=5060
RESKEY_proto_default="udptcp"
RESKEY_sipsak_default="/usr/bin/sipsak"
RESKEY_kamctl_default="/usr/bin/kamctl"
RESKEY_kamctlrc_default="/etc/kamailio/kamctlrc"
RESKEY_kamuser_default=""
RESKEY_kamgroup_default=""
RESKEY_extra_options_default=""
#######################################################################
: ${OCF_RESKEY_binary=${RESKEY_binary_default}}
: ${OCF_RESKEY_conffile=${RESKEY_conffile_default}}
: ${OCF_RESKEY_pidfile=${RESKEY_pidfile_default}}
: ${OCF_RESKEY_monitoring_ip=${RESKEY_monitoring_ip_default}}
: ${OCF_RESKEY_port=${RESKEY_port_default}}
: ${OCF_RESKEY_proto=${RESKEY_proto_default}}
: ${OCF_RESKEY_sipsak=${RESKEY_sipsak_default}}
: ${OCF_RESKEY_kamctl=${RESKEY_kamctl_default}}
: ${OCF_RESKEY_kamctlrc=${RESKEY_kamctlrc_default}}
: ${OCF_RESKEY_kamuser=${RESKEY_kamuser_default}}
: ${OCF_RESKEY_kamgroup=${RESKEY_kamgroup_default}}
: ${OCF_RESKEY_extra_options=${RESKEY_extra_options_default}}
#######################################################################
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
}
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="kamailio">
<version>1.0</version>
<longdesc lang="en">
Resource agent for the Kamailio SIP proxy/registrar.
Multiple instances are possible when using following parameter combinations:
Parameters for Kamailio instance 1:
listen_address=192.168.159.128
monitoring_ip=192.168.159.128
proto=udptcp
port=5060
Parameters for Kamailio instance 2:
listen_address=192.168.159.128
monitoring_ip=192.168.159.128
proto=udp
port=5070
conffile=/etc/kamailio/kamailio2.cfg
kamctlrc=""
Only one instance can be monitored via the command "kamctl monitor"
because the kamctl tool of kamailio 4.x is not designed for multiple
instances. Therefore, the provided kamctrlrc file path needs to be
empty for instance 2, 3 ...
Parameters for a third Kamailio instance:
listen_address=192.168.159.128
monitoring_ip=192.168.159.128
proto=tcp
port=5080
conffile=/etc/kamailio/kamailio3.cfg
kamctlrc=""
</longdesc>
<shortdesc lang="en">Resource agent for Kamailio</shortdesc>
<parameters>
<parameter name="binary" unique="0" required="0">
<longdesc lang="en">The kamailio binary</longdesc>
<shortdesc lang="en">The kamailio binary</shortdesc>
<content type="string" default="${RESKEY_binary_default}" />
</parameter>
<parameter name="conffile" unique="0" required="0">
<longdesc lang="en">
The kamailio configuration file name with full path.
For example, "/etc/kamailio/kamailio.cfg" , which is the default value.
Make sure to use unique names in case of having multiple instances.
</longdesc>
<shortdesc lang="en">Configuration file name with full path</shortdesc>
<content type="string" default="${RESKEY_conffile_default}" />
</parameter>
<parameter name="pidfile" unique="0" required="0">
<longdesc lang="en">
The kamailio PID file. The directory used must be writable by kamailio
process user. Be sure to use unique name for running more than one
instance. Try to use absolute path names.
If empty, resource agent create a unique directory from the resource
instance name for the PID file and assign it to the process user.
</longdesc>
<shortdesc lang="en">PID file</shortdesc>
<content type="string" default="${RESKEY_pidfile_default}" />
</parameter>
<parameter name="monitoring_ip" unique="0" required="0">
<longdesc lang="en">
SIP IP Address of the kamailio instance used for SIP OPTIONS polling monitoring.
Usually the same IP address value as for parameter listen_address should be
provided.
In order to respond with a 200 OK response to the SIP OOPTION requests,
the kamailio.cfg file needs to contain following section:
Note: The following "kamailio.cfg" code sniplet is part of an XML section.
Therefore it contains two &amp; characters, which need to be replaced
with two ampersand characters within "kamailio.cfg":
if (is_method("OPTIONS") &amp;&amp; ($ru=~"sip:monitor@.*")) {
##
## If the method is an OPTIONS we are simply going to respond
## with a 200 OK.
# xlog("L_INFO", "Method is an OPTIONS, probably just monitoring\n");
sl_send_reply("200", "Kamailio is alive");
exit;
}
</longdesc>
<shortdesc lang="en">Monitoring IP address used for SIP OPTIONS polling.</shortdesc>
<content type="string" default="${RESKEY_monitoring_ip_default}" />
</parameter>
<parameter name="listen_address" unique="0" required="1">
<longdesc lang="en">
SIP IP address the kamailio will listen on.
</longdesc>
<shortdesc lang="en">Listening SIP address</shortdesc>
<content type="string" />
</parameter>
<parameter name="port" unique="0" required="0">
<longdesc lang="en">
SIP port for the kamailio instance.
</longdesc>
<shortdesc lang="en">SIP Port</shortdesc>
<content type="string" default="${RESKEY_port_default}" />
</parameter>
<parameter name="extra_options" unique="0" required="0">
<longdesc lang="en">
Extra options to add to kamailio start.
</longdesc>
<shortdesc lang="en">extra_options</shortdesc>
<content type="string" default="${RESKEY_extra_options}" />
</parameter>
<parameter name="proto" unique="0" required="0">
<longdesc lang="en">
The protocol used for SIP proto = udp|tcp|udptcp|conf_udp|conf_tcp|conf_udptcp.
Using the options "conf_*" does not add any "-l" parameters to the kamailio command,
the "listen" parameters from kamailio.conf are used instead. The sipsak checks are
performed depending what protocol is defined after the underscore.
</longdesc>
<shortdesc lang="en">protocol</shortdesc>
<content type="string" default="${RESKEY_proto_default}" />
</parameter>
<parameter name="sipsak" unique="0" required="0">
<longdesc lang="en">
The installation path of the sipsak tool, which is used
for monitoring Kamailio via SIP OPTIONS polling.
</longdesc>
<shortdesc lang="en">sipsak path</shortdesc>
<content type="string" default="${RESKEY_sipsak_default}" />
</parameter>
<parameter name="kamctl" unique="0" required="0">
<longdesc lang="en">
The installation path of the "kamctl" control tool.
</longdesc>
<shortdesc lang="en">kamctl path</shortdesc>
<content type="string" default="${RESKEY_kamctl_default}" />
</parameter>
<parameter name="kamctlrc" unique="0" required="0">
<longdesc lang="en">
The location of the "kamctlrc" file for the Kamailio instance.
The file "kamctlrc" is the Kamailio configuration file for its "kamctl" control tool.
This parameter only needs to be provided in case of using multiple Kamailio server
instances on a single cluster node:
In case that the parameter "kamctlrc" is not empty, this ressource agent monitors
the health state of the Kamailio server via the command "kamctl monitor 1". This
setting is recommended in case of using a single Kamailio server instance.
In case that the parameter "kamctlrc" is empty, the ressource agent does not
monitor the health state of the Kamailio server instance via the "kamctl" command.
Please note that the "kamctl" control command of Kamailio 4.x does not support
running multiple Kamailio instances on one host. Nevertheless this resource agent
does allow multiple Kamailio instances per host. The result of the "kamctl"
limitation in terms of number of Kamailio server instances is that the health
check via "kamctl monitor 1" can be configured for a single Kamailio instance
only.
Please refer to the long description of this resoure agent for an example
of parameter combinations in case that multiple instances are to be
configured per cluster node.
</longdesc>
<shortdesc lang="en">kamctlrc path</shortdesc>
<content type="string" default="${RESKEY_kamctlrc_default}" />
</parameter>
<parameter name="kamuser" unique="0" required="0">
<longdesc lang="en">
The user account for kamailio process to run with.
Uses the current user, if not specified or empty.
There is no check, if running kamailio with the specified user account is possible.
</longdesc>
<shortdesc lang="en">kamailio user</shortdesc>
<content type="string" default="${RESKEY_kamuser_default}" />
</parameter>
<parameter name="kamgroup" unique="0" required="0">
<longdesc lang="en">
The group for kamailio process to run with.
Uses the current group, if not specified or empty.
</longdesc>
<shortdesc lang="en">kamailio group</shortdesc>
<content type="string" default="${RESKEY_kamgroup_default}" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="60s" />
<action name="stop" timeout="30s" />
<action name="status" timeout="30s" interval="10s" />
<action name="monitor" timeout="30s" interval="10s" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="5s" />
<action name="notify" timeout="5s" />
</actions>
</resource-agent>
END
exit $OCF_SUCCESS
}
#######################################################################
###
#Check if a process with given PID is running
# Parameter 1: PID
###
isRunning_PID()
{
kill -s 0 "$1" > /dev/null 2>&1
}
###
#Check if an instance with given command line is running
# Parameter 1: command line.
###
isRunning_cmd()
{
pkill -s 0 "$1" > /dev/null 2>&1
}
###
# Formats the result of a command.
#
# Parameter 1: Exit status.
# Parameter 2: Standard output (stdout).
# Parameter 3: Error output (stderr).
# Returns: Formatted result.
kamailio_format_result() {
local exitstatus="$1"
local value="$2"
local error="$3"
echo -n "exit status: ${exitstatus}"
if [ -n "$value" ]; then
echo -n ", value: ${value}"
fi
if [ -n "$error" ]; then
echo -n ", error: ${error}"
fi
echo
}
###
# Put the command line, how the kamailio process is started according
# to the configured parameters, into the variable "kam_cmd".
###
kamailio_cmd()
{
case ${OCF_RESKEY_proto} in
udp) listen_param="-T -l udp:${OCF_RESKEY_listen_address}:${OCF_RESKEY_port} -l udp:127.0.0.1:${OCF_RESKEY_port}"
;;
tcp) listen_param="-l tcp:${OCF_RESKEY_listen_address}:${OCF_RESKEY_port} -l tcp:127.0.0.1:${OCF_RESKEY_port}"
;;
udptcp) listen_param1="-l udp:${OCF_RESKEY_listen_address}:${OCF_RESKEY_port} -l udp:127.0.0.1:${OCF_RESKEY_port}"
listen_param2="-l tcp:${OCF_RESKEY_listen_address}:${OCF_RESKEY_port} -l tcp:127.0.0.1:${OCF_RESKEY_port}"
listen_param="${listen_param1} ${listen_param2}"
;;
conf_*)
# doing nothing, no listen_param set
;;
*) listen_param="-T"
;;
esac
kam_cmd="${OCF_RESKEY_binary} -P ${OCF_RESKEY_pidfile} -f ${OCF_RESKEY_conffile}"
if [ -n "${listen_param}" ]; then
kam_cmd="${kam_cmd} ${listen_param}"
fi
if [ -n "${OCF_RESKEY_kamuser}" ]; then
kam_cmd="${kam_cmd} -u ${OCF_RESKEY_kamuser}"
fi
if [ -n "${OCF_RESKEY_kamgroup}" ]; then
kam_cmd="${kam_cmd} -g ${OCF_RESKEY_kamgroup}"
fi
if [ -n "${OCF_RESKEY_extra_options}" ]; then
kam_cmd="${kam_cmd} ${OCF_RESKEY_extra_options}"
fi
}
###
# Gets the PID for the running Kamailio instance.
#
# Returns: The variable $PID contains the found PID value or an empty string.
# Exit Status: Zero if the PID file was found and this process run under
# the command line parameters of our instance.
# 1) if the PID file is not present and no process running under
# our command line options is active.
# 2) in all other fatal cases, which we classify in the followig
# as OCF_ERR_genering. These are folloing cases:
# a) The PID file contains a PID value which does no match to
# to our instance
# b) The PID contains a empty string in its first line
# c) The PID file contains some text and some processeses
# from our instance are still active
kamailio_get_pid() {
if [ -f ${OCF_RESKEY_pidfile} ]; then
PID=`head -n 1 $OCF_RESKEY_pidfile`
if [ ! -z "$PID" ]; then
#Cross check if the PID file really contains a process of our kamailio instance:
kamailio_cmd
CROSSPID=`pgrep -o -f "${kam_cmd}"`
if [ x"$PID" == x"$CROSSPID" ]; then
#ocf_log debug "Found kamailio process PID with value: $PID."
return 0
fi
#ocf_log debug "PID file does not contain a PID of a $OCF_RESKEY_binary process!"
return 2
fi
#PID file does not contain a valid PID
rm -f ${OCF_RESKEY_pidfile}
return 2
fi
# No PID file found!
# Check if still a process exists even though we don't have the PID any longer:
kamailio_cmd
pgrep -f "${kam_cmd}"
if [ $? -eq 0 ]; then
ocf_log info "PID file does not contain a valid PID, but kamailio process is still active"
return 2
fi
ocf_log info "No PID file found and our kamailio instance is not active"
return 1
}
kamailio_status() {
local not_running_log_level="warn"
local errorfile error output
if [ "$__OCF_ACTION" = "start" ]; then
not_running_log_level="debug"
fi
kamailio_get_pid >/dev/null
RET=$?
if [ $RET -ne 0 ]; then
if [ $RET -eq 2 ]; then
ocf_log $not_running_log_level "PID file does not contain a PID of a ${OCF_RESKEY_binary} process!"
return $OCF_ERR_GENERIC
fi
return $OCF_NOT_RUNNING
fi
PID=`head -n 1 $OCF_RESKEY_pidfile`
isRunning_PID "$PID"
RET=$?
if [ "$RET" -ne 0 ]; then
ocf_log $not_running_log_level "PID from $PID from ${OCF_RESKEY_pidfile} not running"
rm -f ${OCF_RESKEY_pidfile}
return $OCF_NOT_RUNNING
fi
rc=0
# In case that OCF_RESKEY_kamctlrc we perfom a health check via "kamctl monitor 1"
if [ ! -z ${OCF_RESKEY_kamctlrc} ]; then
# PID is running now but it is not save to check via kamctl without care, because
# the implementation analysis in the case that we kill all running processes
# shows that in case that the fifo cannot be read, then kamctl blocks. This needs
# to be avoided.
# In order to be on the safe side, we run this check therefore under "timeout" control:
rc=1
timeout 3 ${OCF_RESKEY_kamctl} monitor 1 |grep "since" ; rc=$?
fi
if [ $rc -ne 0 ]; then
ocf_log $not_running_log_level "Kamailio is not up according to kamctl monitor!"
return $OCF_NOT_RUNNING
fi
errorfile=`mktemp`
case ${OCF_RESKEY_proto} in
udp) output=`$OCF_RESKEY_sipsak -s sip:monitor@$OCF_RESKEY_monitoring_ip:${OCF_RESKEY_port} -H localhost --transport udp>/dev/null 2>>$errorfile`
result=$?
;;
tcp) output=`$OCF_RESKEY_sipsak -s sip:monitor@$OCF_RESKEY_monitoring_ip:${OCF_RESKEY_port} -H localhost --transport tcp>/dev/null 2>>$errorfile`
result=$?
;;
udptcp) output=`$OCF_RESKEY_sipsak -s sip:monitor@$OCF_RESKEY_monitoring_ip:${OCF_RESKEY_port} -H localhost --transport tcp>/dev/null 2>>$errorfile`
result=$?
if [ $result -eq 0 ]; then
output=`$OCF_RESKEY_sipsak -s sip:monitor@$OCF_RESKEY_monitoring_ip:${OCF_RESKEY_port} -H localhost --transport udp>/dev/null 2>>$errorfile`
result=$?
fi
;;
*) output=`$OCF_RESKEY_sipsak -s sip:monitor@$OCF_RESKEY_monitoring_ip:${OCF_RESKEY_port} -H localhost --transport udp>/dev/null 2>>$errorfile`
result=$?
;;
esac
error=`cat $errorfile`
rm -f $errorfile
if [ $result -ne 0 ]; then
ocf_log $not_running_log_level "Kamailio is running, but not functional as sipsak ${OCF_RESKEY_proto} failed with $(kamailio_format_result $result "$output" "$error")"
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
kamailio_monitor() {
kamailio_status
}
kamailio_start() {
local errorfile error output piddir
if
kamailio_status
then
ocf_log info "kamailio already running."
return $OCF_SUCCESS
fi
# if pidfile directory does not exist, create it with kamailio process owner
piddir=`dirname "${OCF_RESKEY_pidfile}"`
if [ ! -d "$piddir" ]; then
mkdir -p "$piddir"
if [ "$OCF_RESKEY_kamuser" != "" ]; then
chown ${OCF_RESKEY_kamuser} "$piddir"
fi
fi
kamailio_cmd
if [ "$OCF_RESKEY_kamuser" != "" ]; then
- kam_cmd="su -s /bin/bash $OCF_RESKEY_kamuser -c \"$kam_cmd\""
+ kam_cmd="su -s @BASH_SHELL@ $OCF_RESKEY_kamuser -c \"$kam_cmd\""
fi
ocf_log info "start kamailio with $kam_cmd."
errorfile=`mktemp`
output=$(eval ${kam_cmd} 2>>$errorfile)
result=$?
error=`cat $errorfile`
rm -f $errorfile
if [ $result -eq 0 ]; then
result=1
while [ $result -ne 0 ]; do
sleep 1
kamailio_get_pid >/dev/null
result=$?
done
ocf_log info "kamailio instance PID=$PID started."
# check with monitor operation if running correctly
result=$OCF_ERR_GENERIC
while [ $result -ne $OCF_SUCCESS ]; do
sleep 1
kamailio_monitor
result=$?
ocf_log info "monitor in start returned $result"
done
ocf_log info "kamailio started successful."
else
ocf_log err "kamailio instance could not be started, $(kamailio_format_result $result "$output" "$error")"
result=$OCF_ERR_GENERIC
fi
return $result
}
kamailio_stop() {
local piddir
local TRIES=0
result=$OCF_SUCCESS
kamailio_cmd
ocf_log info "Stopping kamailio by sending SIGTERM to ${kam_cmd}"
pkill -SIGTERM -x -f "${kam_cmd}"
if [ $? -eq 1 ]; then
# already stopped. no processes found
# in case of not specified pidfile, delete the created directory
# otherwise only the pidfile itself
if [ "${OCF_RESKEY_pidfile}" == "${RESKEY_pidfile_default}" ]; then
piddir=`dirname "${OCF_RESKEY_pidfile}"`
rm -rf "$piddir"
else
rm -f "${OCF_RESKEY_pidfile}"
fi
return $result
fi
if [ "$OCF_RESKEY_CRM_meta_timeout" != "" ]; then
KAMAILIO_STOP_TIMEOUT=$(( ($OCF_RESKEY_CRM_meta_timeout/1000) - 7 ))
else
KAMAILIO_STOP_TIMEOUT=20
fi
while isRunning_cmd "${kam_cmd}" && [ "$TRIES" -lt "${KAMAILIO_STOP_TIMEOUT}" ]
do
sleep 1
ocf_log info "kamailio ${kam_cmd} is still running after SIGTERM"
((TRIES++))
done
isRunning_cmd "${kam_cmd}"
RET=$?
if [ "$RET" -eq 0 ]; then
ocf_log info "Killing ${kam_cmd} with SIGKILL"
TRIES=0
pkill -SIGKILL -x -f "${kam_cmd}" > /dev/null 2>&1
while isRunning_cmd "${kam_cmd}" && [ "$TRIES" -lt 3 ]
do
sleep 1
ocf_log info "kamailio ${kam_cmd} is still running after SIGKILL"
((TRIES++))
done
isRunning_cmd "${kam_cmd}"
RET=$?
if [ "$RET" -eq 0 ]; then
ocf_log fatal "kamailio is still running even after SIGKILL"
result=$OCF_ERR_GENERIC
fi
else
ocf_log info "${kam_cmd} has stopped."
fi
# in case of not specified pidfile, delete the created directory
# otherwise only the pidfile itself
if [ "${OCF_RESKEY_pidfile}" == "${RESKEY_pidfile_default}" ]; then
piddir=`dirname "${OCF_RESKEY_pidfile}"`
rm -rf "$piddir"
else
rm -f "${OCF_RESKEY_pidfile}"
fi
return $result
}
kamailio_validate_all() {
# Check if kamailio configuration is valid before starting the server
if [ ! -f $OCF_RESKEY_binary ]; then
ocf_log err "File OCF_RESKEY_binary [${OCF_RESKEY_binary}] does not exist!"
return $OCF_NOT_INSTALLED
fi
out=$($OCF_RESKEY_binary -c 2>&1 > /dev/null)
retcode=$?
if [ "$retcode" -ne '0' ]; then
ocf_log info "Not starting kamailio: $OCF_RESKEY_binary does not start!"
return $OCF_ERR_CONFIGURED
fi
case $OCF_RESKEY_monitoring_ip in
"") ocf_log err "Required parameter OCF_RESKEY_monitoring_ip is missing!"
return $OCF_ERR_CONFIGURED
;;
[0-9]*.[0-9]*.[0-9]*.[0-9]*) : OK
;;
*) ocf_log err "Parameter OCF_RESKEY_monitoring_ip [$OCF_RESKEY_monitoring_ip] is not an IP address!"
return $OCF_ERR_CONFIGURED
;;
esac
case $OCF_RESKEY_listen_address in
"") ocf_log err "Required parameter $OCF_RESKEY_listen_address is missing!"
return $OCF_ERR_CONFIGURED
;;
[0-9]*.[0-9]*.[0-9]*.[0-9]*) : OK
;;
*) ocf_log err "Parameter OCF_RESKEY_listen_address [$OCF_RESKEY_listen_address] not an IP address!"
return $OCF_ERR_CONFIGURED
;;
esac
if [ ! -f ${OCF_RESKEY_sipsak} ]; then
ocf_log err "sipsak [${OCF_RESKEY_sipsak}] does not exist!"
return $OCF_NOT_INSTALLED
fi
if [ ! -z ${OCF_RESKEY_kamctlrc} ]; then
if [ ! -f ${OCF_RESKEY_kamctlrc} ]; then
ocf_log err "kamctlrc file [${kamctlrc}] does not exist!"
return $OCF_NOT_INSTALLED
fi
else
ocf_log debug "No monitoring via kamctl monitor because the parameter [kamctlrc] is empty."
fi
if [ ! -f ${OCF_RESKEY_conffile} ]; then
ocf_log err "Kamailio configuration file provided in the parameter conffile [${OCF_RESKEY_conffile}] does not exist!"
return $OCF_ERR_CONFIGURED
fi
case $OCF_RESKEY_proto in
"") ocf_log err "Parameter $OCF_RESKEY_proto is empty!"
return $OCF_ERR_CONFIGURED
;;
udp|tcp|udptcp) : OK
;;
*) ocf_log err "Parameter value $OCF_RESKEY_proto for parameter [proto] not yet supported!"
return $OCF_ERR_CONFIGURED
;;
esac
return $OCF_SUCCESS
}
if [ $# -ne 1 ]; then
usage
exit $OCF_ERR_ARGS
fi
case $__OCF_ACTION in
meta-data) meta_data
exit $OCF_SUCCESS
;;
start|stop|status|monitor)
kamailio_${__OCF_ACTION}
;;
validate-all) kamailio_validate_all
;;
notify) exit $OCF_SUCCESS
;;
usage) usage
exit $OCF_SUCCESS
;;
# reload) #Not supported by Kamailio, but not needed by pacemaker
# ;;
# recover #Not needed by pacemaker
# ;;
*) usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit $?
diff --git a/heartbeat/lxc b/heartbeat/lxc.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/lxc
rename to heartbeat/lxc.in
index 479e3ce5b..5e9d9393e
--- a/heartbeat/lxc
+++ b/heartbeat/lxc.in
@@ -1,374 +1,374 @@
-#!/bin/bash
+#!@BASH_SHELL@
# Should now conform to guidelines:
# https://github.com/ClusterLabs/resource-agents/blob/master/doc/dev-guides/ra-dev-guide.asc
#
# LXC (Linux Containers) OCF RA.
# Used to cluster enable the start, stop and monitoring of a LXC container.
#
# Copyright (c) 2011 AkurIT.com.au, Darren Thompson
# All Rights Reserved.
#
# Without limiting the rights of the original copyright holders
# This resource is licensed under GPL version 2
#
# 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.
# OCF instance parameters
# OCF_RESKEY_container
# OCF_RESKEY_config
# OCF_RESKEY_log
# OCF_RESKEY_use_screen
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
# Defaults
OCF_RESKEY_log_default="${HA_RSCTMP}/${OCF_RESOURCE_INSTANCE}.log"
OCF_RESKEY_use_screen_default="false"
: ${OCF_RESKEY_log=${OCF_RESKEY_log_default}}
: ${OCF_RESKEY_use_screen=${OCF_RESKEY_use_screen_default}}
# Set default TRANS_RES_STATE (temporary file to "flag" if resource was stated but not stopped)
TRANS_RES_STATE="${HA_RSCTMP}/${OCF_RESOURCE_INSTANCE}.state"
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="lxc">
<version>0.1</version>
<longdesc lang="en">Allows LXC containers to be managed by the cluster.
If the container is running "init" it will also perform an orderly shutdown.
It is 'assumed' that the 'init' system will do an orderly shudown if presented with a 'kill -PWR' signal.
On a 'sysvinit' this would require the container to have an inittab file containing "p0::powerfail:/sbin/init 0"
I have absolutly no idea how this is done with 'upstart' or 'systemd', YMMV if your container is using one of them.</longdesc>
<shortdesc lang="en">Manages LXC containers</shortdesc>
<parameters>
<parameter name="container" required="1" unique="1">
<longdesc lang="en">The unique name for this 'Container Instance' e.g. 'test1'.</longdesc>
<shortdesc lang="en">Container Name</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="config" required="1" unique="0">
<longdesc lang="en">Absolute path to the file holding the specific configuration for this container e.g. '/etc/lxc/test1/config'.</longdesc>
<shortdesc lang="en">The LXC config file.</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="log" required="0" unique="0">
<longdesc lang="en">Absolute path to the container log file</longdesc>
<shortdesc lang="en">Container log file</shortdesc>
<content type="string" default="${OCF_RESKEY_log_default}"/>
</parameter>
<parameter name="use_screen" required="0" unique="0">
<longdesc lang="en">Provides the option of capturing the 'root console' from the container and showing it on a separate screen.
To see the screen output run 'screen -r {container name}'
The default value is set to 'false', change to 'true' to activate this option</longdesc>
<shortdesc lang="en">Use 'screen' for container 'root console' output</shortdesc>
<content type="boolean" default="${OCF_RESKEY_use_screen_default}"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="10s" />
<action name="stop" timeout="30s" />
<action name="monitor" timeout="20s" interval="60s" depth="0"/>
<action name="validate-all" timeout="20s" />
<action name="meta-data" timeout="5s" />
</actions>
</resource-agent>
END
}
LXC_usage() {
cat <<END
usage: $0 {start|stop|monitor|validate-all|meta-data}
Expects to have a fully populated OCF RA-compliant environment set.
END
}
lxc_version() {
if have_binary lxc-version ; then
lxc-version | cut -d' ' -f 3
else # since LXC 1.0.0 all commands knows about --version
lxc-info --version
fi
}
cgroup_mounted() {
# test cgroup_mounted, mount if required
# Various possible overrides to cgroup mount point.
# If kernel supplies cgroup mount point, prefer it.
CGROUP_MOUNT_POINT=/var/run/lxc/cgroup
CGROUP_MOUNT_NAME=lxc
CGROUP_MOUNTED=false
[[ -d /sys/fs/cgroup ]] && CGROUP_MOUNT_POINT=/sys/fs/cgroup CGROUP_MOUNT_NAME=cgroup
# If cgroup already mounted, use it no matter where it is.
# If multiple cgroup mounts, prefer the one named lxc if any.
eval `awk 'BEGIN{P="";N=""}END{print("cgmp="P" cgmn="N)}($3=="cgroup"){N=$1;P=$2;if($1="lxc")exit}' /proc/mounts`
[[ "$cgmn" && "$cgmp" && -d "$cgmp" ]] && CGROUP_MOUNT_POINT=$cgmp CGROUP_MOUNT_NAME=$cgmn CGROUP_MOUNTED=true
$CGROUP_MOUNTED || {
[[ -d $CGROUP_MOUNT_POINT ]] || ocf_run mkdir -p $CGROUP_MOUNT_POINT
ocf_run mount -t cgroup $CGROUP_MOUNT_NAME $CGROUP_MOUNT_POINT
}
echo 1 >${CGROUP_MOUNT_POINT}/notify_on_release
return 0
}
LXC_start() {
# put this here as it's so long it gets messy later!!!
if ocf_is_true $OCF_RESKEY_use_screen; then
STARTCMD="screen -dmS ${OCF_RESKEY_container} lxc-start -f ${OCF_RESKEY_config} -n ${OCF_RESKEY_container} -o ${OCF_RESKEY_log}"
else
STARTCMD="lxc-start -f ${OCF_RESKEY_config} -n ${OCF_RESKEY_container} -o ${OCF_RESKEY_log} -d"
fi
LXC_status
if [ $? -eq $OCF_SUCCESS ]; then
ocf_log debug "Resource $OCF_RESOURCE_INSTANCE is already running"
ocf_run touch "${TRANS_RES_STATE}" || exit $OCF_ERR_GENERIC
return $OCF_SUCCESS
fi
cgroup_mounted
if [ $? -ne 0 ]; then
ocf_log err "Unable to find cgroup mount"
exit $OCF_ERR_GENERIC
fi
ocf_log info "Starting" ${OCF_RESKEY_container}
ocf_run ${STARTCMD} || exit $OCF_ERR_GENERIC
# Spin on status, wait for the cluster manager to time us out if
# we fail
while ! LXC_status; do
ocf_log info "Container ${OCF_RESKEY_container} has not started, waiting"
sleep 1
done
ocf_run touch "${TRANS_RES_STATE}" || exit $OCF_ERR_GENERIC
return $OCF_SUCCESS
}
LXC_stop() {
local shutdown_timeout
local now
LXC_status
if [ $? -eq $OCF_NOT_RUNNING ]; then
ocf_log debug "Resource $OCF_RESOURCE_INSTANCE is already stopped"
ocf_run rm -f $TRANS_RES_STATE
return $OCF_SUCCESS
fi
cgroup_mounted
if [ $? -ne 0 ]; then
ocf_log err "Unable to find cgroup mount"
exit $OCF_ERR_GENERIC
fi
# If the container is running "init" and is able to perform and orderly shutdown, then it should be done.
# It is 'assumed' that the 'init' system will do an orderly shudown if presented with a 'kill -PWR' signal.
# On a 'sysvinit' this would require the container to have an inittab file containing "p0::powerfail:/sbin/init 0"
declare -i PID=0
declare CMD=
# LXC prior 1.0.0
if ocf_version_cmp "`lxc_version`" 1.0.0 ; then
# This should work for traditional 'sysvinit' and 'upstart'
lxc-ps --name "${OCF_RESKEY_container}" -- -C init -o pid,comm |while read CN PID CMD ;do
[ $PID -gt 1 ] || continue
[ "$CMD" = "init" ] || continue
ocf_log info "Sending \"OS shut down\" instruction to" ${OCF_RESKEY_container} "as it was found to be using \"sysV init\" or \"upstart\""
kill -PWR $PID
done
# This should work for containers using 'systemd' instead of 'init'
lxc-ps --name "${OCF_RESKEY_container}" -- -C systemd -o pid,comm |while read CN PID CMD ;do
[ $PID -gt 1 ] || continue
[ "$CMD" = "systemd" ] || continue
ocf_log info "Sending \"OS shut down\" instruction to" ${OCF_RESKEY_container} "as it was found to be using \"systemd\""
kill -PWR $PID
done
else
PID=$(lxc-info --name "${OCF_RESKEY_container}" -p -H)
# If there is no PID the container seems to be down which
# shouldn't happen.
if [ $PID -eq 0 ]; then
ocf_log err "${OCF_RESKEY_container} seems to run, but has no PID."
exit $OCF_ERR_GENERIC
fi
# Rescue me.
if [ $PID -eq 1 ]; then
ocf_log err "${OCF_RESKEY_container} seems to run with PID 1 which cannot be."
PID=0
CMD=
else
CMD=$(ps -o comm= -p $PID)
fi
# This should work for traditional 'sysvinit' and 'upstart'
if [ "$CMD" = "init" ]; then
ocf_log info "Sending \"OS shut down\" instruction to" ${OCF_RESKEY_container} "as it was found to be using \"sysV init\" or \"upstart\""
kill -PWR $PID
fi
# This should work for containers using 'systemd' instead of 'init'
if [ "$CMD" = "systemd" ]; then
ocf_log info "Sending \"OS shut down\" instruction to" ${OCF_RESKEY_container} "as it was found to be using \"systemd\""
kill -PWR $PID
fi
fi
# The "shutdown_timeout" we use here is the operation
# timeout specified in the CIB, minus 5 seconds
now=$(date +%s)
shutdown_timeout=$(( $now + ($OCF_RESKEY_CRM_meta_timeout/1000) -5 ))
# Loop on status until we reach $shutdown_timeout
while [ $now -lt $shutdown_timeout ]; do
LXC_status
status=$?
case $status in
"$OCF_NOT_RUNNING")
ocf_run rm -f $TRANS_RES_STATE
return $OCF_SUCCESS
;;
"$OCF_SUCCESS")
# Container 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
# If the container is still running, it will be stopped now. regardless of state!
# LXC prior 1.0.0
if ocf_version_cmp "`lxc_version`" 1.0.0 ; then
ocf_run lxc-stop -n ${OCF_RESKEY_container} || exit $OCF_ERR_GENERIC
else
ocf_run lxc-stop -n ${OCF_RESKEY_container} -k || exit $OCF_ERR_GENERIC
fi
ocf_log info "Container" ${OCF_RESKEY_container} "stopped"
ocf_run rm -f $TRANS_RES_STATE
return $OCF_SUCCESS
}
LXC_status() {
# run lxc-info with -s option for LXC-0.7.5 or later
local lxc_info_opt="-s"
ocf_version_cmp "`lxc_version`" 0.7.5 && lxc_info_opt=""
S=`lxc-info $lxc_info_opt -n ${OCF_RESKEY_container}`
ocf_log debug "State of ${OCF_RESKEY_container}: $S"
if [[ "${S##* }" = "RUNNING" ]] ; then
return $OCF_SUCCESS
fi
return $OCF_NOT_RUNNING
}
LXC_monitor() {
LXC_status && return $OCF_SUCCESS
if [ -f $TRANS_RES_STATE ]; then
ocf_log err "${OCF_RESKEY_container} is not running, but state file ${TRANS_RES_STATE} exists."
exit $OCF_ERR_GENERIC
fi
return $OCF_NOT_RUNNING
}
LXC_validate() {
# Quick check that all required attributes are set
if [ -z "${OCF_RESKEY_container}" ]; then
ocf_log err "LXC container name not set!"
exit $OCF_ERR_CONFIGURED
fi
if [ -z "${OCF_RESKEY_config}" ]; then
ocf_log err "LXC configuration filename name not set!"
exit $OCF_ERR_CONFIGURED
fi
# Tests that apply only to non-probes
if ! ocf_is_probe; then
if ! [ -f "${OCF_RESKEY_config}" ]; then
ocf_log err "LXC configuration file \"${OCF_RESKEY_config}\" missing or not found!"
exit $OCF_ERR_INSTALLED
fi
if ocf_is_true $OCF_RESKEY_use_screen; then
check_binary screen
fi
check_binary lxc-start
check_binary lxc-stop
if ocf_version_cmp "`lxc_version`" 1.0.0 ; then
check_binary lxc-ps
fi
check_binary lxc-info
fi
return $OCF_SUCCESS
}
if [ $# -ne 1 ]; then
LXC_usage
exit $OCF_ERR_ARGS
fi
case $__OCF_ACTION in
meta-data) meta_data
exit $OCF_SUCCESS
;;
usage|help) LXC_usage
exit $OCF_SUCCESS
;;
esac
# Everything except usage and meta-data must pass the validate test
LXC_validate
case $__OCF_ACTION in
start) LXC_start;;
stop) LXC_stop;;
status) LXC_status;;
monitor) LXC_monitor;;
validate-all) ;;
*) LXC_usage
ocf_log err "$0 was called with unsupported arguments: $*"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
rc=$?
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
exit $rc
diff --git a/heartbeat/lxd-info b/heartbeat/lxd-info.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/lxd-info
rename to heartbeat/lxd-info.in
index df11984e2..44ec49948
--- a/heartbeat/lxd-info
+++ b/heartbeat/lxd-info.in
@@ -1,148 +1,148 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
#
# LXD Registration Service OCF Resource Agent
# It records (in the CIB) various attributes of a node
#
# Copyright (c) 2017 Mathieu Grzybek
# 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="lxd-info">
<version>1.0</version>
<longdesc lang="en">
This is a LXD Registration Service Resource Agent.
It records (in the CIB) attributes about the number of running LXD containers
running on the node.
Sample output:
lxd_containers: 5
</longdesc>
<shortdesc lang="en">Records various node attributes in the CIB</shortdesc>
<parameters>
<parameter name="pidfile" unique="0">
<longdesc lang="en">PID file</longdesc>
<shortdesc lang="en">PID file</shortdesc>
<content type="string" default="$OCF_RESKEY_pidfile" />
</parameter>
<parameter name="delay" unique="0">
<longdesc lang="en">Interval to allow values to stabilize</longdesc>
<shortdesc lang="en">Dampening Delay</shortdesc>
<content type="string" default="0s" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="20s" />
<action name="stop" timeout="20s" />
<action name="monitor" timeout="20s" interval="60s"/>
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="20s" />
</actions>
</resource-agent>
END
}
#######################################################################
LXDInfoStats() {
value=$(lxc list|grep -ci RUNNING)
echo -e "lxd_containers:\t$value"
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -S status -n lxd_containers -v $value
}
LXDInfo_usage() {
cat <<END
usage: $0 {start|stop|monitor|validate-all|meta-data}
Expects to have a fully populated OCF RA-compliant environment set.
END
}
LXDInfo_start() {
echo $OCF_RESKEY_clone > $OCF_RESKEY_pidfile
LXDInfoStats
exit $OCF_SUCCESS
}
LXDInfo_stop() {
rm -f $OCF_RESKEY_pidfile
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -D -S state -n lxd_containers
exit $OCF_SUCCESS
}
LXDInfo_monitor() {
if [ -f "$OCF_RESKEY_pidfile" ] ; then
LXDInfoStats
exit $OCF_RUNNING
fi
exit $OCF_NOT_RUNNING
}
LXDInfo_validate() {
return $OCF_SUCCESS
}
if [ $# -ne 1 ]; then
LXDInfo_usage
exit $OCF_ERR_ARGS
fi
: ${OCF_RESKEY_pidfile:="$HA_RSCTMP/LXDInfo-${OCF_RESOURCE_INSTANCE}"}
: ${OCF_RESKEY_clone:="0"}
if [ x != x${OCF_RESKEY_delay} ]; then
OCF_RESKEY_delay="-d ${OCF_RESKEY_delay}"
fi
case $__OCF_ACTION in
meta-data) meta_data
exit $OCF_SUCCESS
;;
start) LXDInfo_start
;;
stop) LXDInfo_stop
;;
monitor) LXDInfo_monitor
;;
validate-all) LXDInfo_validate
;;
usage|help) LXDInfo_usage
exit $OCF_SUCCESS
;;
*) LXDInfo_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit $?
diff --git a/heartbeat/machine-info b/heartbeat/machine-info.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/machine-info
rename to heartbeat/machine-info.in
index 36f973c7b..0622b86a0
--- a/heartbeat/machine-info
+++ b/heartbeat/machine-info.in
@@ -1,149 +1,149 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
#
# Virtual Machine and Container Registration Service OCF Resource Agent
# It records (in the CIB) various attributes of a node
#
# Copyright (c) 2017 Mathieu Grzybek
# 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="machine-info">
<version>1.0</version>
<longdesc lang="en">
This is a Virtual Machine and Container Registration Service Resource Agent.
It records (in the CIB) attributes about the number of running virtual machines
and containers running on the node.
It uses systemd machinectl.
Sample output:
machines: 5
</longdesc>
<shortdesc lang="en">Records various node attributes in the CIB</shortdesc>
<parameters>
<parameter name="pidfile" unique="0">
<longdesc lang="en">PID file</longdesc>
<shortdesc lang="en">PID file</shortdesc>
<content type="string" default="$OCF_RESKEY_pidfile" />
</parameter>
<parameter name="delay" unique="0">
<longdesc lang="en">Interval to allow values to stabilize</longdesc>
<shortdesc lang="en">Dampening Delay</shortdesc>
<content type="string" default="0s" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="20s" />
<action name="stop" timeout="20s" />
<action name="monitor" timeout="20s" interval="60s"/>
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="20s" />
</actions>
</resource-agent>
END
}
#######################################################################
MachineInfoStats() {
value=$(machinectl|awk '/machines listed/ {print $1}')
echo -e "machines:\t$value"
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -S status -n machines -v $value
}
MachineInfo_usage() {
cat <<END
usage: $0 {start|stop|monitor|validate-all|meta-data}
Expects to have a fully populated OCF RA-compliant environment set.
END
}
MachineInfo_start() {
echo $OCF_RESKEY_clone > $OCF_RESKEY_pidfile
MachineInfoStats
exit $OCF_SUCCESS
}
MachineInfo_stop() {
rm -f $OCF_RESKEY_pidfile
${HA_SBIN_DIR}/attrd_updater ${OCF_RESKEY_delay} -D -S state -n machines
exit $OCF_SUCCESS
}
MachineInfo_monitor() {
if [ -f "$OCF_RESKEY_pidfile" ] ; then
MachineInfoStats
exit $OCF_RUNNING
fi
exit $OCF_NOT_RUNNING
}
MachineInfo_validate() {
return $OCF_SUCCESS
}
if [ $# -ne 1 ]; then
MachineInfo_usage
exit $OCF_ERR_ARGS
fi
: ${OCF_RESKEY_pidfile:="$HA_RSCTMP/MachineInfo-${OCF_RESOURCE_INSTANCE}"}
: ${OCF_RESKEY_clone:="0"}
if [ x != x${OCF_RESKEY_delay} ]; then
OCF_RESKEY_delay="-d ${OCF_RESKEY_delay}"
fi
case $__OCF_ACTION in
meta-data) meta_data
exit $OCF_SUCCESS
;;
start) MachineInfo_start
;;
stop) MachineInfo_stop
;;
monitor) MachineInfo_monitor
;;
validate-all) MachineInfo_validate
;;
usage|help) MachineInfo_usage
exit $OCF_SUCCESS
;;
*) MachineInfo_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit $?
diff --git a/heartbeat/mariadb b/heartbeat/mariadb.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/mariadb
rename to heartbeat/mariadb.in
index b2635dfee..860fea7fd
--- a/heartbeat/mariadb
+++ b/heartbeat/mariadb.in
@@ -1,1058 +1,1058 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
#
# MariaDB
#
# Description: Manages a MariaDB Master/Slave database as Linux-HA resource
#
# Authors: Alan Robertson: DB2 Script
# Jakub Janczak: rewrite as MySQL
# Andrew Beekhof: cleanup and import
# Sebastian Reitenbach: add OpenBSD defaults, more cleanup
# Narayan Newton: add Gentoo/Debian defaults
# Marian Marinov, Florian Haas: add replication capability
# Yves Trudeau, Baron Schwartz: add VIP support and improve replication
# Nils Carlson: add GTID support and semi-sync support
#
# Support: users@clusterlabs.org
# License: GNU General Public License (GPL)
#
# (c) 2002-2005 International Business Machines, Inc.
# 2005-2010 Linux-HA contributors
#
# See usage() function below for more details...
#
# OCF instance parameters:
# OCF_RESKEY_binary
# OCF_RESKEY_client_binary
# OCF_RESKEY_config
# OCF_RESKEY_datadir
# OCF_RESKEY_user
# OCF_RESKEY_group
# OCF_RESKEY_node_list
# OCF_RESKEY_test_table
# OCF_RESKEY_test_user
# OCF_RESKEY_test_passwd
# OCF_RESKEY_enable_creation
# OCF_RESKEY_additional_parameters
# OCF_RESKEY_log
# OCF_RESKEY_pid
# OCF_RESKEY_socket
# OCF_RESKEY_replication_user
# OCF_RESKEY_replication_passwd
# OCF_RESKEY_replication_port
#######################################################################
# Initialization:
OCF_RESKEY_node_list_default=""
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
. ${OCF_FUNCTIONS_DIR}/mysql-common.sh
#######################################################################
usage() {
cat <<UEND
usage: $0 (start|stop|validate-all|meta-data|monitor|promote|demote|notify)
$0 manages a MariaDB Database as an HA resource.
The 'start' operation starts the database.
The 'stop' operation stops the database.
The 'status' operation reports whether the database is running
The 'monitor' operation reports whether the database seems to be working
The 'promote' operation makes this mysql server run as master
The 'demote' operation makes this mysql server run as slave
The 'validate-all' operation reports whether the parameters are valid
UEND
}
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="mariadb">
<version>1.0</version>
<longdesc lang="en">
Resource script for MariaDB.
Manages a complete master/slave replication setup with GTID, for simpler
uses look at the mysql resource agent which supports older replication
forms which mysql and mariadb have in common.
The resource must be setup to use notifications. Set 'notify=true' in the metadata
attributes when defining a MariaDB master/slave instance.
The default behavior is to use uname -n values in the change master to command.
Other IPs can be specified manually by adding a node attribute
\${INSTANCE_ATTR_NAME}_mysql_master_IP giving the IP to use for replication.
For example, if the mariadb primitive you are using is p_mariadb, the
attribute to set will be p_mariadb_mysql_master_IP.
</longdesc>
<shortdesc lang="en">Manages a MariaDB master/slave instance</shortdesc>
<parameters>
<parameter name="binary" unique="0" required="0">
<longdesc lang="en">
Location of the MariaDB server binary
</longdesc>
<shortdesc lang="en">MariaDB server binary</shortdesc>
<content type="string" default="${OCF_RESKEY_binary_default}" />
</parameter>
<parameter name="client_binary" unique="0" required="0">
<longdesc lang="en">
Location of the MariaDB client binary
</longdesc>
<shortdesc lang="en">MariaDB client binary</shortdesc>
<content type="string" default="${OCF_RESKEY_client_binary_default}" />
</parameter>
<parameter name="config" unique="0" required="0">
<longdesc lang="en">
Configuration file
</longdesc>
<shortdesc lang="en">MariaDB config</shortdesc>
<content type="string" default="${OCF_RESKEY_config_default}" />
</parameter>
<parameter name="datadir" unique="0" required="0">
<longdesc lang="en">
Directory containing databases
</longdesc>
<shortdesc lang="en">MariaDB datadir</shortdesc>
<content type="string" default="${OCF_RESKEY_datadir_default}" />
</parameter>
<parameter name="user" unique="0" required="0">
<longdesc lang="en">
User running MariaDB daemon
</longdesc>
<shortdesc lang="en">MariaDB user</shortdesc>
<content type="string" default="${OCF_RESKEY_user_default}" />
</parameter>
<parameter name="group" unique="0" required="0">
<longdesc lang="en">
Group running MariaDB daemon (for logfile and directory permissions)
</longdesc>
<shortdesc lang="en">MariaDB group</shortdesc>
<content type="string" default="${OCF_RESKEY_group_default}"/>
</parameter>
<parameter name="log" unique="0" required="0">
<longdesc lang="en">
The logfile to be used for mysqld.
</longdesc>
<shortdesc lang="en">MariaDB log file</shortdesc>
<content type="string" default="${OCF_RESKEY_log_default}"/>
</parameter>
<parameter name="node_list" unique="0" required="1">
<longdesc lang="en">
All node names of nodes that will execute mariadb.
Please separate each node name with a space.
This is required for the master selection to function.
</longdesc>
<shortdesc lang="en">node list</shortdesc>
<content type="string" default="${OCF_RESKEY_node_list_default}" />
</parameter>
<parameter name="pid" unique="0" required="0">
<longdesc lang="en">
The pidfile to be used for mysqld.
</longdesc>
<shortdesc lang="en">MariaDB pid file</shortdesc>
<content type="string" default="${OCF_RESKEY_pid_default}"/>
</parameter>
<parameter name="socket" unique="0" required="0">
<longdesc lang="en">
The socket to be used for mysqld.
</longdesc>
<shortdesc lang="en">MariaDB socket</shortdesc>
<content type="string" default="${OCF_RESKEY_socket_default}"/>
</parameter>
<parameter name="test_table" unique="0" required="0">
<longdesc lang="en">
Table to be tested in monitor statement (in database.table notation)
</longdesc>
<shortdesc lang="en">MariaDB test table</shortdesc>
<content type="string" default="${OCF_RESKEY_test_table_default}" />
</parameter>
<parameter name="test_user" unique="0" required="0">
<longdesc lang="en">
MariaDB test user, must have select privilege on test_table
</longdesc>
<shortdesc lang="en">MariaDB test user</shortdesc>
<content type="string" default="${OCF_RESKEY_test_user_default}" />
</parameter>
<parameter name="test_passwd" unique="0" required="0">
<longdesc lang="en">
MariaDB test user password
</longdesc>
<shortdesc lang="en">MariaDB test user password</shortdesc>
<content type="string" default="${OCF_RESKEY_test_passwd_default}" />
</parameter>
<parameter name="enable_creation" unique="0" required="0">
<longdesc lang="en">
If the MariaDB database does not exist, it will be created
</longdesc>
<shortdesc lang="en">Create the database if it does not exist</shortdesc>
<content type="boolean" default="${OCF_RESKEY_enable_creation_default}"/>
</parameter>
<parameter name="additional_parameters" unique="0" required="0">
<longdesc lang="en">
Additional parameters which are passed to the mysqld on startup.
(e.g. --skip-external-locking or --skip-grant-tables)
</longdesc>
<shortdesc lang="en">Additional parameters to pass to mysqld</shortdesc>
<content type="string" default="${OCF_RESKEY_additional_parameters_default}"/>
</parameter>
<parameter name="replication_user" unique="0" required="0">
<longdesc lang="en">
MariaDB replication user. This user is used for starting and stopping
MariaDB replication, for setting and resetting the master host, and for
setting and unsetting read-only mode. Because of that, this user must
have SUPER, REPLICATION SLAVE, REPLICATION CLIENT, PROCESS and RELOAD
privileges on all nodes within the cluster. Mandatory if you define a
master-slave resource.
</longdesc>
<shortdesc lang="en">MariaDB replication user</shortdesc>
<content type="string" default="${OCF_RESKEY_replication_user_default}" />
</parameter>
<parameter name="replication_passwd" unique="0" required="0">
<longdesc lang="en">
MariaDB replication password. Used for replication client and slave.
Mandatory if you define a master-slave resource.
</longdesc>
<shortdesc lang="en">MariaDB replication user password</shortdesc>
<content type="string" default="${OCF_RESKEY_replication_passwd_default}" />
</parameter>
<parameter name="replication_port" unique="0" required="0">
<longdesc lang="en">
The port on which the Master MariaDB instance is listening.
</longdesc>
<shortdesc lang="en">MariaDB replication port</shortdesc>
<content type="string" default="${OCF_RESKEY_replication_port_default}" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="120" />
<action name="stop" timeout="120" />
<action name="status" timeout="60" />
<action name="monitor" depth="0" timeout="30" interval="20" />
<action name="monitor" role="Master" depth="0" timeout="30" interval="10" />
<action name="monitor" role="Slave" depth="0" timeout="30" interval="30" />
<action name="promote" timeout="120" />
<action name="demote" timeout="120" />
<action name="notify" timeout="90" />
<action name="validate-all" timeout="5" />
<action name="meta-data" timeout="5" />
</actions>
</resource-agent>
END
}
# Convenience functions
greater_than_equal_long()
{
# there are values we need to compare in this script
# that are too large for shell -gt to process
local true=$(echo "$1 > $2" | bc)
if [ "$true" -eq "1" ]; then
return 0
else
return 1
fi
}
greater_than_gtid()
{
local gtid1_transaction_id=$(echo $1 | cut -d - -f 3)
local gtid2_transaction_id=$(echo $2 | cut -d - -f 3)
greater_than_equal_long $gtid1_transaction_id $gtid2_transaction_id
return $?
}
set_gtid() {
# Sets the GTID in CIB using attrd_updater for this node.
local gtid=$($MYSQL $MYSQL_OPTIONS_REPL \
-s -N -e "show global variables like 'gtid_current_pos'" | cut -f 2)
# Ensure that we got somethine like a valid GTID
if ! echo $gtid | grep -q '-'; then
ocf_exit_reason "Unable to read GTID from MariaDB"
ocf_log err "Unable to read GTID from MariaDB"
return $OCF_ERR_GENERIC
fi
${HA_SBIN_DIR}/attrd_updater -p -n ${OCF_RESOURCE_INSTANCE}-gtid -U $gtid
}
read_gtid() {
local node=$1
local query_result
local name
local host
local value
# This produces output of the form 'name="var-name" host="node2" value="val"'.
# This should be set at this point, because we have store our own GTID previously.
if ! query_result=$(${HA_SBIN_DIR}/attrd_updater -p -N $node -n ${OCF_RESOURCE_INSTANCE}-gtid -Q); then
ocf_exit_reason "Unable to read GTID from attrd"
ocf_log err "Unable to read GTID from attrd"
echo ""
return
fi
# Evaluate the query result to place the variables in the local scope.
eval ${query_result}
echo ${value}
}
clear_all_gtid() {
for node in $OCF_RESKEY_node_list; do
${HA_SBIN_DIR}/attrd_updater -n ${OCF_RESOURCE_INSTANCE}-gtid -N $node -D
done
}
set_waiting_for_first_master() {
${HA_SBIN_DIR}/attrd_updater -p -n ${OCF_RESOURCE_INSTANCE}-waiting-for-first-master -U true
}
waiting_for_first_master() {
local query_result
local name
local host
local value
if ! query_result=$(${HA_SBIN_DIR}/attrd_updater -p -n ${OCF_RESOURCE_INSTANCE}-waiting-for-first-master -Q); then
ocf_exit_reason "Unable to read waiting-for-first-master from attrd"
ocf_log err "Unable to read waiting-for-first-master from attrd"
return 1
fi
# Evaluate the query result to place the variables in the local scope.
eval ${query_result}
if [ "$value" = "true" ]; then
return 0
else
return 1
fi
}
clear_waiting_for_first_master() {
attrd_updater -n ${OCF_RESOURCE_INSTANCE}-waiting-for-first-master -D
}
have_master_with_priority() {
# Go through each node and validate that at least one has
# a set priority. Because we unset the priority on reboot
# a lack of priority indicates that we need to select a
# new master.
for node in $OCF_RESKEY_node_list; do
$CRM_MASTER -G -N $node >/dev/null 2>&1
rc=$?
if [ $rc -eq 0 ]; then
return 0
fi
done
return 1
}
attempt_to_set_master() {
ocf_log info "Attempting to set master"
local expected_node_count
if waiting_for_first_master; then
# Wait for all nodes to come online
expected_node_count=$OCF_RESKEY_CRM_meta_clone_max
else
# We accept one node being down. This is not arbitrary,
# synchronous replication requires acknowledgement from
# at least one host, which means only two nodes must have
# the latest GTID. So a set of n - 1 ensures that we do
# not lose any writes.
expected_node_count=$(($OCF_RESKEY_CRM_meta_clone_max-1))
fi
# Set the gtid for this node, making it available to other nodes
set_gtid
local node_count=0
local highest_gtid=0
local master_candidate=""
for node in $OCF_RESKEY_node_list; do
local node_gtid=$(read_gtid $node)
if [ -z "$node_gtid" ]; then
continue
fi
# Got a valid gtid, increment node count
node_count=$(($node_count+1))
# Check if this is a good master candidate
if greater_than_gtid $node_gtid $highest_gtid; then
master_candidate=$node
highest_gtid=$node_gtid
fi
done
# If we managed to query a sufficient number of nodes
# then set a master
if [ $node_count -ge $expected_node_count ]; then
ocf_log info "Promoting $master_candidate to master, highest gtid $highest_gtid, queried $node_count nodes."
$CRM_MASTER -v 100 -N $master_candidate
else
ocf_log info "Not enough nodes ($node_count) contributed to select a master, need $expected_node_count nodes."
fi
}
set_read_only() {
# Sets or unsets read-only mode. Accepts one boolean as its
# optional argument. If invoked without any arguments, defaults to
# enabling read only mode. Should only be set in master/slave
# setups.
# Returns $OCF_SUCCESS if the operation succeeds, or
# $OCF_ERR_GENERIC if it fails.
local ro_val
if ocf_is_true $1; then
ro_val="on"
else
ro_val="off"
fi
ocf_run $MYSQL $MYSQL_OPTIONS_REPL \
-e "SET GLOBAL read_only=${ro_val}"
}
get_read_only() {
# Check if read-only is set
local read_only_state
read_only_state=$($MYSQL $MYSQL_OPTIONS_REPL \
-e "SHOW VARIABLES" | grep -w read_only | awk '{print $2}')
if [ "$read_only_state" = "ON" ]; then
return 0
else
return 1
fi
}
is_slave() {
# Determine whether the machine is currently running as a MariaDB
# slave, as determined per SHOW SLAVE STATUS. Returns 1 if SHOW
# SLAVE STATUS creates an empty result set, 0 otherwise.
local rc
# Check whether this machine should be slave
if ! get_read_only; then
return 1
fi
if get_slave_info; then
# show slave status is not empty
# Is the slave sql thread running, then we are a slave!
if [ "$slave_sql" == 'Yes' ]; then
return 0
else
return 1
fi
else
# "SHOW SLAVE STATUS" returns an empty set if instance is not a
# replication slave
return 1
fi
}
parse_slave_info() {
# Extracts field $1 from result of "SHOW SLAVE STATUS\G" from file $2
sed -ne "s/^.* $1: \(.*\)$/\1/p" < $2
}
get_slave_info() {
if [ "$master_log_file" -a "$master_host" ]; then
# variables are already defined, get_slave_info has been run before
return $OCF_SUCCESS
else
local tmpfile=$(mktemp ${HA_RSCTMP}/check_slave.${OCF_RESOURCE_INSTANCE}.XXXXXX)
$MYSQL $MYSQL_OPTIONS_REPL \
-e 'SHOW SLAVE STATUS\G' > $tmpfile
if [ -s $tmpfile ]; then
master_host=$(parse_slave_info Master_Host $tmpfile)
master_user=$(parse_slave_info Master_User $tmpfile)
master_port=$(parse_slave_info Master_Port $tmpfile)
master_using_gtid=$(parse_slave_info Using_Gtid $tmpfile)
master_log_file=$(parse_slave_info Master_Log_File $tmpfile)
slave_sql=$(parse_slave_info Slave_SQL_Running $tmpfile)
slave_io=$(parse_slave_info Slave_IO_Running $tmpfile)
last_errno=$(parse_slave_info Last_Errno $tmpfile)
last_error=$(parse_slave_info Last_Error $tmpfile)
secs_behind=$(parse_slave_info Seconds_Behind_Master $tmpfile)
last_io_errno=$(parse_slave_info Last_IO_Errno $tmpfile)
last_io_error=$(parse_slave_info Last_IO_Error $tmpfile)
ocf_log debug "MariaDB instance running as a replication slave"
rm "$tmpfile"
else
# Instance produced an empty "SHOW SLAVE STATUS" output --
# instance is not a slave
rm "$tmpfile"
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
fi
}
check_slave() {
# Checks slave status
local rc new_master
get_slave_info
rc=$?
if [ $rc -eq 0 ]; then
# Check normal errors
if [ $last_errno -ne 0 ]; then
ocf_exit_reason "MariaDB slave replication has failed ($last_errno): $last_error"
exit $OCF_ERR_GENERIC
fi
# Check IO Errors, ignore 2003 which indicates a connection failure to the master
if [ $last_io_errno -ne 0 ] && [ $last_io_errno -ne 2003 ]; then
ocf_exit_reason "MariaDB slave io has failed ($last_io_errno): $last_io_error"
exit $OCF_ERR_GENERIC
fi
if [ $last_io_errno -eq 2003 ]; then
ocf_log warn "MariaDB master not reachable from slave"
fi
if [ "$slave_io" != 'Yes' ]; then
# Not necessarily a bad thing. The master may have
# temporarily shut down, and the slave may just be
# reconnecting. A warning can't hurt, though.
ocf_log warn "MariaDB Slave IO threads currently not running."
# Sanity check, are we at least on the right master
new_master=$($CRM_ATTR_REPL_INFO --query -q)
if [ "$master_host" != "$new_master" ]; then
# Not pointing to the right master, not good, removing the VIPs
set_reader_attr 0
exit $OCF_SUCCESS
fi
fi
if [ "$slave_sql" != 'Yes' ]; then
# We don't have a replication SQL thread running. Not a
# good thing. Try to recoved by restarting the SQL thread
# and remove reader vip. Prevent MariaDB restart.
ocf_exit_reason "MariaDB Slave SQL threads currently not running."
# Remove reader vip
set_reader_attr 0
# try to restart slave
ocf_run $MYSQL $MYSQL_OPTIONS_REPL \
-e "START SLAVE"
# Return success to prevent a restart
exit $OCF_SUCCESS
fi
ocf_log debug "MariaDB instance running as a replication slave"
else
# Instance produced an empty "SHOW SLAVE STATUS" output --
# instance is not a slave
# TODO: Needs to handle when get_slave_info will return too many connections error
ocf_exit_reason "check_slave invoked on an instance that is not a replication slave."
exit $OCF_ERR_GENERIC
fi
}
set_master() {
local new_master=$($CRM_ATTR_REPL_INFO --query -q)
# Informs the MariaDB server of the master to replicate
# from. Accepts one mandatory argument which must contain the host
# name of the new master host. The master must either be unchanged
# from the laste master the slave replicated from, or freshly
# reset with RESET MASTER.
ocf_log info "Changing MariaDB configuration to replicate from $new_master."
ocf_run $MYSQL $MYSQL_OPTIONS_REPL \
-e "CHANGE MASTER TO MASTER_HOST='$new_master', \
MASTER_PORT=$OCF_RESKEY_replication_port, \
MASTER_USER='$OCF_RESKEY_replication_user', \
MASTER_PASSWORD='$OCF_RESKEY_replication_passwd', \
MASTER_USE_GTID=current_pos";
}
unset_master(){
# Instructs the MariaDB server to stop replicating from a master
# host.
# If we're currently not configured to be replicating from any
# host, then there's nothing to do. But we do log a warning as
# no-one but the CRM should be touching the MariaDB master/slave
# configuration.
if ! is_slave; then
ocf_log warn "Attempted to unset the replication master on an instance that is not configured as a replication slave"
return $OCF_SUCCESS
fi
# Stop the slave I/O thread and wait for relay log
# processing to complete
ocf_run $MYSQL $MYSQL_OPTIONS_REPL \
-e "STOP SLAVE IO_THREAD"
if [ $? -gt 0 ]; then
ocf_exit_reason "Error stopping slave IO thread"
exit $OCF_ERR_GENERIC
fi
local tmpfile=$(mktemp ${HA_RSCTMP}/threads.${OCF_RESOURCE_INSTANCE}.XXXXXX)
while true; do
$MYSQL $MYSQL_OPTIONS_REPL \
-e 'SHOW PROCESSLIST\G' > $tmpfile
if grep -i 'Has read all relay log' $tmpfile >/dev/null; then
ocf_log info "MariaDB slave has finished processing relay log"
break
fi
if ! grep -q 'system user' $tmpfile; then
ocf_log info "Slave not runnig - not waiting to finish"
break
fi
ocf_log info "Waiting for MariaDB slave to finish processing relay log"
sleep 1
done
rm -f $tmpfile
# Now, stop all slave activity and unset the master host
ocf_run $MYSQL $MYSQL_OPTIONS_REPL \
-e "STOP SLAVE"
if [ $? -gt 0 ]; then
ocf_exit_reason "Error stopping rest slave threads"
exit $OCF_ERR_GENERIC
fi
ocf_run $MYSQL $MYSQL_OPTIONS_REPL \
-e "RESET SLAVE /*!50516 ALL */;"
if [ $? -gt 0 ]; then
ocf_exit_reason "Failed to reset slave"
exit $OCF_ERR_GENERIC
fi
}
# Start replication as slave
start_slave() {
ocf_run $MYSQL $MYSQL_OPTIONS_REPL \
-e "START SLAVE"
}
# Set the attribute controlling the readers VIP
set_reader_attr() {
local curr_attr_value
curr_attr_value=$(get_reader_attr)
if [ "$curr_attr_value" -ne "$1" ]; then
$CRM_ATTR -l reboot --name ${OCF_RESKEY_reader_attribute} -v $1
fi
}
# get the attribute controlling the readers VIP
get_reader_attr() {
local attr_value
local rc
attr_value=$($CRM_ATTR -l reboot --name ${OCF_RESKEY_reader_attribute} --query -q)
rc=$?
if [ "$rc" -eq "0" ]; then
echo $attr_value
else
echo -1
fi
}
# Determines what IP address is attached to the current host. The output of the
# crm_attribute command looks like this:
# scope=nodes name=IP value=10.2.2.161
# If the ${INSTANCE_ATTR_NAME}_MYSQL_MASTER_IP node attribute is not defined, fallback is to uname -n
# The ${INSTANCE_ATTR_NAME}_MYSQL_MASTER_IP is the IP address that will be used for the
# change master to command.
get_local_ip() {
local IP
IP=$($CRM_ATTR -l forever -n ${INSTANCE_ATTR_NAME}_mysql_master_IP -q -G 2>/dev/null)
if [ ! $? -eq 0 ]; then
uname -n
else
echo $IP
fi
}
#######################################################################
# Functions invoked by resource manager actions
mysql_monitor() {
local rc
local status_loglevel="err"
# Set loglevel to info during probe
if ocf_is_probe; then
status_loglevel="info"
fi
mysql_common_status $status_loglevel
rc=$?
# If status returned an error, return that immediately
if [ $rc -ne $OCF_SUCCESS ]; then
return $rc
fi
# Check if this instance is configured as a slave, and if so
# check slave status
if is_slave; then
if ! check_slave; then
return $OCF_ERR_GENERIC
fi
fi
if [ -n "$OCF_RESKEY_test_table" ]; then
# Check for test table
ocf_run -q $MYSQL $MYSQL_OPTIONS_TEST \
-e "SELECT COUNT(*) FROM $OCF_RESKEY_test_table"
rc=$?
if [ $rc -ne 0 ]; then
ocf_exit_reason "Failed to select from $test_table";
return $OCF_ERR_GENERIC;
fi
fi
# Check if we are in read-only mode and there is no master
# with priority then we attempt to select a master
if get_read_only && ! have_master_with_priority; then
attempt_to_set_master
fi
if ! get_read_only; then
ocf_log debug "MariaDB monitor succeeded (master)";
return $OCF_RUNNING_MASTER
else
ocf_log debug "MariaDB monitor succeeded";
return $OCF_SUCCESS
fi
}
mysql_start() {
local rc
if ! ocf_is_ms; then
ocf_exit_reason "Resource is not configured as master/slave"
return $OCF_ERR_GENERIC
fi
# Initialize the ReaderVIP attribute, monitor will enable it
set_reader_attr 0
mysql_common_status info
if [ $? = $OCF_SUCCESS ]; then
ocf_log info "MariaDB already running"
return $OCF_SUCCESS
fi
mysql_common_prepare_dirs
mysql_common_start --skip-slave-start --log-slave-updates
rc=$?
if [ $rc != $OCF_SUCCESS ]; then
return $rc
fi
# Enable semi-sync
ocf_run -q $MYSQL $MYSQL_OPTIONS_TEST \
-e "SET GLOBAL rpl_semi_sync_slave_enabled='ON', \
rpl_semi_sync_master_enabled='ON', \
rpl_semi_sync_master_wait_no_slave='OFF', \
rpl_semi_sync_master_wait_point='AFTER_SYNC', \
gtid_strict_mode='ON', \
sync_binlog=1, \
sync_master_info=1, \
innodb_flush_log_at_trx_commit=1;"
rc=$?
if [ $rc -ne 0 ]; then
ocf_exit_reason "Failed to enable semi-sync and set variables";
return $OCF_ERR_GENERIC;
fi
# We're configured as a stateful resource. We must start as
# slave by default. At this point we don't know if the CRM has
# already promoted a master. So, we simply start in read only
# mode and make sure our old score is invalidated.
set_read_only on
$CRM_MASTER -D
# Now, let's see whether there is a master. We might be a new
# node that is just joining the cluster, and the CRM may have
# promoted a master before.
new_master_host=$(echo $OCF_RESKEY_CRM_meta_notify_master_uname|tr -d " ")
if [ "$new_master_host" -a "$new_master_host" != ${NODENAME} ]; then
set_master
start_slave
if [ $? -ne 0 ]; then
ocf_exit_reason "Failed to start slave"
return $OCF_ERR_GENERIC
fi
else
ocf_log info "No MariaDB master present - clearing replication state, setting gtid in attrd, waiting for first master"
unset_master
set_waiting_for_first_master
fi
# Initial monitor action
if [ -n "$OCF_RESKEY_test_table" -a -n "$OCF_RESKEY_test_user" -a -n "$OCF_RESKEY_test_passwd" ]; then
OCF_CHECK_LEVEL=10
fi
mysql_monitor
rc=$?
if [ $rc != $OCF_SUCCESS -a $rc != $OCF_RUNNING_MASTER ]; then
ocf_exit_reason "Failed initial monitor action"
return $rc
fi
ocf_log info "MariaDB started"
return $OCF_SUCCESS
}
mysql_stop() {
# clear preference for becoming master
$CRM_MASTER -D
# Remove VIP capability
set_reader_attr 0
mysql_common_stop
}
mysql_promote() {
local master_info
if ( ! mysql_common_status err ); then
return $OCF_NOT_RUNNING
fi
ocf_run $MYSQL $MYSQL_OPTIONS_REPL \
-e "STOP SLAVE"
set_read_only off || return $OCF_ERR_GENERIC
# Force the master to wait for timeout period on slave disconnect
ocf_run -q $MYSQL $MYSQL_OPTIONS_TEST \
-e "SET GLOBAL rpl_semi_sync_master_wait_no_slave='ON';"
# Set Master Info in CIB, cluster level attribute
master_info="$(get_local_ip)"
${CRM_ATTR_REPL_INFO} -v "$master_info"
# A master can accept reads
set_reader_attr 1
# Clear the gtids in attrd now that there is a master
clear_all_gtid
return $OCF_SUCCESS
}
mysql_demote() {
if ! mysql_common_status err; then
return $OCF_NOT_RUNNING
fi
# Return to default no wait setting.
ocf_run -q $MYSQL $MYSQL_OPTIONS_TEST \
-e "SET GLOBAL rpl_semi_sync_master_wait_no_slave='OFF';"
# Return master preference to default, so the cluster manager gets
# a chance to select a new master
$CRM_MASTER -D
}
mysql_notify() {
local type_op
type_op="${OCF_RESKEY_CRM_meta_notify_type}-${OCF_RESKEY_CRM_meta_notify_operation}"
ocf_log debug "Received $type_op notification."
case "$type_op" in
'pre-promote')
# A master is now being promoted, remove the waiting-for-first-master flag
clear_waiting_for_first_master
;;
'post-promote')
# The master has completed its promotion. Now is a good
# time to check whether our replication slave is working
# correctly.
new_master_host=$(echo $OCF_RESKEY_CRM_meta_notify_promote_uname|tr -d " ")
if [ "$new_master_host" = ${NODENAME} ]; then
ocf_log info "This will be the new master, ignoring post-promote notification."
else
ocf_log info "Resetting replication, uname of master: $new_master_host"
unset_master
if [ $? -ne 0 ]; then
return $OCF_ERR_GENERIC
fi
set_master
if [ $? -ne 0 ]; then
return $OCF_ERR_GENERIC
fi
start_slave
if [ $? -ne 0 ]; then
ocf_exit_reason "Failed to start slave"
return $OCF_ERR_GENERIC
fi
fi
return $OCF_SUCCESS
;;
'pre-demote')
demote_host=$(echo $OCF_RESKEY_CRM_meta_notify_demote_uname|tr -d " ")
if [ $demote_host = ${NODENAME} ]; then
ocf_log info "pre-demote notification for $demote_host"
set_read_only on
if [ $? -ne 0 ]; then
ocf_exit_reason "Failed to set read-only";
return $OCF_ERR_GENERIC;
fi
# Must kill all existing user threads because they are still Read/write
# in order for the slaves to complete the read of binlogs
local tmpfile=$(mktemp ${HA_RSCTMP}/threads.${OCF_RESOURCE_INSTANCE}.XXXXXX)
$MYSQL $MYSQL_OPTIONS_REPL -e "SHOW PROCESSLIST" > $tmpfile
for thread in $(awk '$0 !~ /Binlog Dump|system user|event_scheduler|SHOW PROCESSLIST/ && $0 ~ /^[0-9]/ {print $1}' $tmpfile)
do
ocf_run $MYSQL $MYSQL_OPTIONS_REPL \
-e "KILL ${thread}"
done
rm -f $tmpfile
else
ocf_log info "Ignoring post-demote notification execpt for my own demotion."
fi
return $OCF_SUCCESS
;;
'post-demote')
demote_host=$(echo $OCF_RESKEY_CRM_meta_notify_demote_uname|tr -d " ")
if [ $demote_host = ${NODENAME} ]; then
ocf_log info "Ignoring post-demote notification for my own demotion."
return $OCF_SUCCESS
fi
ocf_log info "post-demote notification for $demote_host."
# The former master has just been gracefully demoted.
unset_master
;;
*)
return $OCF_SUCCESS
;;
esac
}
#######################################################################
##########################################################################
# If DEBUG_LOG is set, make this resource agent easy to debug: set up the
# debug log and direct all output to it. Otherwise, redirect to /dev/null.
# The log directory must be a directory owned by root, with permissions 0700,
# and the log must be writable and not a symlink.
##########################################################################
DEBUG_LOG="/tmp/mysql.ocf.ra.debug/log"
if [ "${DEBUG_LOG}" -a -w "${DEBUG_LOG}" -a ! -L "${DEBUG_LOG}" ]; then
DEBUG_LOG_DIR="${DEBUG_LOG%/*}"
if [ -d "${DEBUG_LOG_DIR}" ]; then
exec 9>>"$DEBUG_LOG"
exec 2>&9
date >&9
echo "$*" >&9
env | grep OCF_ | sort >&9
set -x
else
exec 9>/dev/null
fi
fi
case "$1" in
meta-data) meta_data
exit $OCF_SUCCESS;;
usage|help) usage
exit $OCF_SUCCESS;;
esac
mysql_common_validate
rc=$?
LSB_STATUS_STOPPED=3
if [ $rc -ne 0 ]; then
case "$1" in
stop) ;;
monitor)
mysql_common_status "info"
if [ $? -eq $OCF_SUCCESS ]; then
# if validatation fails and pid is active, always treat this as an error
ocf_exit_reason "environment validation failed, active pid is in unknown state."
exit $OCF_ERR_GENERIC
fi
# validation failed and pid is not active, it's safe to say this instance is inactive.
exit $OCF_NOT_RUNNING;;
status) exit $LSB_STATUS_STOPPED;;
*) exit $rc;;
esac
fi
# What kind of method was invoked?
case "$1" in
start) mysql_start;;
stop) mysql_stop;;
status) mysql_common_status err;;
monitor) mysql_monitor;;
promote) mysql_promote;;
demote) mysql_demote;;
notify) mysql_notify;;
validate-all) exit $OCF_SUCCESS;;
*) usage
exit $OCF_ERR_UNIMPLEMENTED;;
esac
# vi:sw=4:ts=4:et:
diff --git a/heartbeat/mpathpersist b/heartbeat/mpathpersist.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/mpathpersist
rename to heartbeat/mpathpersist.in
index beada544c..43dcc7453
--- a/heartbeat/mpathpersist
+++ b/heartbeat/mpathpersist.in
@@ -1,682 +1,682 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
#
# OCF Resource Agent compliant PERSISTENT SCSI RESERVATION on multipath devices resource script.
# Testversion for a mpathpersist implementation for demo purposes by Andreas Thomas
#
# Copyright (c) 2017 Evgeny Nifontov, lwang@suse.com,
# Andreas Tomas<Andreas.Tomas@suse.com>,
# Zhu Lingshan<lszhu@suse.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.
#
#
# OCF instance parameters
# OCF_RESKEY_binary
# OCF_RESKEY_devs
# OCF_RESKEY_required_devs_no
# OCF_RESKEY_reservation_type
# OCF_RESKEY_master_score_base
# OCF_RESKEY_master_score_dev_factor
# OCF_RESKEY_master_score_delay
#
# TODO
#
# 1) PROBLEM: devices which were not accessible during 'start' action, will be never registered/reserved
# TODO: 'Master' and 'Slave' registers new devs in 'monitor' action
# TODO: 'Master' reserves new devs in 'monitor' action
#Defaults
OCF_RESKEY_mpathpersist_binary_default="mpathpersist"
OCF_RESKEY_required_devs_no_default=1
OCF_RESKEY_reservation_type_default=1
OCF_RESKEY_master_score_base_default=0
OCF_RESKEY_master_score_dev_factor_default=100
OCF_RESKEY_master_score_delay_default=30
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
# set default values
: ${OCF_RESKEY_mpathpersist_binary=${OCF_RESKEY_mpathpersist_binary_default}} # binary name for the resource
: ${OCF_RESKEY_required_devs_no=${OCF_RESKEY_required_devs_no_default}} # number of required devices
: ${OCF_RESKEY_reservation_type=${OCF_RESKEY_reservation_type_default}} # reservation type
: ${OCF_RESKEY_master_score_base=${OCF_RESKEY_master_score_base_default}} # master score base
: ${OCF_RESKEY_master_score_dev_factor=${OCF_RESKEY_master_score_dev_factor_default}} # device factor for master score
: ${OCF_RESKEY_master_score_delay=${OCF_RESKEY_master_score_delay_default}} # delay for master score
#######################################################################
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="mpathpersist">
<version>1.1</version>
<longdesc lang="en">
This resource agent manages SCSI persistent reservations on multipath devices.
"mpathpersist" from multipath-tools is used, please see its documentation.
Should be used as multistate (Master/Slave) resource
Slave registers its node id ("crm_node -i") as reservation key ( --param-sark ) on each device in the params "devs" list.
Master reservs all devices from params "devs" list with reservation "--prout-type" value from "reservation_type" parameter.
Please see man sg_persist(8) and mpathpersist(8) for reservation_type details.
</longdesc>
<shortdesc lang="en">Manages SCSI persistent reservations on multipath devices</shortdesc>
<parameters>
<parameter name="binary" unique="0">
<longdesc lang="en">
The name of the binary that manages the resource.
</longdesc>
<shortdesc lang="en">the binary name of the resource</shortdesc>
<content type="string" default="${OCF_RESKEY_mpathpersist_binary_default}"/>
</parameter>
<parameter name="devs" unique="0" required="1">
<longdesc lang="en">
Device list. Multiple devices can be listed with blank space as separator.
Shell wildcars are allowed.
</longdesc>
<shortdesc lang="en">device list</shortdesc>
<content type="string"/>
</parameter>
<parameter name="required_devs_no" unique="0" required="0">
<longdesc lang="en">
Minimum number of "working" devices from device list
1) existing
2) "mpathpersist --in --read-keys &lt;device&gt;" works (Return code 0)
resource actions "start","monitor","promote" and "validate-all" return "OCF_ERR_INSTALLED"
if the actual number of "working" devices is less than "required_devs_no".
resource actions "stop" and "demote" tries to remove reservations and registration keys from
all working devices, but always return "OCF_SUCCESS"
</longdesc>
<shortdesc lang="en">minimum number of working devices</shortdesc>
<content type="string" default="${OCF_RESKEY_required_devs_no_default}"/>
</parameter>
<parameter name="reservation_type" unique="0" required="0">
<longdesc lang="en">
reservation type
</longdesc>
<shortdesc lang="en">reservation type</shortdesc>
<content type="string" default="${OCF_RESKEY_reservation_type_default}" />
</parameter>
<parameter name="master_score_base" unique="0" required="0">
<longdesc lang="en">
master_score_base value
"master_score_base" value is used in "master_score" calculation:
master_score = master_score_base + master_score_dev_factor * working_devs
if set to bigger value in mpathpersist resource configuration on some node, this node will be "preferred" for master role.
</longdesc>
<shortdesc lang="en">base master_score value</shortdesc>
<content type="string" default="${OCF_RESKEY_master_score_base_default}" />
</parameter>
<parameter name="master_score_dev_factor" unique="0" required="0">
<longdesc lang="en">
Working device factor in master_score calculation
each "working" device provides additional value to "master_score",
so the node that sees more devices will be preferred for the "Master"-role
Setting it to 0 will disable this behavior.
</longdesc>
<shortdesc lang="en">working device factor in master_score calculation</shortdesc>
<content type="string" default="${OCF_RESKEY_master_score_dev_factor_default}" />
</parameter>
<parameter name="master_score_delay" unique="0" required="0">
<longdesc lang="en">
master/slave decreases/increases its master_score after delay of "master_score_delay" seconds
so if some device gets inaccessible, the slave decreases its master_score first and the resource will no be watched
and after this device reappears again the master increases its master_score first
this can work only if the master_score_delay is bigger then monitor interval on both master and slave
Setting it to 0 will disable this behavior.
</longdesc>
<shortdesc lang="en">master_score decrease/increase delay time</shortdesc>
<content type="string" default="${OCF_RESKEY_master_score_delay_default}" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="30s" />
<action name="promote" timeout="30s" />
<action name="demote" timeout="30s" />
<action name="notify" timeout="30s" />
<action name="stop" timeout="30s" />
<action name="monitor" depth="0" timeout="20s" interval="29s" role="Slave" />
<action name="monitor" depth="0" timeout="20s" interval="60s" role="Master" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="30s" />
</actions>
</resource-agent>
END
exit $OCF_SUCCESS
}
mpathpersist_init() {
if ! ocf_is_root ; then
ocf_log err "You must be root to perform this operation."
exit $OCF_ERR_PERM
fi
MPATHPERSIST="${OCF_RESKEY_mpathpersist_binary}"
check_binary $MPATHPERSIST
ROLE=$OCF_RESKEY_CRM_meta_role
NOW=$(date +%s)
RESOURCE="${OCF_RESOURCE_INSTANCE}"
MASTER_SCORE_VAR_NAME="master-${OCF_RESOURCE_INSTANCE}"
PENDING_VAR_NAME="pending-$MASTER_SCORE_VAR_NAME"
#only works with corocync
CRM_NODE="${HA_SBIN_DIR}/crm_node"
NODE_ID_DEC=$($CRM_NODE -i)
NODE=$($CRM_NODE -l | $GREP -w ^$NODE_ID_DEC)
NODE=${NODE#$NODE_ID_DEC }
NODE=${NODE% *}
MASTER_SCORE_ATTRIBUTE="${HA_SBIN_DIR}/crm_attribute --lifetime=reboot --name=$MASTER_SCORE_VAR_NAME --node=$NODE"
CRM_MASTER="${HA_SBIN_DIR}/crm_master --lifetime=reboot"
PENDING_ATTRIBUTE="${HA_SBIN_DIR}/crm_attribute --lifetime=reboot --name=$PENDING_VAR_NAME --node=$NODE"
NODE_ID_HEX=$(printf '0x%x' $NODE_ID_DEC)
if [ -z "$NODE_ID_HEX" ]; then
ocf_log err "Couldn't get node id with \"$CRM_NODE\""
exit $OCF_ERR_INSTALLED
fi
ocf_log debug "$RESOURCE: NODE:$NODE, ROLE:$ROLE, NODE_ID DEC:$NODE_ID_DEC HEX:$NODE_ID_HEX"
DEVS="${OCF_RESKEY_devs}"
REQUIRED_DEVS_NO="${OCF_RESKEY_required_devs_no}"
RESERVATION_TYPE="${OCF_RESKEY_reservation_type}"
MASTER_SCORE_BASE="${OCF_RESKEY_master_score_base}"
MASTER_SCORE_DEV_FACTOR="${OCF_RESKEY_master_score_dev_factor}"
MASTER_SCORE_DELAY="${OCF_RESKEY_master_score_delay}"
ocf_log debug "$RESOURCE: DEVS=$DEVS"
ocf_log debug "$RESOURCE: REQUIRED_DEVS_NO=$REQUIRED_DEVS_NO"
ocf_log debug "$RESOURCE: RESERVATION_TYPE=$RESERVATION_TYPE"
ocf_log debug "$RESOURCE: MASTER_SCORE_BASE=$MASTER_SCORE_BASE"
ocf_log debug "$RESOURCE: MASTER_SCORE_DEV_FACTOR=$MASTER_SCORE_DEV_FACTOR"
ocf_log debug "$RESOURCE: MASTER_SCORE_DELAY=$MASTER_SCORE_DELAY"
#expand path wildcards
DEVS=$(echo $DEVS)
if [ -z "$DEVS" ]; then
ocf_log err "\"devs\" not defined"
exit $OCF_ERR_INSTALLED
fi
mpathpersist_check_devs
mpathpersist_get_status
}
mpathpersist_action_usage() {
cat <<END
usage: $0 {start|stop|monitor|validate-all|promote|demote|notify|meta-data}
Expects to have a fully populated OCF RA-compliant environment set.
END
}
mpathpersist_get_status() {
unset WORKING_DEVS[*]
for dev in ${EXISTING_DEVS[*]}
do
READ_KEYS=`$MPATHPERSIST --in --read-keys $dev 2>&1`
if [ $? -eq 0 ]; then
WORKING_DEVS+=($dev)
echo "$READ_KEYS" | $GREP -w $NODE_ID_HEX\$ >/dev/null
if [ $? -eq 0 ]; then
REGISTERED_DEVS+=($dev)
READ_RESERVATION=`$MPATHPERSIST --in --read-reservation $dev 2>&1`
if [ $? -eq 0 ]; then
echo "$READ_RESERVATION" | $GREP -w $NODE_ID_HEX\$ >/dev/null
if [ $? -eq 0 ]; then
RESERVED_DEVS+=($dev)
fi
reservation_key=`echo $READ_RESERVATION | $GREP -o 'Key = 0x[0-9a-f]*' | $GREP -o '0x[0-9a-f]*'`
if [ -n "$reservation_key" ]; then
DEVS_WITH_RESERVATION+=($dev)
RESERVATION_KEYS+=($reservation_key)
fi
fi
fi
fi
done
WORKING_DEVS_NO=${#WORKING_DEVS[*]}
ocf_log debug "$RESOURCE: working devices: `mpathpersist_echo_array ${WORKING_DEVS[*]}`"
ocf_log debug "$RESOURCE: number of working devices: $WORKING_DEVS_NO"
ocf_log debug "$RESOURCE: registered devices: `mpathpersist_echo_array ${REGISTERED_DEVS[*]}`"
ocf_log debug "$RESOURCE: reserved devices: `mpathpersist_echo_array ${RESERVED_DEVS[*]}`"
ocf_log debug "$RESOURCE: devices with reservation: `mpathpersist_echo_array ${DEVS_WITH_RESERVATION[*]}`"
ocf_log debug "$RESOURCE: reservation keys: `mpathpersist_echo_array ${RESERVATION_KEYS[*]}`"
MASTER_SCORE=$(($MASTER_SCORE_BASE + $MASTER_SCORE_DEV_FACTOR*$WORKING_DEVS_NO))
ocf_log debug "$RESOURCE: master_score: $MASTER_SCORE_BASE + $MASTER_SCORE_DEV_FACTOR*$WORKING_DEVS_NO = $MASTER_SCORE"
}
mpathpersist_check_devs() {
for dev in $DEVS
do
if [ -e "$dev" ]; then
EXISTING_DEVS+=($dev)
fi
done
EXISTING_DEVS_NO=${#EXISTING_DEVS[*]}
if [ $EXISTING_DEVS_NO -lt $REQUIRED_DEVS_NO ]; then
ocf_log err "Number of existing devices=$EXISTING_DEVS_NO less then required_devs_no=$REQUIRED_DEVS_NO"
exit $OCF_ERR_INSTALLED
fi
}
mpathpersist_is_registered() {
for registered_dev in ${REGISTERED_DEVS[*]}
do
if [ "$registered_dev" == "$1" ]; then
return 0
fi
done
return 1
}
mpathpersist_get_reservation_key() {
for array_index in ${!DEVS_WITH_RESERVATION[*]}
do
if [ "${DEVS_WITH_RESERVATION[$array_index]}" == "$1" ]; then
echo ${RESERVATION_KEYS[$array_index]}
return 0
fi
done
echo ""
}
mpathpersist_echo_array() {
str_count=0
arr_str=""
for str in "$@"
do
arr_str="$arr_str[$str_count]:$str "
str_count=$(($str_count+1))
done
echo $arr_str
}
mpathpersist_parse_act_pending() {
ACT_PENDING_TS=0
ACT_PENDING_SCORE=0
if [ -n "$ACT_PENDING" ]; then
ACT_PENDING_TS=${ACT_PENDING%%_*}
ACT_PENDING_SCORE=${ACT_PENDING##*_}
fi
}
mpathpersist_clear_pending() {
if [ -n "$ACT_PENDING" ]; then
DO_PENDING_UPDATE="YES"
NEW_PENDING=""
fi
}
mpathpersist_new_master_score() {
DO_MASTER_SCORE_UPDATE="YES"
NEW_MASTER_SCORE=$1
}
mpathpersist_new_pending() {
DO_PENDING_UPDATE="YES"
NEW_PENDING=$1
}
# Functions invoked by resource manager actions
mpathpersist_action_start() {
ocf_run $MASTER_SCORE_ATTRIBUTE --update=$MASTER_SCORE
ocf_run $PENDING_ATTRIBUTE --update=""
if [ $WORKING_DEVS_NO -lt $REQUIRED_DEVS_NO ]; then
ocf_log err "$RESOURCE: Number of working devices=$WORKING_DEVS_NO less then required_devs_no=$REQUIRED_DEVS_NO"
exit $OCF_ERR_GENERIC
fi
for dev in ${WORKING_DEVS[*]}
do
if mpathpersist_is_registered $dev ; then
: OK
else
ocf_run $MPATHPERSIST --out --register --param-sark=$NODE_ID_HEX $dev
if [ $? -ne $OCF_SUCCESS ]
then
return $OCF_ERR_GENERIC
fi
fi
done
return $OCF_SUCCESS
}
mpathpersist_action_stop() {
if [ ${#REGISTERED_DEVS[*]} -eq 0 ]; then
ocf_log debug "$RESOURCE stop: already no registrations"
else
# Clear preference for becoming master
ocf_run $MASTER_SCORE_ATTRIBUTE --delete
ocf_run $PENDING_ATTRIBUTE --delete
for dev in ${REGISTERED_DEVS[*]}
do
ocf_run $MPATHPERSIST --out --register --param-rk=$NODE_ID_HEX $dev
done
fi
return $OCF_SUCCESS
}
mpathpersist_action_monitor() {
ACT_MASTER_SCORE=`$MASTER_SCORE_ATTRIBUTE --query --quiet 2>&1`
ocf_log debug "$RESOURCE monitor: ACT_MASTER_SCORE=$ACT_MASTER_SCORE"
ACT_PENDING=`$PENDING_ATTRIBUTE --query --quiet 2>&1`
ocf_log debug "$RESOURCE monitor: ACT_PENDING=$ACT_PENDING"
mpathpersist_parse_act_pending
ocf_log debug "$RESOURCE monitor: ACT_PENDING_TS=$ACT_PENDING_TS"
ocf_log debug "$RESOURCE monitor: ACT_PENDING_VAL=$ACT_PENDING_SCORE"
ocf_log debug "$MASTER_SCORE, $ACT_MASTER_SCORE, $ROLE"
DO_MASTER_SCORE_UPDATE="NO"
DO_PENDING_UPDATE="NO"
if [ -n "$ACT_MASTER_SCORE" ]
then
if [ $ACT_MASTER_SCORE -eq $MASTER_SCORE ]; then
mpathpersist_clear_pending
else
case $ROLE in
Master)
if [ $MASTER_SCORE -lt $ACT_MASTER_SCORE ]; then
if [ -n "$ACT_PENDING" ]
then
if [ $(($NOW-$ACT_PENDING_TS-$MASTER_SCORE_DELAY)) -ge 0 ]; then
mpathpersist_new_master_score $MASTER_SCORE
mpathpersist_clear_pending
fi
else
if [ $MASTER_SCORE_DELAY -eq 0 ]; then
mpathpersist_new_master_score $MASTER_SCORE
mpathpersist_clear_pending
else
mpathpersist_new_pending "${NOW}_${MASTER_SCORE}"
fi
fi
else
mpathpersist_new_master_score $MASTER_SCORE
mpathpersist_clear_pending
fi
;;
Slave)
if [ $MASTER_SCORE -gt $ACT_MASTER_SCORE ]; then
if [ -n "$ACT_PENDING" ]; then
if [ $(($NOW-$ACT_PENDING_TS-$MASTER_SCORE_DELAY)) -ge 0 ]; then
mpathpersist_new_master_score $MASTER_SCORE
mpathpersist_clear_pending
fi
else
if [ $MASTER_SCORE_DELAY -eq 0 ]; then
mpathpersist_new_master_score $MASTER_SCORE
mpathpersist_clear_pending
else
mpathpersist_new_pending "${NOW}_${MASTER_SCORE}"
fi
fi
else
mpathpersist_new_master_score $MASTER_SCORE
mpathpersist_clear_pending
fi
;;
*)
;;
esac
fi
fi
if [ $DO_MASTER_SCORE_UPDATE == "YES" ]; then
ocf_run $MASTER_SCORE_ATTRIBUTE --update=$NEW_MASTER_SCORE
fi
if [ $DO_PENDING_UPDATE == "YES" ]; then
ocf_run $PENDING_ATTRIBUTE --update=$NEW_PENDING
fi
if [ ${#REGISTERED_DEVS[*]} -eq 0 ]; then
ocf_log debug "$RESOURCE monitor: no registrations"
return $OCF_NOT_RUNNING
fi
if [ ${#RESERVED_DEVS[*]} -eq ${#WORKING_DEVS[*]} ]; then
return $OCF_RUNNING_MASTER
fi
if [ ${#REGISTERED_DEVS[*]} -eq ${#WORKING_DEVS[*]} ]; then
if [ $RESERVATION_TYPE -eq 7 ] || [ $RESERVATION_TYPE -eq 8 ]; then
if [ ${#DEVS_WITH_RESERVATION[*]} -gt 0 ]; then
return $OCF_RUNNING_MASTER
else
return $OCF_SUCCESS
fi
else
return $OCF_SUCCESS
fi
fi
ocf_log err "$RESOURCE monitor: unexpected state"
return $OCF_ERR_GENERIC
}
mpathpersist_action_promote() {
if [ ${#RESERVED_DEVS[*]} -gt 0 ]; then
ocf_log info "$RESOURCE promote: already master"
return $OCF_SUCCESS
fi
for dev in ${WORKING_DEVS[*]}
do
reservation_key=`mpathpersist_get_reservation_key $dev`
case $RESERVATION_TYPE in
1|3|5|6)
if [ -z "$reservation_key" ]; then
ocf_run $MPATHPERSIST --out --reserve --param-rk=$NODE_ID_HEX --prout-type=$RESERVATION_TYPE $dev
if [ $? -ne $OCF_SUCCESS ]; then
return $OCF_ERR_GENERIC
fi
else
ocf_run $MPATHPERSIST --out --preempt --param-sark=$reservation_key --param-rk=$NODE_ID_HEX --prout-type=$RESERVATION_TYPE $dev
if [ $? -ne $OCF_SUCCESS ]; then
return $OCF_ERR_GENERIC
fi
fi
;;
7|8)
if [ -z "$reservation_key" ]; then
ocf_run $MPATHPERSIST --out --reserve --param-rk=$NODE_ID_HEX --prout-type=$RESERVATION_TYPE $dev
if [ $? -ne $OCF_SUCCESS ]
then
return $OCF_ERR_GENERIC
fi
else
ocf_log info "$RESOURCE promote: there already exist an reservation holder, all registrants become reservation holders"
return $OCF_SUCCESS
fi
;;
*)
return $OCF_ERR_ARGS
;;
esac
done
return $OCF_SUCCESS
}
mpathpersist_action_demote() {
case $RESERVATION_TYPE in
1|3|5|6)
if [ ${#RESERVED_DEVS[*]} -eq 0 ]; then
ocf_log info "$RESOURCE demote: already slave"
return $OCF_SUCCESS
fi
for dev in ${RESERVED_DEVS[*]}
do
ocf_run $MPATHPERSIST --out --release --param-rk=$NODE_ID_HEX --prout-type=$RESERVATION_TYPE $dev
if [ $? -ne $OCF_SUCCESS ]; then
return $OCF_ERR_GENERIC
fi
done
;;
7|8) #in case of 7/8, --release won't release the reservation unless unregister the key.
if [ ${#REGISTERED_DEVS[*]} -eq 0 ]; then
ocf_log info "$RESOURCE demote: already slave"
return $OCF_SUCCESS
fi
for dev in ${REGISTERED_DEVS[*]}
do
ocf_run $MPATHPERSIST --out --register --param-rk=$NODE_ID_HEX --param-sark=0 $dev
if [ $? -ne $OCF_SUCCESS ]; then
return $OCF_ERR_GENERIC
fi
done
;;
*)
return $OCF_ERR_ARGS
;;
esac
return $OCF_SUCCESS
}
mpathpersist_action_notify() {
local n_type="$OCF_RESKEY_CRM_meta_notify_type"
local n_op="$OCF_RESKEY_CRM_meta_notify_operation"
set -- $OCF_RESKEY_CRM_meta_notify_active_resource
local n_active="$#"
set -- $OCF_RESKEY_CRM_meta_notify_stop_resource
local n_stop="$#"
set -- $OCF_RESKEY_CRM_meta_notify_start_resource
local n_start="$#"
ocf_log debug "$RESOURCE notify: $n_type for $n_op - counts: active $n_active - starting $n_start - stopping $n_stop"
return $OCF_SUCCESS
}
mpathpersist_action_validate_all () {
if [ "$OCF_RESKEY_CRM_meta_master_max" != "1" ] && [ "$RESERVATION_TYPE" != "7" ] && [ "$RESERVATION_TYPE" != "8" ]; then
ocf_log err "Master options misconfigured."
exit $OCF_ERR_CONFIGURED
fi
return $OCF_SUCCESS
}
if [ $# -ne 1 ]; then
echo "Incorrect parameter count."
mpathpersist_action_usage
exit $OCF_ERR_ARGS
fi
ACTION=$1
case $ACTION in
meta-data)
meta_data
;;
validate-all)
mpathpersist_init
mpathpersist_action_validate_all
;;
start|promote|monitor|stop|demote)
ocf_log debug "$RESOURCE: starting action \"$ACTION\""
mpathpersist_init
mpathpersist_action_$ACTION
exit $?
;;
notify)
mpathpersist_action_notify
exit $?
;;
usage|help)
mpathpersist_action_usage
exit $OCF_SUCCESS
;;
*)
mpathpersist_action_usage
exit $OCF_ERR_ARGS
;;
esac
diff --git a/heartbeat/nfsnotify b/heartbeat/nfsnotify.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/nfsnotify
rename to heartbeat/nfsnotify.in
index 20c03c4f3..6e3a8de35
--- a/heartbeat/nfsnotify
+++ b/heartbeat/nfsnotify.in
@@ -1,315 +1,315 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (c) 2014 David Vossel <davidvossel@gmail.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>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="90s" />
<action name="stop" timeout="90s" />
<action name="monitor" timeout="90s" interval="30s" depth="0" />
<action name="reload" timeout="90s" />
<action name="meta-data" timeout="10s" />
<action name="validate-all" timeout="20s" />
</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_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_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_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_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/redis b/heartbeat/redis.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/redis
rename to heartbeat/redis.in
index b6f111d16..d5eb8f664
--- a/heartbeat/redis
+++ b/heartbeat/redis.in
@@ -1,709 +1,709 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Resource agent script for redis server.
#
# Copyright (c) 2013 Patrick Hemmer <patrick.hemmer@gmail.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
: ${OCF_RESKEY_bin:=/usr/bin/redis-server}
: ${OCF_RESKEY_client_bin:=/usr/bin/redis-cli}
: ${OCF_RESKEY_user:=redis}
: ${OCF_RESKEY_rundir:=/var/run/redis}
: ${OCF_RESKEY_pidfile_name:=redis-server.pid}
: ${OCF_RESKEY_socket_name:=redis.sock}
: ${OCF_RESKEY_port:=6379}
: ${OCF_RESKEY_tunnel_host:=127.0.0.1}
if [ -z "$OCF_RESKEY_config" ]; then
if [ -f "/etc/redis.conf" ]; then
OCF_RESKEY_config="/etc/redis.conf"
else
OCF_RESKEY_config="/etc/redis/redis.conf"
fi
fi
CHECK_SLAVE_STATE=0
REDIS_CHECK_DUMP="/usr/bin/redis-check-dump"
REDIS_SERVER="$OCF_RESKEY_bin"
REDIS_CLIENT="$OCF_RESKEY_client_bin"
REDIS_CONFIG="$OCF_RESKEY_config"
REDIS_USER="$OCF_RESKEY_user"
REDIS_RUNDIR="$OCF_RESKEY_rundir"
REDIS_PIDFILE="$OCF_RESKEY_rundir/$OCF_RESKEY_pidfile_name"
REDIS_SOCKET="$OCF_RESKEY_rundir/$OCF_RESKEY_socket_name"
REDIS_REPLICATION_PORT="$OCF_RESKEY_port"
if ! [ -f $REDIS_CHECK_DUMP ]; then
REDIS_CHECK_DUMP="$(which redis-check-dump 2>/dev/null)"
fi
if [ -z "$REDIS_CHECK_DUMP" ]; then
REDIS_CHECK_DUMP="$(which redis-check-rdb 2>/dev/null)"
fi
if [ -r "$REDIS_CONFIG" ]; then
REDIS_DUMP_DIR="$(grep "^\s*dir\s" < "$REDIS_CONFIG" | awk '{ print $2 }' 2>/dev/null)"
REDIS_DUMP_FILE="$(grep "^\s*dbfilename\s" < "$REDIS_CONFIG" | awk '{ print $2 }' 2>/dev/null)"
fi
: ${REDIS_DUMP_DIR:=/var/lib/redis/}
: ${REDIS_DUMP_FILE:=dump.rdb}
redis_meta_data() {
cat <<EOI
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="redis">
<version>1.0</version>
<longdesc lang="en">
Resource agent script for redis server.
This resource fully supports master/slave replication. The master preference of a node is determined by the 'slave_priority' parameter of the redis config.
When taking the resource from 'unmanaged' to 'managed', the currently active master will be given a priority of 1000 (plus 1 for each active connection). The default 'slave_priority' is 100, so the master will stay master. For a slave to become master after converting the resource to managed, set a slave_priority greater than 1000.
</longdesc>
<shortdesc lang="en">Redis server</shortdesc>
<parameters>
<parameter name="bin" unique="0" required="0">
<longdesc lang="en">
Path to \`redis-server\`
</longdesc>
<shortdesc lang="en">Path to \`redis-server\`</shortdesc>
<content type="string" default="${OCF_RESKEY_bin}" />
</parameter>
<parameter name="client_bin" unique="0" required="0">
<longdesc lang="en">
Path to \`redis-cli\`
</longdesc>
<shortdesc lang="en">Path to \`redis-cli\`</shortdesc>
<content type="string" default="${OCF_RESKEY_client_bin}" />
</parameter>
<parameter name="config" unique="1" required="0">
<longdesc lang="en">
Path to 'redis.conf'
</longdesc>
<shortdesc lang="en">Path to 'redis.conf'</shortdesc>
<content type="string" default="${OCF_RESKEY_config}" />
</parameter>
<parameter name="user" unique="0" required="0">
<longdesc lang="en">
User to run redis as
</longdesc>
<shortdesc lang="en">Redis user</shortdesc>
<content type="string" default="${OCF_RESKEY_user}" />
</parameter>
<parameter name="rundir" unique="1" required="0">
<longdesc lang="en">
Directory to store socket and pid file in
</longdesc>
<shortdesc lang="en">Redis var/run dir</shortdesc>
<content type="string" default="${OCF_RESKEY_rundir}"/>
</parameter>
<parameter name="pidfile_name" unique="0" required="0">
<longdesc lang="en">
The filename to use for the pidfile. Will be created in the rundir.
Should only be a basename, not a full path.
</longdesc>
<shortdesc lang="en">Redis pidfile name</shortdesc>
<content type="string" default="${OCF_RESKEY_pidfile_name}"/>
</parameter>
<parameter name="socket_name" unique="0" required="0">
<longdesc lang="en">
The filename to use for the socket. Will be crated in the rundir.
Should only be a basename, not a full path.
</longdesc>
<shortdesc lang="en">Redis socket name</shortdesc>
<content type="string" default="${OCF_RESKEY_socket_name}"/>
</parameter>
<parameter name="port" unique="0" required="0">
<longdesc lang="en">
Port for replication client to connect to on remote server
</longdesc>
<shortdesc lang="en">Replication port</shortdesc>
<content type="string" default="${OCF_RESKEY_port}"/>
</parameter>
<parameter name="tunnel_host" unique="0" required="0">
<longdesc lang="en">
When replication traffic is tunnelled, this is the host to target
to forward outgoing traffic to the redis master. The resource
agent configures the redis slave to target the master via
tunnel_host:tunnel_port.
Note that in order to enable replication traffic tunneling,
parameter {tunnel_port_map} must be populated.
</longdesc>
<shortdesc lang="en">Tunnel host for replication traffic</shortdesc>
<content type="string" default="${OCF_RESKEY_tunnel_host}"/>
</parameter>
<parameter name="tunnel_port_map" unique="0" required="0">
<longdesc lang="en">
A mapping of pacemaker node names to redis port number.
To be used when redis servers need to tunnel replication traffic.
On every node where the redis resource is running, the redis server
listens to a different port. Each redis server can access its peers
for replication traffic via a tunnel accessible at {tunnel_host}:port.
The mapping the form of:
pcmk1-name:port-for-redis1;pcmk2-name:port-for-redis2;pcmk3-name:port-for-redis3
where the redis resource started on node pcmk1-name would listen on
port port-for-redis1
</longdesc>
<shortdesc lang="en">Mapping of Redis server name to redis port</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="wait_last_known_master" unique="0" required="0">
<longdesc lang="en">
During redis cluster bootstrap, wait for the last known master to be
promoted before allowing any other instances in the cluster to be
promoted. This lessens the risk of data loss when persistent data
is in use.
</longdesc>
<shortdesc lang="en">Wait for last known master</shortdesc>
<content type="boolean" default="false"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="120s" />
<action name="stop" timeout="120s" />
<action name="status" timeout="60s" />
<action name="monitor" depth="0" timeout="60s" interval="45s" />
<action name="monitor" role="Master" depth="0" timeout="60s" interval="20s" />
<action name="monitor" role="Slave" depth="0" timeout="60s" interval="60s" />
<action name="promote" timeout="120s" />
<action name="demote" timeout="120s" />
<action name="notify" timeout="90s" />
<action name="validate-all" timeout="5s" />
<action name="meta-data" timeout="5s" />
</actions>
</resource-agent>
EOI
}
INSTANCE_ATTR_NAME=$(echo "${OCF_RESOURCE_INSTANCE}" | awk -F : '{print $1}')
CRM_ATTR_REPL_INFO="${HA_SBIN_DIR}/crm_attribute --type crm_config --name ${INSTANCE_ATTR_NAME}_REPL_INFO -s redis_replication"
MASTER_HOST=""
MASTER_ACTIVE_CACHED=""
MASTER_ACTIVE=""
master_is_active()
{
if [ -z "$MASTER_ACTIVE_CACHED" ]; then
# determine if a master instance is already up and is healthy
crm_mon --as-xml | grep "resource.*id=\"${OCF_RESOURCE_INSTANCE}\".*role=\"Master\".*active=\"true\".*orphaned=\"false\".*failed=\"false\"" > /dev/null 2>&1
MASTER_ACTIVE=$?
MASTER_ACTIVE_CACHED="true"
fi
return $MASTER_ACTIVE
}
set_master()
{
MASTER_HOST="$1"
${CRM_ATTR_REPL_INFO} -v "$1" -q
}
last_known_master()
{
if [ -z "$MASTER_HOST" ]; then
MASTER_HOST="$(${CRM_ATTR_REPL_INFO} --query -q 2>/dev/null)"
fi
echo "$MASTER_HOST"
}
crm_master_reboot() {
local node
node=$(ocf_attribute_target)
"${HA_SBIN_DIR}/crm_master" -N "$node" -l reboot "$@"
}
calculate_score()
{
perf_score="$1"
connected_clients="$2"
if ocf_is_true "$OCF_RESKEY_wait_last_known_master"; then
# only set perferred score by slave_priority if
# we are not waiting for the last known master. Otherwise
# we want the agent to have complete control over the scoring.
perf_score=""
connected_clients="0"
fi
if [[ -z "$perf_score" ]]; then
if [[ "$(last_known_master)" == "$NODENAME" ]]; then
perf_score=1000
else
perf_score=1
fi
fi
perf_score=$(( perf_score + connected_clients ))
echo "$perf_score"
}
set_score()
{
local score
local last_master
score="$1"
if ocf_is_true "$OCF_RESKEY_wait_last_known_master" && ! master_is_active; then
last_master="$(last_known_master)"
if [ -n "$last_master" ] && [[ "$last_master" != "$NODENAME" ]]; then
ocf_log info "Postponing setting master score for ${NODENAME} until last known master instance [${last_master}] is promoted"
return
fi
fi
ocf_log debug "monitor: Setting master score to '$score'"
crm_master_reboot -v "$score"
}
redis_client() {
ocf_log debug "redis_client: '$REDIS_CLIENT' -s '$REDIS_SOCKET' $*"
if [ -n "$clientpasswd" ]; then
"$REDIS_CLIENT" -s "$REDIS_SOCKET" -a "$clientpasswd" "$@" | sed 's/\r//'
else
"$REDIS_CLIENT" -s "$REDIS_SOCKET" "$@" | sed 's/\r//'
fi
}
simple_status() {
local pid
if ! [ -f "$REDIS_PIDFILE" ]; then
return $OCF_NOT_RUNNING
fi
pid="$(<"$REDIS_PIDFILE")"
pidof "$REDIS_SERVER" | grep -q "\<$pid\>" || return $OCF_NOT_RUNNING
ocf_log debug "monitor: redis-server running under pid $pid"
return $OCF_SUCCESS
}
redis_monitor() {
local res
local master_name
local last_known_master_port
simple_status
res=$?
if (( res != OCF_SUCCESS )); then
return $res
fi
typeset -A info
while read line; do
[[ "$line" == "#"* ]] && continue
[[ "$line" != *":"* ]] && continue
IFS=':' read -r key value <<< "$line"
info[$key]="$value"
done < <(redis_client info)
if [[ -z "${info[role]}" ]]; then
ocf_log err "monitor: Could not get role from \`$REDIS_CLIENT -s $REDIS_SOCKET info\`"
return $OCF_ERR_GENERIC
fi
if ocf_is_ms; then
# Here we see if a score has already been set.
# If score isn't set we the redis setting 'slave_priority'.
# If that isn't set, we default to 1000 for a master, and 1 for slave.
# We then add 1 for each connected client
score="$(crm_master_reboot -G --quiet 2>/dev/null)"
if [[ -z "$score" ]]; then
score=$(calculate_score "${info[slave_priority]}" "${info[connected_clients]}")
set_score "$score"
fi
if [[ "${info[role]}" == "master" ]]; then
if ocf_is_probe; then
set_master "$NODENAME"
fi
return $OCF_RUNNING_MASTER
fi
if [ "$CHECK_SLAVE_STATE" -eq 1 ]; then
if [[ "${info[master_link_status]}" != "up" ]]; then
ocf_log info "monitor: Slave mode link has not yet been established (link=${info[master_link_status]})"
return $OCF_ERR_GENERIC
fi
if [[ "${info[master_host]}" != "$(last_known_master)" ]]; then
if [ -n "${OCF_RESKEY_tunnel_port_map}" ]; then
master_name=$(port_to_redis_node ${info[master_port]})
last_known_master_port=$(redis_node_to_port $(last_known_master))
if [[ "${info[master_host]}" != "${OCF_RESKEY_tunnel_host}" ]] ||
[[ "${info[master_port]}" != "${last_known_master_port}" ]]; then
ocf_log err "monitor: Slave mode current tunnelled connection to redis server does not match running master. tunnelled='${info[master_host]}:${info[master_port]} (${master_name})', running='$(last_known_master)'"
return $OCF_ERR_GENERIC
fi
else
ocf_log err "monitor: Slave mode current master does not match running master. current=${info[master_host]}, running=$(last_known_master)"
return $OCF_ERR_GENERIC
fi
fi
fi
fi
return $OCF_SUCCESS
}
redis_node_to_port()
{
local node=$1
echo "$OCF_RESKEY_tunnel_port_map" | tr ';' '\n' | tr -d ' ' | sed 's/:/ /' | awk -F' ' '$1=="'"$node"'" {print $2;exit}'
}
port_to_redis_node()
{
local port=$1
echo "$OCF_RESKEY_tunnel_port_map" | tr ';' '\n' | tr -d ' ' | sed 's/:/ /' | awk -F' ' '$2=="'"$port"'" {print $1;exit}'
}
get_tunnel_port_from_master()
{
local master_name=$1
crm_attribute --node "$master_name" -l forever --name ${INSTANCE_ATTR_NAME}-tunnel-port --query -q 2>/dev/null
}
get_master_from_tunnel_port()
{
local master_name=$1
crm_attribute --node "$master_name" -l forever --name ${INSTANCE_ATTR_NAME}-tunnel-port --query -q 2>/dev/null
}
check_dump_file()
{
if ! have_binary "$REDIS_CHECK_DUMP"; then
return 0
fi
$REDIS_CHECK_DUMP ${REDIS_DUMP_DIR}/${REDIS_DUMP_FILE} 2>&1
}
redis_start() {
local size
redis_monitor
status=$?
if (( status == OCF_SUCCESS )) || (( status == OCF_RUNNING_MASTER )); then
ocf_log info "start: redis is already running"
return $OCF_SUCCESS
fi
[[ ! -d "$REDIS_RUNDIR" ]] && mkdir -p "$REDIS_RUNDIR"
chown -R "$REDIS_USER" "$REDIS_RUNDIR"
if have_binary "restorecon"; then
restorecon -Rv "$REDIS_RUNDIR"
fi
# check for 0 byte database dump file. This is an unrecoverable start
# condition that we can avoid by deleting the 0 byte database file.
if [ -f "${REDIS_DUMP_DIR}/${REDIS_DUMP_FILE}" ]; then
size="$(stat --format "%s" ${REDIS_DUMP_DIR}/${REDIS_DUMP_FILE})"
if [ "$?" -eq "0" ] && [ "$size" -eq "0" ]; then
ocf_log notice "Detected 0 byte ${REDIS_DUMP_FILE}, deleting zero length file to avoid start failure."
rm -f "${REDIS_DUMP_DIR}/${REDIS_DUMP_FILE}"
fi
fi
ocf_log info "start: $REDIS_SERVER --daemonize yes --unixsocket '$REDIS_SOCKET' --pidfile '$REDIS_PIDFILE'"
output="$(su "$REDIS_USER" -s /bin/sh -c "cd '$REDIS_RUNDIR'; exec '$REDIS_SERVER' '$REDIS_CONFIG' --daemonize yes --unixsocket '$REDIS_SOCKET' --pidfile '$REDIS_PIDFILE'" 2>&1)"
while true; do
# wait for redis to start
typeset -A info
while read line; do
[[ "$line" == "#"* ]] && continue
[[ "$line" != *":"* ]] && continue
IFS=':' read -r key value <<< "$line"
info[$key]="$value"
done < <(redis_client info)
if (( info[loading] == 0 )); then
break
elif (( info[loading] == 1 )); then
sleep "${info[loading_eta_seconds]}"
elif pidof "$REDIS_SERVER" >/dev/null; then
# unknown error, but the process still exists.
# This check is mainly because redis daemonizes before it starts listening, causing `redis-cli` to fail
# See https://github.com/antirez/redis/issues/2368
# It's possible that the `pidof` will pick up a different redis, but in that case, the start operation will just time out
sleep 1
else
check_output="$(check_dump_file)"
ocf_log err "start: Unknown error waiting for redis to start. redis-check-dump output=${check_output//$'\n'/; }"
return $OCF_ERR_GENERIC
fi
done
while ! [ -s "$REDIS_PIDFILE" ]; do
ocf_log debug "start: Waiting for pid file '$REDIS_PIDFILE' to appear"
sleep 1
done
ocf_is_ms && redis_demote # pacemaker expects resources to start in slave mode
redis_monitor
status=$?
if (( status == OCF_SUCCESS )) || (( status == OCF_RUNNING_MASTER )); then
return $OCF_SUCCESS
fi
check_output="$(check_dump_file)"
ocf_log err "start: Unknown error starting redis. redis-server output=${output//$'\n'/; } redis-check-dump output=${check_output//$'\n'/; }"
return $status
}
redis_stop() {
redis_monitor
status=$?
if (( status == OCF_NOT_RUNNING )); then
ocf_log info "stop: redis is already stopped"
crm_master_reboot -D
return $OCF_SUCCESS
fi
pid="$(<"$REDIS_PIDFILE")"
kill -TERM "$pid"
while true; do
simple_status
status=$?
if (( status == OCF_NOT_RUNNING )); then
crm_master_reboot -D
return $OCF_SUCCESS
fi
sleep 1
done
}
redis_promote() {
redis_monitor
status=$?
if (( status == OCF_RUNNING_MASTER )); then
ocf_log info "promote: Already running as master"
set_master "$NODENAME"
return $OCF_SUCCESS
elif (( status != OCF_SUCCESS )); then
ocf_log err "promote: Node is not running as a slave"
return $OCF_ERR_GENERIC
fi
redis_client slaveof no one
redis_monitor
status=$?
if (( status == OCF_RUNNING_MASTER )); then
set_master "$NODENAME"
return $OCF_SUCCESS
fi
ocf_log err "promote: Unknown error while promoting to master (status=$status)"
return $OCF_ERR_GENERIC
}
redis_demote() {
local master_host
local master_port
local tunnel_port
# client kill is only supported in Redis 2.8.12 or greater
version=$(redis_client -v | awk '{print $NF}')
ocf_version_cmp "$version" "2.8.11"
client_kill=$?
CHECK_SLAVE_STATE=1
redis_monitor
status=$?
if (( status == OCF_SUCCESS )); then
ocf_log info "demote: Already running as slave"
return $OCF_SUCCESS
elif (( status == OCF_NOT_RUNNING )); then
ocf_log err "demote: Failed to demote, redis not running."
return $OCF_NOT_RUNNING
fi
master_host="$(last_known_master)"
master_port="${REDIS_REPLICATION_PORT}"
# The elected master has to remain a slave during startup.
# During this period a placeholder master host is assigned.
if [ -z "$master_host" ] || [[ "$master_host" == "$NODENAME" ]]; then
CHECK_SLAVE_STATE=0
master_host="no-such-master"
elif ! master_is_active; then
# no master has been promoted yet. we'll be notified when the
# master starts.
CHECK_SLAVE_STATE=0
master_host="no-such-master"
fi
if [ -n "${OCF_RESKEY_tunnel_port_map}" ]; then
# master_host can be the special marker "no-such-master"
# while a master is being selected. In this case, no
# tunnel port is returned, but this is not fatal.
tunnel_port=$(redis_node_to_port "$master_host")
if [ -n "$tunnel_port" ]; then
ocf_log info "demote: Setting master to '$master_host' via local tunnel '${OCF_RESKEY_tunnel_host}' on port '$tunnel_port'"
master_host="${OCF_RESKEY_tunnel_host}"
master_port="$tunnel_port"
fi
else
ocf_log info "demote: Setting master to '$master_host'"
fi
redis_client slaveof "$master_host" "$master_port"
# Wait forever for the slave to connect to the master and finish the
# sync. Timeout is controlled by Pacemaker "op start timeout=XX".
#
# hint: redis master_link_status will only come "up" when
# the SYNC with the master has completed.
# This can take an arbitraty time (data) and should
# only be parametrized by the start operation timeout
# by the administrator, not by this resource agent code
while true; do
# Wait infinite if replication is syncing
# Then start/demote operation timeout determines timeout
if [ "$client_kill" -eq 2 ]; then
redis_client CLIENT PAUSE 2000
fi
redis_monitor
status=$?
if (( status == OCF_SUCCESS )); then
if [ "$client_kill" -eq 2 ]; then
redis_client CLIENT KILL type normal
fi
return $OCF_SUCCESS
fi
sleep 1
done
ocf_log err "demote: Unexpected error setting slave mode (status=$status)"
return $OCF_ERR_GENERIC
}
redis_notify() {
mode="${OCF_RESKEY_CRM_meta_notify_type}-${OCF_RESKEY_CRM_meta_notify_operation}"
case "$mode" in
post-demote|post-promote) # change the master
redis_monitor
status=$?
if (( status == OCF_SUCCESS )); then # were a slave
# calling demote updates the slave's connection
# to the newly appointed Master instance.
redis_demote
fi
;;
esac
return $OCF_SUCCESS
}
redis_validate() {
if [[ -x "$REDIS_SERVER" ]]; then
ocf_log err "validate: $REDIS_SERVER does not exist or is not executable"
return $OCF_ERR_INSTALLED
fi
if [[ -x "$REDIS_CLIENT" ]]; then
ocf_log err "validate: $REDIS_CLIENT does not exist or is not executable"
return $OCF_ERR_INSTALLED
fi
if [[ -f "$REDIS_CONFIG" ]]; then
ocf_log err "validate: $REDIS_CONFIG does not exist"
return $OCF_ERR_CONFIGURED
fi
if ! getent passwd "$REDIS_USER" &>/dev/null; then
ocf_log err "validate: $REDIS_USER is not a valid user"
return $OCF_ERR_CONFIGURED
fi
}
NODENAME=$(ocf_attribute_target)
if [ -r "$REDIS_CONFIG" ]; then
clientpasswd="$(sed -n -e 's/^\s*requirepass\s*\(.*\)\s*$/\1/p' < $REDIS_CONFIG | tail -n 1)"
fi
ocf_log debug "action=${1:-$__OCF_ACTION} notify_type=${OCF_RESKEY_CRM_meta_notify_type} notify_operation=${OCF_RESKEY_CRM_meta_notify_operation} master_host=${OCF_RESKEY_CRM_meta_notify_master_uname} slave_host=${OCF_RESKEY_CRM_meta_notify_slave_uname} promote_host=${OCF_RESKEY_CRM_meta_notify_promote_uname} demote_host=${OCF_RESKEY_CRM_meta_notify_demote_uname}; params: bin=${OCF_RESKEY_bin} client_bin=${OCF_RESKEY_client_bin} config=${OCF_RESKEY_config} user=${OCF_RESKEY_user} rundir=${OCF_RESKEY_rundir} port=${OCF_RESKEY_port}"
case "${1:-$__OCF_ACTION}" in
status|monitor)
redis_monitor
;;
start)
redis_start
;;
stop)
redis_stop
;;
restart)
redis_stop && redis_start
;;
promote)
redis_promote
;;
demote)
redis_demote
;;
notify)
redis_notify
;;
meta-data)
redis_meta_data
;;
validate-all)
redis_validate
;;
*)
echo "Usage: $0 {monitor|start|stop|restart|promote|demote|notify|validate-all|meta-data}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
status=$?
ocf_log debug "exit_status=$status"
exit $status
diff --git a/heartbeat/rsyslog b/heartbeat/rsyslog.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/rsyslog
rename to heartbeat/rsyslog.in
index fe6333b90..b029a09c5
--- a/heartbeat/rsyslog
+++ b/heartbeat/rsyslog.in
@@ -1,254 +1,254 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Description: Manages a rsyslog instance, provided by NTT OSSC as an
# OCF High-Availability resource under Heartbeat/LinuxHA control
#
# Copyright (c) 2011 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################
# OCF parameters:
# OCF_RESKEY_rsyslog_binary : Path to rsyslog binary.
# Default is "/sbin/rsyslogd"
# OCF_RESKEY_configfile : Configuration file
# OCF_RESKEY_start_opts : Startup options
#
# Only OCF_RESKEY_configfile must be specified. Each of the rests
# has its default value or refers OCF_RESKEY_configfile to make
# its value when no explicit value is given.
#
# Further infomation for setup:
# There are sample configurations at the end of this file.
#
###############################################################################
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
usage()
{
cat <<-!
usage: $0 action
action:
start : start a new rsyslog instance
stop : stop the running rsyslog instance
status : return the status of rsyslog, run or down
monitor : return TRUE if the rsyslog appears to be working.
meta-data : show meta data message
validate-all: validate the instance parameters
!
return $OCF_ERR_UNIMPLEMENTED
}
metadata_rsyslog()
{
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="rsyslog">
<version>1.0</version>
<longdesc lang="en">
This script manages a rsyslog instance as an HA resource.
</longdesc>
<shortdesc lang="en">rsyslog resource agent</shortdesc>
<parameters>
<parameter name="configfile" unique="1" required="1">
<longdesc lang="en">
This parameter specifies a configuration file
for a rsyslog instance managed by this RA.
</longdesc>
<shortdesc lang="en">Configuration file</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="rsyslog_binary" unique="0">
<longdesc lang="en">
This parameter specifies rsyslog's executable file.
</longdesc>
<shortdesc lang="en">rsyslog executable</shortdesc>
<content type="string" default="/sbin/rsyslogd"/>
</parameter>
<parameter name="start_opts" unique="0">
<longdesc lang="en">
This parameter specifies startup options for a
rsyslog instance managed by this RA. When no value is given, no startup
options is used. Don't use option '-F'. It causes a stuck of a start action.
</longdesc>
<shortdesc lang="en">Start options</shortdesc>
<content type="string" default=""/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="20s" />
<action name="stop" timeout="60s" />
<action name="status" timeout="20s" />
<action name="monitor" depth="0" timeout="20s" interval="20s" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="5s"/>
</actions>
</resource-agent>
END
return $OCF_SUCCESS
}
monitor_rsyslog()
{
set -- $(pgrep -f "$PROCESS_PATTERN" 2>/dev/null)
case $# in
0) ocf_log debug "No rsyslog process for $CONFIGFILE"
return $OCF_NOT_RUNNING;;
1) return $OCF_SUCCESS;;
esac
ocf_log warn "Multiple rsyslog process for $CONFIGFILE"
return $OCF_SUCCESS
}
start_rsyslog()
{
local ocf_status
monitor_rsyslog
if [ $? = "$OCF_SUCCESS" ]; then
return $OCF_SUCCESS
fi
$RSYSLOG_EXE -f $CONFIGFILE $START_OPTS 2>&1
ocf_status=$?
if [ "$ocf_status" != "$OCF_SUCCESS" ]; then
return $OCF_ERR_GENERIC
fi
while true; do
monitor_rsyslog
if [ $? = "$OCF_SUCCESS" ]; then
return $OCF_SUCCESS
fi
sleep 1
done
}
stop_rsyslog()
{
pkill -TERM -f "$PROCESS_PATTERN"
typeset lapse_sec=0
while pgrep -f "$PROCESS_PATTERN" > /dev/null; do
sleep 1
lapse_sec=$(( lapse_sec + 1 ))
ocf_log debug "stop_rsyslog[${OCF_RESOURCE_INSTANCE}]: stop NORM $lapse_sec/$OCF_RESKEY_CRM_meta_timeout"
if [ $lapse_sec -ge $OCF_RESKEY_CRM_meta_timeout ]; then
break
fi
done
lapse_sec=0
while pgrep -f "$PROCESS_PATTERN" > /dev/null; do
pkill -KILL -f "$PROCESS_PATTERN"
sleep 1
lapse_sec=$(( lapse_sec + 1 ))
ocf_log debug "stop_rsyslog[${OCF_RESOURCE_INSTANCE}]: suspend rsyslog by SIGKILL ($lapse_sec/@@@)"
done
return $OCF_SUCCESS
}
status_rsyslog()
{
monitor_rsyslog
rc=$?
if [ $rc = $OCF_SUCCESS ]; then
echo "rsyslog service is running."
elif [ $rc = $OCF_NOT_RUNNING ]; then
echo "rsyslog service is stopped."
fi
return $rc
}
validate_all_rsyslog()
{
ocf_log info "validate_all_rsyslog[${OCF_RESOURCE_INSTANCE}]"
return $OCF_SUCCESS
}
if [[ "$1" = "meta-data" ]]; then
metadata_rsyslog
exit $?
fi
CONFIGFILE="${OCF_RESKEY_configfile}"
if [[ -z "$CONFIGFILE" ]]; then
ocf_log err "undefined parameter:configfile"
exit $OCF_ERR_CONFIGURED
fi
if [[ ! -f "$CONFIGFILE" ]]; then
ocf_log err "Config file $CONFIGFILE does not exist."
exit $OCF_ERR_CONFIGURED
fi
RSYSLOG_EXE="${OCF_RESKEY_rsyslog_binary-/sbin/rsyslogd}"
if [[ ! -x "$RSYSLOG_EXE" ]]; then
ocf_log err "Invalid value:rsyslog_binary:$RSYSLOG_EXE"
exit $OCF_ERR_CONFIGURED
fi
START_OPTS=${OCF_RESKEY_start_opts}
PROCESS_PATTERN="$RSYSLOG_EXE -f $CONFIGFILE"
COMMAND=$1
case "$COMMAND" in
start)
ocf_log debug "[${OCF_RESOURCE_INSTANCE}] Enter rsyslog start"
start_rsyslog
func_status=$?
ocf_log debug "[${OCF_RESOURCE_INSTANCE}] Leave rsyslog start $func_status"
exit $func_status
;;
stop)
ocf_log debug "[${OCF_RESOURCE_INSTANCE}] Enter rsyslog stop"
stop_rsyslog
func_status=$?
ocf_log debug "[${OCF_RESOURCE_INSTANCE}] Leave rsyslog stop $func_status"
exit $func_status
;;
status)
status_rsyslog
exit $?
;;
monitor)
monitor_rsyslog
func_status=$?
exit $func_status
;;
validate-all)
validate_all_rsyslog
exit $?
;;
*)
usage
;;
esac
diff --git a/heartbeat/sg_persist b/heartbeat/sg_persist.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/sg_persist
rename to heartbeat/sg_persist.in
index 70390d1fd..4a4df2f86
--- a/heartbeat/sg_persist
+++ b/heartbeat/sg_persist.in
@@ -1,674 +1,674 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
#
# OCF Resource Agent compliant PERSISTENT SCSI RESERVATION resource script.
#
#
# Copyright (c) 2011 Evgeny Nifontov and lwang@suse.com All Rights Reserved.
#
# "Heartbeat drbd OCF Resource Agent: 2007, Lars Marowsky-Bree" was used
# as example of multistate OCF Resource Agent.
#
# 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.
#
#
# OCF instance parameters
# OCF_RESKEY_binary
# OCF_RESKEY_devs
# OCF_RESKEY_required_devs_nof
# OCF_RESKEY_reservation_type
# OCF_RESKEY_master_score_base
# OCF_RESKEY_master_score_dev_factor
# OCF_RESKEY_master_score_delay
#
# TODO
#
# 1) PROBLEM: devices which were not accessible during 'start' action, will be never registered/reserved
# TODO: 'Master' and 'Salve' registers new devs in 'monitor' action
# TODO: 'Master' reserves new devs in 'monitor' action
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
# set default values
: ${sg_persist_binary="sg_persist"} # binary name for the resource
: ${devs=""} # device list
: ${required_devs_nof=1} # number of required devices
: ${reservation_type=1} # reservation type
: ${master_score_base=0} # master score base
: ${master_score_dev_factor=100} # device factor for master score
: ${master_score_delay=30} # delay for master score
#######################################################################
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="sg_persist">
<version>1.1</version>
<longdesc lang="en">
This resource agent manages SCSI PERSISTENT RESERVATIONS.
"sg_persist" from sg3_utils is used, please see its documentation.
Should be used as multistate (Master/Slave) resource
Slave registers its node id ("crm_node -i") as reservation key ( --param-rk ) on each device in the "devs" list.
Master reservs all devices from "devs" list with reservation "--prout-type" value from "reservation_type" parameter.
</longdesc>
<shortdesc lang="en">Manages SCSI PERSISTENT RESERVATIONS</shortdesc>
<parameters>
<parameter name="binary" unique="0">
<longdesc lang="en">
The name of the binary that manages the resource.
</longdesc>
<shortdesc lang="en">the binary name of the resource</shortdesc>
<content type="string" default="$sg_persist_binary"/>
</parameter>
<parameter name="devs" unique="0" required="1">
<longdesc lang="en">
Device list. Multiple devices can be listed with blank space as separator.
Shell wildcars are allowed.
</longdesc>
<shortdesc lang="en">device list</shortdesc>
<content type="string"/>
</parameter>
<parameter name="required_devs_nof" unique="0" required="0">
<longdesc lang="en">
Minimum number of "working" devices from device list
1) existing
2) "sg_persist --read-keys \$device" works (Return code 0)
resource actions "start","monitor","promote" and "validate-all" return "\$OCF_ERR_INSTALLED"
if the actual number of "working" devices is less then "required_devs_nof".
resource actions "stop" and "demote" tries to remove reservations and registration keys from
all working devices, but always return "\$OCF_SUCCESS"
</longdesc>
<shortdesc lang="en">minimum number of working devices</shortdesc>
<content type="string" default="1"/>
</parameter>
<parameter name="reservation_type" unique="0" required="0">
<longdesc lang="en">
reservation type
</longdesc>
<shortdesc lang="en">reservation type</shortdesc>
<content type="string" default="1" />
</parameter>
<parameter name="master_score_base" unique="0" required="0">
<longdesc lang="en">
master_score_base value
"master_score_base" value is used in "master_score" calculation:
master_score = \$master_score_base + \$master_score_dev_factor * \$working_devs
if set to bigger value in sg_persist resource configuration on some node, this node will be "preferred" for master role.
</longdesc>
<shortdesc lang="en">base master_score value</shortdesc>
<content type="string" default="0" />
</parameter>
<parameter name="master_score_dev_factor" unique="0" required="0">
<longdesc lang="en">
Working device factor in master_score calculation
each "working" device provides additional value to "master_score",
so the node that sees more devices will be preferred for the "Master"-role
Setting it to 0 will disable this behavior.
</longdesc>
<shortdesc lang="en">working device factor in master_score calculation</shortdesc>
<content type="string" default="100" />
</parameter>
<parameter name="master_score_delay" unique="0" required="0">
<longdesc lang="en">
master/slave decreases/increases its master_score after delay of \$master_score_delay seconds
so if some device gets inaccessible, the slave decreases its master_score first and the resource will no be watched
and after this device reappears again the master increases its master_score first
this can work only if the master_score_delay is bigger then monitor interval on both master and slave
Setting it to 0 will disable this behavior.
</longdesc>
<shortdesc lang="en">master_score decrease/increase delay time</shortdesc>
<content type="string" default="30" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="30s" />
<action name="promote" timeout="30s" />
<action name="demote" timeout="30s" />
<action name="notify" timeout="30s" />
<action name="stop" timeout="30s" />
<action name="monitor" depth="0" timeout="20s" interval="29s" role="Slave" />
<action name="monitor" depth="0" timeout="20s" interval="60s" role="Master" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="30s" />
</actions>
</resource-agent>
END
exit $OCF_SUCCESS
}
sg_persist_init() {
if ! ocf_is_root ; then
ocf_log err "You must be root to perform this operation."
exit $OCF_ERR_PERM
fi
SG_PERSIST=${OCF_RESKEY_binary:-"$sg_persist_binary"}
check_binary $SG_PERSIST
ROLE=$OCF_RESKEY_CRM_meta_role
NOW=$(date +%s)
RESOURCE="${OCF_RESOURCE_INSTANCE}"
MASTER_SCORE_VAR_NAME="master-${OCF_RESOURCE_INSTANCE//:/-}"
PENDING_VAR_NAME="pending-$MASTER_SCORE_VAR_NAME"
#only works with corocync
CRM_NODE="${HA_SBIN_DIR}/crm_node"
NODE_ID_DEC=$($CRM_NODE -i)
NODE=$($CRM_NODE -l | $GREP -w ^$NODE_ID_DEC)
NODE=${NODE#$NODE_ID_DEC }
NODE=${NODE% *}
MASTER_SCORE_ATTRIBUTE="${HA_SBIN_DIR}/crm_attribute --lifetime=reboot --name=$MASTER_SCORE_VAR_NAME --node=$NODE"
CRM_MASTER="${HA_SBIN_DIR}/crm_master --lifetime=reboot"
PENDING_ATTRIBUTE="${HA_SBIN_DIR}/crm_attribute --lifetime=reboot --name=$PENDING_VAR_NAME --node=$NODE"
NODE_ID_HEX=$(printf '0x%x' $NODE_ID_DEC)
if [ -z "$NODE_ID_HEX" ]; then
ocf_log err "Couldn't get node id with \"$CRM_NODE\""
exit $OCF_ERR_INSTALLED
fi
ocf_log debug "$RESOURCE: NODE:$NODE, ROLE:$ROLE, NODE_ID DEC:$NODE_ID_DEC HEX:$NODE_ID_HEX"
DEVS=${OCF_RESKEY_devs:=$devs}
REQUIRED_DEVS_NOF=${OCF_RESKEY_required_devs_nof:=$required_devs_nof}
RESERVATION_TYPE=${OCF_RESKEY_reservation_type:=$reservation_type}
MASTER_SCORE_BASE=${OCF_RESKEY_master_score_base:=$master_score_base}
MASTER_SCORE_DEV_FACTOR=${OCF_RESKEY_master_score_dev_factor:=$master_score_dev_factor}
MASTER_SCORE_DELAY=${OCF_RESKEY_master_score_delay:=$master_score_delay}
ocf_log debug "$RESOURCE: DEVS=$DEVS"
ocf_log debug "$RESOURCE: REQUIRED_DEVS_NOF=$REQUIRED_DEVS_NOF"
ocf_log debug "$RESOURCE: RESERVATION_TYPE=$RESERVATION_TYPE"
ocf_log debug "$RESOURCE: MASTER_SCORE_BASE=$MASTER_SCORE_BASE"
ocf_log debug "$RESOURCE: MASTER_SCORE_DEV_FACTOR=$MASTER_SCORE_DEV_FACTOR"
ocf_log debug "$RESOURCE: MASTER_SCORE_DELAY=$MASTER_SCORE_DELAY"
#expand path wildcards
DEVS=$(echo $DEVS)
if [ -z "$DEVS" ]; then
ocf_log err "\"devs\" not defined"
exit $OCF_ERR_INSTALLED
fi
sg_persist_check_devs
sg_persist_get_status
}
sg_persist_action_usage() {
cat <<END
usage: $0 {start|stop|monitor|validate-all|promote|demote|notify|meta-data}
Expects to have a fully populated OCF RA-compliant environment set.
END
}
sg_persist_get_status() {
unset WORKING_DEVS[*]
for dev in ${EXISTING_DEVS[*]}
do
READ_KEYS=`$SG_PERSIST --in --read-keys $dev 2>&1`
[ $? -eq 0 ] || continue
WORKING_DEVS+=($dev)
echo "$READ_KEYS" | $GREP -qw $NODE_ID_HEX\$
[ $? -eq 0 ] || continue
REGISTERED_DEVS+=($dev)
READ_RESERVATION=`$SG_PERSIST --in --read-reservation $dev 2>&1`
[ $? -eq 0 ] || continue
echo "$READ_RESERVATION" | $GREP -qw $NODE_ID_HEX\$
if [ $? -eq 0 ]; then
RESERVED_DEVS+=($dev)
fi
reservation_key=`echo $READ_RESERVATION | $GREP -o 'Key=0x[0-9a-f]*' | $GREP -o '0x[0-9a-f]*'`
if [ -n "$reservation_key" ]; then
DEVS_WITH_RESERVATION+=($dev)
RESERVATION_KEYS+=($reservation_key)
fi
done
WORKING_DEVS_NOF=${#WORKING_DEVS[*]}
ocf_log debug "$RESOURCE: working devices: `sg_persist_echo_array ${WORKING_DEVS[*]}`"
ocf_log debug "$RESOURCE: number of working devices: $WORKING_DEVS_NOF"
ocf_log debug "$RESOURCE: registered devices: `sg_persist_echo_array ${REGISTERED_DEVS[*]}`"
ocf_log debug "$RESOURCE: reserved devices: `sg_persist_echo_array ${RESERVED_DEVS[*]}`"
ocf_log debug "$RESOURCE: devices with reservation: `sg_persist_echo_array ${DEVS_WITH_RESERVATION[*]}`"
ocf_log debug "$RESOURCE: reservation keys: `sg_persist_echo_array ${RESERVATION_KEYS[*]}`"
MASTER_SCORE=$(($MASTER_SCORE_BASE + $MASTER_SCORE_DEV_FACTOR*$WORKING_DEVS_NOF))
ocf_log debug "$RESOURCE: master_score: $MASTER_SCORE_BASE + $MASTER_SCORE_DEV_FACTOR*$WORKING_DEVS_NOF = $MASTER_SCORE"
}
sg_persist_check_devs() {
for dev in $DEVS
do
if [ -e "$dev" ]; then
EXISTING_DEVS+=($dev)
fi
done
EXISTING_DEVS_NOF=${#EXISTING_DEVS[*]}
if [ $EXISTING_DEVS_NOF -lt $REQUIRED_DEVS_NOF ]; then
ocf_log err "Number of existing devices=$EXISTING_DEVS_NOF less then required_devs_nof=$REQUIRED_DEVS_NOF"
exit $OCF_ERR_INSTALLED
fi
}
sg_persist_is_registered() {
for registered_dev in ${REGISTERED_DEVS[*]}
do
if [ "$registered_dev" == "$1" ]; then
return 0
fi
done
return 1
}
sg_persist_get_reservation_key() {
for array_index in ${!DEVS_WITH_RESERVATION[*]}
do
if [ "${DEVS_WITH_RESERVATION[$array_index]}" == "$1" ]; then
echo ${RESERVATION_KEYS[$array_index]}
return 0
fi
done
echo ""
}
sg_persist_echo_array() {
str_count=0
arr_str=""
for str in "$@"
do
arr_str="$arr_str[$str_count]:$str "
str_count=$(($str_count+1))
done
echo $arr_str
}
sg_persist_parse_act_pending() {
ACT_PENDING_TS=0
ACT_PENDING_SCORE=0
if [ -n "$ACT_PENDING" ]; then
ACT_PENDING_TS=${ACT_PENDING%%_*}
ACT_PENDING_SCORE=${ACT_PENDING##*_}
fi
}
sg_persist_clear_pending() {
if [ -n "$ACT_PENDING" ]; then
DO_PENDING_UPDATE="YES"
NEW_PENDING=""
fi
}
sg_persist_new_master_score() {
DO_MASTER_SCORE_UPDATE="YES"
NEW_MASTER_SCORE=$1
}
sg_persist_new_pending() {
DO_PENDING_UPDATE="YES"
NEW_PENDING=$1
}
# Functions invoked by resource manager actions
sg_persist_action_start() {
ocf_run $MASTER_SCORE_ATTRIBUTE --update=$MASTER_SCORE
ocf_run $PENDING_ATTRIBUTE --update=""
if [ $WORKING_DEVS_NOF -lt $REQUIRED_DEVS_NOF ]; then
ocf_log err "$RESOURCE: Number of working devices=$WORKING_DEVS_NOF less then required_devs_nof=$REQUIRED_DEVS_NOF"
exit $OCF_ERR_GENERIC
fi
for dev in ${WORKING_DEVS[*]}
do
if sg_persist_is_registered $dev ; then
: OK
else
ocf_run $SG_PERSIST --out --no-inquiry --register --param-rk=0 --param-sark=$NODE_ID_HEX $dev
if [ $? -ne $OCF_SUCCESS ]
then
return $OCF_ERR_GENERIC
fi
fi
done
return $OCF_SUCCESS
}
sg_persist_action_stop() {
if [ ${#REGISTERED_DEVS[*]} -eq 0 ]; then
ocf_log debug "$RESOURCE stop: already no registrations"
else
# Clear preference for becoming master
ocf_run $MASTER_SCORE_ATTRIBUTE --delete
ocf_run $PENDING_ATTRIBUTE --delete
for dev in ${REGISTERED_DEVS[*]}
do
ocf_run $SG_PERSIST --out --no-inquiry --register --param-rk=$NODE_ID_HEX --param-sark=0 $dev
done
fi
return $OCF_SUCCESS
}
sg_persist_action_monitor() {
ACT_MASTER_SCORE=`$MASTER_SCORE_ATTRIBUTE --query --quiet 2>/dev/null`
ocf_log debug "$RESOURCE monitor: ACT_MASTER_SCORE=$ACT_MASTER_SCORE"
ACT_PENDING=`$PENDING_ATTRIBUTE --query --quiet 2>/dev/null`
ocf_log debug "$RESOURCE monitor: ACT_PENDING=$ACT_PENDING"
sg_persist_parse_act_pending
ocf_log debug "$RESOURCE monitor: ACT_PENDING_TS=$ACT_PENDING_TS"
ocf_log debug "$RESOURCE monitor: ACT_PENDING_VAL=$ACT_PENDING_SCORE"
ocf_log debug "$MASTER_SCORE, $ACT_MASTER_SCORE, $ROLE"
DO_MASTER_SCORE_UPDATE="NO"
DO_PENDING_UPDATE="NO"
if [ -n "$ACT_MASTER_SCORE" ]
then
if [ $ACT_MASTER_SCORE -eq $MASTER_SCORE ]; then
sg_persist_clear_pending
else
case $ROLE in
Master)
if [ $MASTER_SCORE -lt $ACT_MASTER_SCORE ]; then
if [ -n "$ACT_PENDING" ]
then
if [ $(($NOW-$ACT_PENDING_TS-$MASTER_SCORE_DELAY)) -ge 0 ]; then
sg_persist_new_master_score $MASTER_SCORE
sg_persist_clear_pending
fi
else
if [ $MASTER_SCORE_DELAY -eq 0 ]; then
sg_persist_new_master_score $MASTER_SCORE
sg_persist_clear_pending
else
sg_persist_new_pending "${NOW}_${MASTER_SCORE}"
fi
fi
else
sg_persist_new_master_score $MASTER_SCORE
sg_persist_clear_pending
fi
;;
Slave)
if [ $MASTER_SCORE -gt $ACT_MASTER_SCORE ]; then
if [ -n "$ACT_PENDING" ]; then
if [ $(($NOW-$ACT_PENDING_TS-$MASTER_SCORE_DELAY)) -ge 0 ]; then
sg_persist_new_master_score $MASTER_SCORE
sg_persist_clear_pending
fi
else
if [ $MASTER_SCORE_DELAY -eq 0 ]; then
sg_persist_new_master_score $MASTER_SCORE
sg_persist_clear_pending
else
sg_persist_new_pending "${NOW}_${MASTER_SCORE}"
fi
fi
else
sg_persist_new_master_score $MASTER_SCORE
sg_persist_clear_pending
fi
;;
*)
;;
esac
fi
fi
if [ $DO_MASTER_SCORE_UPDATE == "YES" ]; then
ocf_run $MASTER_SCORE_ATTRIBUTE --update=$NEW_MASTER_SCORE
fi
if [ $DO_PENDING_UPDATE == "YES" ]; then
ocf_run $PENDING_ATTRIBUTE --update=$NEW_PENDING
fi
if [ ${#REGISTERED_DEVS[*]} -eq 0 ]; then
ocf_log debug "$RESOURCE monitor: no registrations"
return $OCF_NOT_RUNNING
fi
if [ ${#RESERVED_DEVS[*]} -eq ${#WORKING_DEVS[*]} ]; then
return $OCF_RUNNING_MASTER
fi
if [ ${#REGISTERED_DEVS[*]} -eq ${#WORKING_DEVS[*]} ]; then
if [ $RESERVATION_TYPE -eq 7 ] || [ $RESERVATION_TYPE -eq 8 ]; then
if [ ${#DEVS_WITH_RESERVATION[*]} -gt 0 ]; then
return $OCF_RUNNING_MASTER
else
return $OCF_SUCCESS
fi
else
return $OCF_SUCCESS
fi
fi
ocf_log err "$RESOURCE monitor: unexpected state"
return $OCF_ERR_GENERIC
}
sg_persist_action_promote() {
if [ ${#RESERVED_DEVS[*]} -gt 0 ]; then
ocf_log info "$RESOURCE promote: already master"
return $OCF_SUCCESS
fi
for dev in ${WORKING_DEVS[*]}
do
reservation_key=`sg_persist_get_reservation_key $dev`
case $RESERVATION_TYPE in
1|3|5|6)
if [ -z "$reservation_key" ]; then
ocf_run $SG_PERSIST --out --no-inquiry --reserve --param-rk=$NODE_ID_HEX --prout-type=$RESERVATION_TYPE $dev
if [ $? -ne $OCF_SUCCESS ]; then
return $OCF_ERR_GENERIC
fi
else
ocf_run $SG_PERSIST --out --no-inquiry --preempt --param-sark=$reservation_key --param-rk=$NODE_ID_HEX --prout-type=$RESERVATION_TYPE $dev
if [ $? -ne $OCF_SUCCESS ]; then
return $OCF_ERR_GENERIC
fi
fi
;;
7|8)
if [ -z "$reservation_key" ]; then
ocf_run $SG_PERSIST --out --no-inquiry --reserve --param-rk=$NODE_ID_HEX --prout-type=$RESERVATION_TYPE $dev
if [ $? -ne $OCF_SUCCESS ]
then
return $OCF_ERR_GENERIC
fi
else
ocf_log info "$RESOURCE promote: there already exist an reservation holder, all registrants become reservation holders"
return $OCF_SUCCESS
fi
;;
*)
return $OCF_ERR_ARGS
;;
esac
done
return $OCF_SUCCESS
}
sg_persist_action_demote() {
case $RESERVATION_TYPE in
1|3|5|6)
if [ ${#RESERVED_DEVS[*]} -eq 0 ]; then
ocf_log info "$RESOURCE demote: already slave"
return $OCF_SUCCESS
fi
for dev in ${RESERVED_DEVS[*]}
do
ocf_run $SG_PERSIST --out --no-inquiry --release --param-rk=$NODE_ID_HEX --prout-type=$RESERVATION_TYPE $dev
if [ $? -ne $OCF_SUCCESS ]; then
return $OCF_ERR_GENERIC
fi
done
;;
7|8) #in case of 7/8, --release won't release the reservation unless unregister the key.
if [ ${#REGISTERED_DEVS[*]} -eq 0 ]; then
ocf_log info "$RESOURCE demote: already slave"
return $OCF_SUCCESS
fi
for dev in ${REGISTERED_DEVS[*]}
do
ocf_run $SG_PERSIST --out --no-inquiry --register --param-rk=$NODE_ID_HEX --param-sark=0 $dev
if [ $? -ne $OCF_SUCCESS ]; then
return $OCF_ERR_GENERIC
fi
done
;;
*)
return $OCF_ERR_ARGS
;;
esac
return $OCF_SUCCESS
}
sg_persist_action_notify() {
local n_type="$OCF_RESKEY_CRM_meta_notify_type"
local n_op="$OCF_RESKEY_CRM_meta_notify_operation"
set -- $OCF_RESKEY_CRM_meta_notify_active_resource
local n_active="$#"
set -- $OCF_RESKEY_CRM_meta_notify_stop_resource
local n_stop="$#"
set -- $OCF_RESKEY_CRM_meta_notify_start_resource
local n_start="$#"
ocf_log debug "$RESOURCE notify: $n_type for $n_op - counts: active $n_active - starting $n_start - stopping $n_stop"
return $OCF_SUCCESS
}
sg_persist_action_validate_all () {
if [ "$OCF_RESKEY_CRM_meta_master_max" != "1" ] && [ "$RESERVATION_TYPE" != "7" ] && [ "$RESERVATION_TYPE" != "8" ]; then
ocf_log err "Master options misconfigured."
exit $OCF_ERR_CONFIGURED
fi
return $OCF_SUCCESS
}
if [ $# -ne 1 ]; then
echo "Incorrect parameter count."
sg_persist_action_usage
exit $OCF_ERR_ARGS
fi
ACTION=$1
case $ACTION in
meta-data)
meta_data
;;
validate-all)
sg_persist_init
sg_persist_action_validate_all
;;
start|promote|monitor|stop|demote)
ocf_log debug "$RESOURCE: starting action \"$ACTION\""
sg_persist_init
sg_persist_action_$ACTION
exit $?
;;
notify)
sg_persist_action_notify
exit $?
;;
usage|help)
sg_persist_action_usage
exit $OCF_SUCCESS
;;
*)
sg_persist_action_usage
exit $OCF_ERR_ARGS
;;
esac
diff --git a/heartbeat/slapd b/heartbeat/slapd.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/slapd
rename to heartbeat/slapd.in
index 961924e1b..4366453dd
--- a/heartbeat/slapd
+++ b/heartbeat/slapd.in
@@ -1,577 +1,577 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Stand-alone LDAP Daemon (slapd)
#
# Description: Manages Stand-alone LDAP Daemon (slapd) as an OCF resource in
# an high-availability setup.
#
# Authors: Jeroen Koekkoek
# nozawat@gmail.com
# John Keith Hohm
#
# License: GNU General Public License (GPL)
# Copyright: (C) 2011 Pagelink B.V.
#
# The OCF code was inspired by the Postfix resource script written by
# Raoul Bhatia <r.bhatia@ipax.at>.
#
# The code for managing the slapd instance is based on the the slapd init
# script found in Debian GNU/Linux 6.0.
#
# OCF parameters:
# OCF_RESKEY_slapd
# OCF_RESKEY_ldapsearch
# OCF_RESKEY_config
# OCF_RESKEY_pidfile
# OCF_RESKEY_user
# OCF_RESKEY_group
# OCF_RESKEY_services
# OCF_RESKEY_watch_suffix
# OCF_RESKEY_ignore_suffix
# OCF_RESKEY_bind_dn
# OCF_RESKEY_password
# OCF_RESKEY_parameters
# OCF_RESKEY_stop_escalate
# OCF_RESKEY_maxfiles
#
################################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
: ${OCF_RESKEY_slapd="/usr/sbin/slapd"}
: ${OCF_RESKEY_ldapsearch="ldapsearch"}
: ${OCF_RESKEY_config=""}
: ${OCF_RESKEY_pidfile=""}
: ${OCF_RESKEY_user=""}
: ${OCF_RESKEY_group=""}
: ${OCF_RESKEY_services="ldap:///"}
: ${OCF_RESKEY_watch_suffix=""}
: ${OCF_RESKEY_ignore_suffix=""}
: ${OCF_RESKEY_bind_dn=""}
: ${OCF_RESKEY_password=""}
: ${OCF_RESKEY_parameters=""}
: ${OCF_RESKEY_stop_escalate=15}
: ${OCF_RESKEY_maxfiles=""}
USAGE="Usage: $0 {start|stop|status|monitor|validate-all|meta-data}"
ORIG_IFS=$IFS
NEWLINE='
'
################################################################################
usage() {
echo $USAGE >&2
}
meta_data()
{
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="slapd">
<version>0.1</version>
<longdesc lang="en">
Resource script for Stand-alone LDAP Daemon (slapd). It manages a slapd instance as an OCF resource.
</longdesc>
<shortdesc lang="en">Manages a Stand-alone LDAP Daemon (slapd) instance</shortdesc>
<parameters>
<parameter name="slapd" unique="0" required="0">
<longdesc lang="en">
Full path to the slapd binary.
For example, "/usr/sbin/slapd".
</longdesc>
<shortdesc lang="en">Full path to slapd binary</shortdesc>
<content type="string" default="/usr/sbin/slapd" />
</parameter>
<parameter name="ldapsearch" unique="0" required="0">
<longdesc lang="en">
Full path to the ldapsearch binary.
For example, "/usr/bin/ldapsearch".
</longdesc>
<shortdesc lang="en">Full path to ldapsearch binary</shortdesc>
<content type="string" default="ldapsearch" />
</parameter>
<parameter name="config" required="0" unique="1">
<longdesc lang="en">
Full path to a slapd configuration directory or a slapd configuration file.
For example, "/etc/ldap/slapd.d" or "/etc/ldap/slapd.conf".
</longdesc>
<shortdesc lang="en">Full path to configuration directory or file</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="pidfile" required="0" unique="0">
<longdesc lang="en">
File to read the PID from; read from olcPidFile/pidfile in config if not set.
</longdesc>
<shortdesc lang="en">File to read PID from</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="user" unique="0" required="0">
<longdesc lang="en">
User name or id slapd will run with. The group id is also changed to this
user's gid, unless the group parameter is used to override.
</longdesc>
<shortdesc lang="en">User name or id slapd will run with</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="group" unique="0" required="0">
<longdesc lang="en">
Group name or id slapd will run with.
</longdesc>
<shortdesc lang="en">Group name or id slapd will run with</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="services" required="0" unique="1">
<longdesc lang="en">
LDAP (and other scheme) URLs slapd will serve.
For example, "ldap://127.0.0.1:389 ldaps:/// ldapi:///"
</longdesc>
<shortdesc lang="en">LDAP (and other scheme) URLs to serve</shortdesc>
<content type="string" default="ldap:///"/>
</parameter>
<parameter name="watch_suffix" required="0" unique="0">
<longdesc lang="en">
Suffix (database backend) that will be monitored for availability. Multiple
suffixes can be specified by providing a space seperated list. By providing one
or more suffixes here, the ignore_suffix parameter is discarded. All suffixes
will be monitored if left blank.
</longdesc>
<shortdesc lang="en">Suffix that will be monitored for availability.</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="ignore_suffix" required="0" unique="0">
<longdesc lang="en">
Suffix (database backend) that will not be monitored for availability. Multiple
suffixes can be specified by providing a space seperated list. No suffix will
be excluded if left blank.
</longdesc>
<shortdesc lang="en">Suffix that will not be monitored for availability.</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="bind_dn" required="0" unique="0">
<longdesc lang="en">
Distinguished Name used to bind to the LDAP directory for testing. Leave blank
to bind to the LDAP directory anonymously.
</longdesc>
<shortdesc lang="en">Distinguished Name used to bind to the LDAP directory for testing.</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="password" required="0" unique="0">
<longdesc lang="en">
Password used to bind to the LDAP directory for testing.
</longdesc>
<shortdesc lang="en">Password used to bind to the LDAP directory for testing.</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="parameters" unique="0" required="0">
<longdesc lang="en">
slapd may be called with additional parameters.
Specify any of them here.
</longdesc>
<shortdesc lang="en">Any additional parameters to slapd.</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="stop_escalate" unique="0" required="0">
<longdesc lang="en">
Number of seconds to wait for shutdown (using SIGTERM) before resorting to
SIGKILL
</longdesc>
<shortdesc lang="en">Seconds before stop escalation to KILL</shortdesc>
<content type="integer" default="15" />
</parameter>
<parameter name="maxfiles">
<longdesc lang="en">
Maximum number of open files (for ulimit -n)
</longdesc>
<shortdesc lang="en">Max open files</shortdesc>
<content type="string" default="" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="20s" />
<action name="stop" timeout="20s" />
<action name="monitor" depth="0" timeout="20s" interval="60s" />
<action name="validate-all" timeout="20s" />
<action name="meta-data" timeout="5s" />
</actions>
</resource-agent>
END
}
watch_suffix()
{
local rc
if [ -n "$OCF_RESKEY_watch_suffix" ]; then
if echo "'$OCF_RESKEY_watch_suffix'" | grep "'$1'" >/dev/null 2>&1; then
rc=0
else
rc=1
fi
else
if echo "'$OCF_RESKEY_ignore_suffix'" | grep "'$1'" >/dev/null 2>&1; then
rc=1
else
rc=0
fi
fi
return $rc
}
slapd_pid()
{
local pid
if [ -f "$pid_file" ]; then
pid=`head -n 1 "$pid_file" 2>/dev/null`
if [ "X$pid" != "X" ]; then
echo "$pid"
return $OCF_SUCCESS
fi
ocf_exit_reason "slapd pid file '$pid_file' empty."
return $OCF_ERR_GENERIC
fi
ocf_log info "slapd pid file '$pid_file' does not exist."
return $OCF_NOT_RUNNING
}
slapd_status()
{
local pid=$1
if ! kill -0 $pid >/dev/null 2>&1; then
return $OCF_NOT_RUNNING
else
return $OCF_SUCCESS
fi
}
slapd_start()
{
local options
local reason
local rc
local state
slapd_status `slapd_pid`; state=$?
if [ $state -eq $OCF_SUCCESS ]; then
ocf_log info "slapd already running."
return $state
elif [ $state -eq $OCF_ERR_GENERIC ]; then
return $state
fi
options="-u $user -g $group"
if [ -d "$config" ]; then
options="$options -F $config"
elif [ -f "$config" ]; then
options="$options -f $config"
else
ocf_exit_reason "slapd configuration '$config' does not exist."
return $OCF_ERR_INSTALLED
fi
if [ -n "$parameters" ]; then
options="$options $parameters"
fi
if [ -n "$OCF_RESKEY_maxfiles" ]; then
ulimit -n $OCF_RESKEY_maxfiles
u_rc=$?
if [ "$u_rc" -ne 0 ]; then
ocf_log warn "Could not set ulimit for open files for slapd to '$OCF_RESKEY_maxfiles'"
fi
fi
if [ -n "$services" ]; then
$slapd -h "$services" $options 2>&1; rc=$?
else
$slapd $options 2>&1; rc=$?
fi
if [ $rc -ne 0 ]; then
ocf_exit_reason "slapd returned error."
return $OCF_ERR_GENERIC
fi
while true; do
slapd_monitor start
if [ $? = "$OCF_SUCCESS" ]; then
break
fi
sleep 1
done
ocf_log info "slapd started."
return $OCF_SUCCESS
}
slapd_stop()
{
local pid
local rc
local state
pid=`slapd_pid`; slapd_status $pid; state=$?
if [ $state -eq $OCF_NOT_RUNNING ]; then
ocf_log info "slapd already stopped."
return $OCF_SUCCESS
elif [ $state -eq $OCF_ERR_GENERIC ]; then
return $state
fi
ocf_stop_processes TERM $OCF_RESKEY_stop_escalate $pid; rc=$?
if [ $rc -eq 1 ]; then
ocf_log err "cannot stop slapd."
return $OCF_ERR_GENERIC
fi
if [ -f "$pid_file" ]; then
rm -f "$pid_file" >/dev/null 2>&1
fi
ocf_log info "slapd stopped."
return $OCF_SUCCESS
}
slapd_monitor()
{
local options
local rc
local state
local suffix
local suffixes
local err_option="-info"
slapd_status `slapd_pid`; state=$?
if [ $state -eq $OCF_NOT_RUNNING ]; then
if [ -z "$1" ];then
if ! ocf_is_probe; then
ocf_exit_reason "slapd process not found."
fi
fi
return $state
elif [ $state -ne $OCF_SUCCESS ]; then
ocf_exit_reason "slapd returned error."
return $state
fi
if [ -d "$config" ]; then
for suffix in `find "$config"/'cn=config' -type f -name olcDatabase* -exec \
sed -ne 's/^[[:space:]]*olcSuffix:[[:space:]]\+\(.\+\)/\1/p' {} \;`
do
suffix=${suffix#\"*}
suffix=${suffix%\"*}
if watch_suffix $suffix; then
suffixes="$suffixes $suffix"
fi
done
elif [ -f "$config" ]; then
for suffix in `sed -ne 's/^[[:space:]]*suffix[[:space:]]\+\(.\+\)/\1/p' "$config"`
do
suffix=${suffix#\"*}
suffix=${suffix%\"*}
if watch_suffix $suffix; then
suffixes="$suffixes $suffix"
fi
done
else
if ocf_is_probe; then
ocf_log info "slapd configuration '$config' does not exist during probe."
else
ocf_exit_reason "slapd configuration '$config' does not exist."
return $OCF_ERR_INSTALLED
fi
fi
options="-LLL -s base -x"
if [ -n "$bind_dn" ]; then
options="$options -D $bind_dn -w $password"
fi
[ -z "$1" ] && err_option=""
for suffix in $suffixes; do
ocf_run -q $err_option "$ldapsearch" -H "$services" -b "$suffix" $options >/dev/null 2>&1; rc=$?
case "$rc" in
"0")
ocf_log debug "slapd database with suffix '$suffix' reachable"
;;
"49")
ocf_exit_reason "slapd database with suffix '$suffix' unreachable. Invalid credentials."
return $OCF_ERR_CONFIGURED
;;
*)
if [ -z "$1" ] || [ -n "$1" -a $rc -ne 1 ]; then
ocf_exit_reason "slapd database with suffix '$suffix' unreachable. exit code ($rc)"
fi
state=$OCF_ERR_GENERIC
;;
esac
done
return $state
}
slapd_validate_all()
{
check_binary "$slapd"
check_binary "$ldapsearch"
if [ -z "$pid_file" ]; then
if [ -d "$config" ]; then
pid_file=`sed -ne \
's/^olcPidFile:[[:space:]]\+\(.\+\)[[:space:]]*/\1/p' \
"$config"/'cn=config.ldif' 2>/dev/null`
elif [ -f "$config" ]; then
pid_file=`sed -ne \
's/^pidfile[[:space:]]\+\(.\+\)/\1/p' \
"$config" 2>/dev/null`
else
if ocf_is_probe; then
ocf_log info "slapd configuration '$config' does not exist during probe."
else
ocf_exit_reason "slapd configuration '$config' does not exist."
return $OCF_ERR_INSTALLED
fi
fi
fi
if [ -z "$user" ]; then
user=`id -nu 2>/dev/null`
elif ! id "$user" >/dev/null 2>&1; then
ocf_exit_reason "slapd user '$user' does not exist"
return $OCF_ERR_INSTALLED
fi
if [ -z "$group" ]; then
group=`id -ng 2>/dev/null`
elif ! grep "^$group:" /etc/group >/dev/null 2>&1; then
ocf_exit_reason "slapd group '$group' does not exist"
return $OCF_ERR_INSTALLED
fi
pid_dir=`dirname "$pid_file"`
if [ ! -d "$pid_dir" ]; then
mkdir -p "$pid_dir"
chown -R "$user" "$pid_dir"
chgrp -R "$group" "$pid_dir"
fi
return $OCF_SUCCESS
}
#
# Main
#
slapd=$OCF_RESKEY_slapd
ldapsearch=$OCF_RESKEY_ldapsearch
config=$OCF_RESKEY_config
user=$OCF_RESKEY_user
group=$OCF_RESKEY_group
services=$OCF_RESKEY_services
bind_dn=$OCF_RESKEY_bind_dn
password=$OCF_RESKEY_password
parameters=$OCF_RESKEY_parameters
pid_file=$OCF_RESKEY_pidfile
if [ -z "$config" ]; then
config_dirname="/etc/ldap"
if [ -e "/etc/openldap" ]; then
config_dirname="/etc/openldap"
fi
config="$config_dirname/slapd.conf"
if [ -e "$config_dirname/slapd.d" ]; then
config="$config_dirname/slapd.d"
fi
fi
if [ $# -ne 1 ]; then
usage
exit $OCF_ERR_ARGS
fi
case $1 in
meta-data)
meta_data
exit $OCF_SUCCESS
;;
usage|help)
usage
exit $OCF_SUCCESS
;;
esac
slapd_validate_all
rc=$?
[ $rc -eq $OCF_SUCCESS ] || exit $rc
case $1 in
status)
slapd_status `slapd_pid`; state=$?
if [ $state -eq $OCF_SUCCESS ]; then
ocf_log debug "slapd is running."
elif [ $state -eq $OCF_NOT_RUNNING ]; then
ocf_log debug "slapd is stopped."
fi
exit $state
;;
start)
slapd_start
exit $?
;;
stop)
slapd_stop
exit $?
;;
monitor)
slapd_monitor; state=$?
exit $state
;;
validate-all)
exit $OCF_SUCCESS
;;
*)
usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/heartbeat/syslog-ng b/heartbeat/syslog-ng.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/syslog-ng
rename to heartbeat/syslog-ng.in
index f1081e5b8..8c97af750
--- a/heartbeat/syslog-ng
+++ b/heartbeat/syslog-ng.in
@@ -1,368 +1,368 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Description: Manages a syslog-ng instance, provided by NTT OSSC as an
# OCF High-Availability resource under Heartbeat/LinuxHA control
#
# Copyright (c) 2009 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################
# OCF parameters:
# OCF_RESKEY_syslog_ng_binary : Path to syslog-ng binary.
# Default is "/sbin/syslog-ng"
# OCF_RESKEY_configfile : Configuration file
# OCF_RESKEY_start_opts : Startup options
# OCF_RESKEY_kill_term_timeout: Number of seconds to await to confirm a
# normal stop method
#
# Only OCF_RESKEY_configfile must be specified. Each of the rests
# has its default value or refers OCF_RESKEY_configfile to make
# its value when no explicit value is given.
#
# Further infomation for setup:
# There are sample configurations at the end of this file.
#
###############################################################################
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
usage()
{
cat <<-!
usage: $0 action
action:
start : start a new syslog-ng instance
stop : stop the running syslog-ng instance
status : return the status of syslog-ng, run or down
monitor : return TRUE if the syslog-ng appears to be working.
meta-data : show meta data message
validate-all: validate the instance parameters
!
return $OCF_ERR_UNIMPLEMENTED
}
metadata_syslog_ng()
{
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="syslog-ng">
<version>1.0</version>
<longdesc lang="en">
This script manages a syslog-ng instance as an HA resource.
</longdesc>
<shortdesc lang="en">Syslog-ng resource agent</shortdesc>
<parameters>
<parameter name="configfile" unique="0" required="1">
<longdesc lang="en">
This parameter specifies a configuration file
for a syslog-ng instance managed by this RA.
</longdesc>
<shortdesc lang="en">Configuration file</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="syslog_ng_binary" unique="0">
<longdesc lang="en">
This parameter specifies syslog-ng's executable file.
</longdesc>
<shortdesc lang="en">syslog-ng executable</shortdesc>
<content type="string" default="/sbin/syslog-ng"/>
</parameter>
<parameter name="start_opts" unique="0">
<longdesc lang="en">
This parameter specifies startup options for a
syslog-ng instance managed by this RA. When no value is given, no startup
options is used. Don't use option '-F'. It causes a stuck of a start action.
</longdesc>
<shortdesc lang="en">Start options</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="kill_term_timeout" unique="0">
<longdesc lang="en">
On a stop action, a normal stop method(pkill -TERM) is firstly used.
And then the confirmation of its completion is waited for
the specified seconds by this parameter.
The default value is 10.
</longdesc>
<shortdesc lang="en">Number of seconds to await to confirm a normal stop method</shortdesc>
<content type="integer" default="10"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="60s" />
<action name="stop" timeout="120s" />
<action name="status" timeout="60s" />
<action name="monitor" depth="0" timeout="60s" interval="60s" />
<action name="meta-data" timeout="5s" />
<action name="validate-all" timeout="5s"/>
</actions>
</resource-agent>
END
return $OCF_SUCCESS
}
monitor_syslog_ng()
{
set -- $(pgrep -f "$PROCESS_PATTERN" 2>/dev/null)
case $# in
0) ocf_log debug "No syslog-ng process for $CONFIGFILE"
return $OCF_NOT_RUNNING;;
1) return $OCF_SUCCESS;;
esac
ocf_log warn "Multiple syslog-ng process for $CONFIGFILE"
return $OCF_SUCCESS
}
start_syslog_ng()
{
monitor_syslog_ng
if [[ $? = "$OCF_SUCCESS" ]]; then
return $OCF_SUCCESS
fi
# set -- $SYSLOG_NG_OPTS
# ocf_run "$SYSLOG_NG_EXE" -f "$SYSLOG_NG_CONF" "$@"
# reduce to this?
ocf_run "$SYSLOG_NG_EXE" -f "$CONFIGFILE" $START_OPTS
ocf_status=$?
if [[ "$ocf_status" != "$OCF_SUCCESS" ]]; then
return $OCF_ERR_GENERIC
fi
while true; do
monitor_syslog_ng
if [[ $? = "$OCF_SUCCESS" ]]; then
return $OCF_SUCCESS
fi
sleep 1
done
}
stop_syslog_ng()
{
pkill -TERM -f "$PROCESS_PATTERN"
typeset lapse_sec=0
while pgrep -f "$PROCESS_PATTERN" > /dev/null; do
sleep 1
lapse_sec=$(( lapse_sec + 1 ))
ocf_log debug "stop_syslog_ng[$SYSLOG_NG_NAME]: stop NORM $lapse_sec/$KILL_TERM_TIMEOUT"
if [ $lapse_sec -ge $KILL_TERM_TIMEOUT ]; then
break
fi
done
# if the process can't be removed, then the following part is
# not going to be executed (the RA will be killed by lrmd on
# timeout) and the pidfile will remain; don't know if that
# has any consequences
# 2009/09/18 Nakahira
# If the syslog-ng process hangs, syslog-ng RA waits
# $KILL_TERM_TIMEOUT seconds.
# The stop timeout of RA should be longer than $KILL_TERM_TIMEOUT.
lapse_sec=0
while pgrep -f "$PROCESS_PATTERN" > /dev/null; do
pkill -KILL -f "$PROCESS_PATTERN"
sleep 1
lapse_sec=$(( lapse_sec + 1 ))
ocf_log debug "stop_syslog_ng[$SYSLOG_NG_NAME]: suspend syslog_ng by SIGKILL ($lapse_sec/@@@)"
done
return $OCF_SUCCESS
}
status_syslog_ng()
{
# ???? why not monitor and then print running or stopped
monitor_syslog_ng
rc=$?
if [ $rc = $OCF_SUCCESS ]; then
echo "Syslog-ng service is running."
elif [ $rc = $OCF_NOT_RUNNING ]; then
echo "Syslog-ng service is stopped."
else
echo "Mutiple syslog-ng process for $CONFIGFILE."
fi
return $rc
}
validate_all_syslog_ng()
{
ocf_log info "validate_all_syslog_ng[$SYSLOG_NG_NAME]"
return $OCF_SUCCESS
}
if [[ "$1" = "meta-data" ]]; then
metadata_syslog_ng
exit $?
fi
CONFIGFILE="${OCF_RESKEY_configfile}"
if [[ -z "$CONFIGFILE" ]]; then
ocf_log err "undefined parameter:configfile"
exit $OCF_ERR_CONFIGURED
fi
SYSLOG_NG_NAME=${CONFIGFILE##*/}
SYSLOG_NG_NAME=${SYSLOG_NG_NAME%.*}
SYSLOG_NG_EXE="${OCF_RESKEY_syslog_ng_binary:-/sbin/syslog-ng}"
if [[ ! -x "$SYSLOG_NG_EXE" ]]; then
ocf_log err "Invalid value:syslog_ng_binary:$SYSLOG_NG_EXE"
exit $OCF_ERR_CONFIGURED
fi
# actually, the pidfile has no function; the status is checked by
# testing for a running process only
KILL_TERM_TIMEOUT="${OCF_RESKEY_kill_term_timeout-10}"
if ! ocf_is_decimal "$KILL_TERM_TIMEOUT"; then
ocf_log err "Invalid value:kill_term_timeout:$KILL_TERM_TIMEOUT"
exit $OCF_ERR_CONFIGURED
fi
START_OPTS=${OCF_RESKEY_start_opts}
EXECUTABLE=$(basename "$SYSLOG_NG_EXE")
PROCESS_PATTERN="$EXECUTABLE -f $CONFIGFILE"
COMMAND=$1
case "$COMMAND" in
start)
ocf_log debug "[$SYSLOG_NG_NAME] Enter syslog_ng start"
start_syslog_ng
func_status=$?
ocf_log debug "[$SYSLOG_NG_NAME] Leave syslog_ng start $func_status"
exit $func_status
;;
stop)
ocf_log debug "[$SYSLOG_NG_NAME] Enter syslog_ng stop"
stop_syslog_ng
func_status=$?
ocf_log debug "[$SYSLOG_NG_NAME] Leave syslog_ng stop $func_status"
exit $func_status
;;
status)
status_syslog_ng
exit $?
;;
monitor)
#ocf_log debug "[$SYSLOG_NG_NAME] Enter syslog_ng monitor"
monitor_syslog_ng
func_status=$?
#ocf_log debug "[$SYSLOG_NG_NAME] Leave syslog_ng monitor $func_status"
exit $func_status
;;
validate-all)
validate_all_syslog_ng
exit $?
;;
*)
usage
;;
esac
# vim: set sw=4 ts=4 :
### A sample snippet of cib.xml for a syslog-ng resource
##
# <primitive id="prmApSyslog-ng" class="ocf" type="syslog-ng" provider="heartbeat">
# <instance_attributes id="prmDummyB_instance_attrs">
# <attributes>
# <nvpair id="atr:Syslog-ng:syslog-ng:configfile" name="configfile" value="/etc/syslog-ng/syslog-ng-ext.conf"/>
# </attributes>
# </instance_attributes>
# <operations>
# <op id="op:prmSyslog-ng:start" name="start" timeout="60s" on_fail="restart"/>
# <op id="op:prmSyslog-ng:monitor" name="monitor" interval="10s" timeout="60s" on_fail="restart"/>
# <op id="op:prmSyslog-ng:stop" name="stop" timeout="60s" on_fail="block"/>
# </operations>
# </primitive>
### A sample syslog-ng configuration file for a log collecting host
###
### This sample is for a log collecting host by syslog-ng.
### A syslog-ng process configurated by this sample accepts all messages
### from a certain network. Any message from the network is preserved into
### a file for security infomation. Restricting messages to "authpriv" from
### the network is done on log sending hosts. (See the sample below)
### Any internal message of the syslog-ng process is preserved into its
### dedicated file. And any "authpriv" internal message of the syslog-ng
### process is also preserved into the security infomation file.
###
### Change "f_incoming" to suit your enviroment.
### If you use it as a configuration file for the sample cib.xml above,
### save it into "/etc/syslog-ng/syslog-ng-ext.conf".
##
#options {
# sync (0);
# time_reopen (10);
# log_fifo_size (1000);
# long_hostnames (off);
# use_dns (yes);
# use_fqdn (no);
# create_dirs (no);
# keep_hostname (yes); };
#
#source s_internal { internal(); };
#source s_incoming { udp(port(514)); };
#filter f_internal { facility(authpriv); };
#filter f_incoming { netmask("172.20.0.0/255.255.192.0"); };
#
#destination d_internal { file("/var/log/syslog-ng-ext.log" perm(0640));};
#destination d_incoming {
# file("/var/log/secure-ext.log" create_dirs(yes) perm(0640)); };
#
#log { source(s_internal); destination(d_internal); };
#log { source(s_internal); filter(f_internal); destination(d_incoming); };
#log { source(s_incoming); filter(f_incoming); destination(d_incoming); };
### A sample snippet of syslog-ng configuration file for a log sending host
###
### This sample is for a log sending host that uses syslog-ng.
###
### Replace "syslog-ng-ext" to the IP address or the hostname of your
### log collecting host and append it to "syslog-ng.conf" of each log sending
### host. See the install default syslog-ng.conf to know what "s_sys" and
### "f_auth" are.
##
#destination d_outgoing { udp("syslog-ng-ext" port(514)); };
#log { source(s_sys); filter(f_auth); destination(d_outgoing); };
### A sample snippet of syslog configuration file for a log sending host
###
### This sample is for a log sending host that uses syslog.
###
### Replace "syslog-ng-ext" to the IP address or the hostname of your
### log collecting host and append it to "syslog.conf" of each log sending
### host.
##
# authpriv.* @syslog-ng-ext
diff --git a/heartbeat/vsftpd b/heartbeat/vsftpd.in
old mode 100755
new mode 100644
similarity index 99%
rename from heartbeat/vsftpd
rename to heartbeat/vsftpd.in
index ce9dfabaf..6419746e9
--- a/heartbeat/vsftpd
+++ b/heartbeat/vsftpd.in
@@ -1,253 +1,253 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Resource script for vsftpd
#
# Description: Manages vsftpd as an OCF resource in
# an Active-Passive High Availability setup.
#
# Author: Michel Rode <rode@b1-systems.de> : vsftpd script
# License: GNU General Public License (GPLv2)
#
#
# usage: $0 {start|stop|status|monitor|validate-all|meta-data}
#
# The "start" arg starts vsftpd.
#
# The "stop" arg stops it.
#
# OCF parameters:
# OCF_RESKEY_binpath
# OCF_RESKEY_conffile
# OCF_RESKEY_pidfile
#
##########################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
: ${OCF_RESKEY_binpath="/usr/sbin/vsftpd"}
: ${OCF_RESKEY_conffile="/etc/vsftpd/vsftpd.conf"}
: ${OCF_RESKEY_pidfile="/var/run/vsftpd.pid"}
USAGE="Usage: $0 {start|stop|status|monitor|validate-all|meta-data}";
##########################################################################
usage()
{
echo $USAGE >&2
}
meta_data()
{
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="vsftpd">
<version>1.0</version>
<longdesc lang="en">
This script manages vsftpd
</longdesc>
<shortdesc lang="en">Manages an vsftpd</shortdesc>
<parameters>
<parameter name="binpath">
<longdesc lang="en">
The vsftpd binary path.
For example, "/usr/sbin/vsftpd"
</longdesc>
<shortdesc lang="en">Full path to the vsftpd binary</shortdesc>
<content type="string" default="/usr/sbin/vsftpd"/>
</parameter>
<parameter name="conffile">
<longdesc lang="en">
The vsftpd configuration file name with full path.
For example, "/etc/vsftpd/vsftpd.conf"
</longdesc>
<shortdesc lang="en">Configuration file name with full path</shortdesc>
<content type="string" default="/etc/vsftpd/vsftpd.conf" />
</parameter>
<parameter name="pidfile">
<longdesc lang="en">
The vsftpd pidfile with full path.
For example, "/var/run/vsftpd.pid"
</longdesc>
<shortdesc lang="en">PID file with full path</shortdesc>
<content type="string" default="/var/run/vsftpd.pid" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="20s"/>
<action name="stop" timeout="20s"/>
<action name="monitor" depth="0" timeout="20s" interval="60s" />
<action name="validate-all" timeout="20s"/>
<action name="meta-data" timeout="5s"/>
</actions>
</resource-agent>
END
exit $OCF_SUCCESS
}
get_pidfile()
{
PIDFILE=$OCF_RESKEY_pidfile
}
vsftpd_status()
{
if [ -n "$PIDFILE" -a -f $PIDFILE ]; then
# vsftpd is probably running
PID=`cat $PIDFILE`
if [ -n "$PID" ]; then
if ps -p $PID | grep vsftpd >/dev/null ; then
ocf_log info "vsftpd daemon running"
return $OCF_SUCCESS
else
ocf_log info "vsftpd daemon is not running but pid file exists"
return $OCF_ERR_GENERIC
fi
else
ocf_log err "PID file empty!"
return $OCF_ERR_GENERIC
fi
fi
# vsftpd is not running
ocf_log info "vsftpd daemon is not running"
return $OCF_NOT_RUNNING
}
vsftpd_start()
{
# if vsftpd is running return success
vsftpd_status
retVal=$?
if [ $retVal -eq $OCF_SUCCESS ]; then
exit $OCF_SUCCESS
elif [ $retVal -ne $OCF_NOT_RUNNING ]; then
ocf_log err "Error. Unknown status."
exit $OCF_ERR_GENERIC
fi
if [ -n "$OCF_RESKEY_binpath" ]; then
COMMAND="$OCF_RESKEY_binpath"
fi
if [ -n "$OCF_RESKEY_conffile" ]; then
COMMAND="$COMMAND $OCF_RESKEY_conffile"
fi
$COMMAND;
if [ $? -ne 0 ]; then
ocf_log err "Error. vsftpd returned error $?."
exit $OCF_ERR_GENERIC
fi
PID=$( pgrep $OCF_RESKEY_binpath )
case $? in
0)
ocf_log info "PID file (pid:${PID} at $PIDFILE) created for vsftpd."
ocf_log info "Started vsftpd."
echo $PID > $PIDFILE
exit $OCF_SUCCESS
;;
1)
rm -f "$PIDFILE" > /dev/null 2>&1
ocf_log info "$Error getting pid."
exit $OCF_ERR_GENERIC
;;
*)
rm -f "$PIDFILE" > /dev/null 2>&1
ocf_exit_reason "Error encountered detecting pid of vsftpd."
exit OCF_ERR_GENERIC
;;
esac
}
vsftpd_stop()
{
if vsftpd_status ; then
PID=`cat $PIDFILE`
if [ -n "$PID" ] ; then
kill $PID
if [ $? -ne 0 ]; then
kill -s KILL $PID
if [ $? -ne 0 ]; then
ocf_log err "Error. Could not stop vsftpd daemon."
return $OCF_ERR_GENERIC
fi
fi
rm $PIDFILE 2>/dev/null
fi
fi
ocf_log info "Stopped vsftpd daemon."
exit $OCF_SUCCESS
}
vsftpd_monitor()
{
vsftpd_status
}
vsftpd_validate_all()
{
check_binary $OCF_RESKEY_binpath
if [ -n "$OCF_RESKEY_conffile" -a ! -f "$OCF_RESKEY_conffile" ]; then
ocf_log err "Config file $OCF_RESKEY_conffile does not exist."
exit $OCF_ERR_ARGS
fi
return $OCF_SUCCESS
}
#
# Main
#
if [ $# -ne 1 ]; then
usage
exit $OCF_ERR_ARGS
fi
case $1 in
start) get_pidfile
vsftpd_start
;;
stop) get_pidfile
vsftpd_stop
;;
status) get_pidfile
vsftpd_status
;;
monitor)get_pidfile
vsftpd_monitor
;;
validate-all) vsftpd_validate_all
;;
meta-data) meta_data
;;
usage) usage
exit $OCF_SUCCESS
;;
*) usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/ASEHAagent.sh b/rgmanager/src/resources/ASEHAagent.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/ASEHAagent.sh
rename to rgmanager/src/resources/ASEHAagent.sh.in
index ec78ce9db..5fe807b8a
--- a/rgmanager/src/resources/ASEHAagent.sh
+++ b/rgmanager/src/resources/ASEHAagent.sh.in
@@ -1,900 +1,900 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Sybase Availability Agent for Red Hat Cluster v15.0.2
# Copyright (C) - 2007
# Sybase, Inc. All rights reserved.
#
# Sybase Availability Agent for Red Hat Cluster v15.0.2 is licensed
# under the GNU General Public License Version 2.
#
# Author(s):
# Jian-ping Hui <jphui@sybase.com>
#
# Description: Service script for starting/stopping/monitoring \
# Sybase Adaptive Server on: \
# Red Hat Enterprise Linux 5 ES \
# Red Hat Enterprise Linux 5 AS
#
# NOTES:
#
# (1) Before running this script, we assume that user has installed
# Sybase ASE 15.0.2 or higher version on the machine. Please
# customize your configuration in /etc/cluster/cluster.conf according
# to your actual environment. We assume the following files exist before
# you start the service:
# /$sybase_home/SYBASE.sh
# /$sybase_home/$sybase_ase/install/RUN_$server_name
#
# (2) You can customize the interval value in the meta-data section if needed:
# <action name="start" timeout="300" />
# <action name="stop" timeout="300" />
#
# <!-- Checks to see if it''s mounted in the right place -->
# <action name="status" interval="30" timeout="100" />
# <action name="monitor" interval="30" timeout="100" />
#
# <!--Checks to see if we can read from the mountpoint -->
# <action name="status" depth="10" timeout="100" interval="120" />
# <action name="monitor" depth="10" timeout="100" interval="120" />
#
# <action name="meta-data" timeout="5" />
# <action name="validate-all" timeout="5" />
# The timeout value is not supported by Redhat in RHCS5.0.
#
# (3) This script should be put under /usr/share/cluster. Its owner should be "root" with
# execution permission.
#
. /etc/init.d/functions
. $(dirname $0)/ocf-shellfuncs
PROG=${0}
export LD_POINTER_GUARD=0
#######################################################################################
# Declare some variables we will use in the script. Please don't change their values. #
#######################################################################################
declare login_string=""
declare RUNSERVER_SCRIPT=$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase/install/RUN_$OCF_RESKEY_server_name
declare CONSOLE_LOG=$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase/install/$OCF_RESKEY_server_name.log
##################################################################################################
# This function will be called by rgmanager to get the meta data of resource agent "ASEHAagent". #
# NEVER CHANGE ANYTHING IN THIS FUNCTION.
##################################################################################################
meta_data()
{
cat <<EOT
<?xml version="1.0" ?>
<resource-agent name="ASEHAagent" version="rgmanager 2.0">
<version>1.0</version>
<longdesc lang="en">
Sybase ASE Failover Instance
</longdesc>
<shortdesc lang="en">
Sybase ASE Failover Instance
</shortdesc>
<parameters>
<parameter name="name" unique="1" primary="1">
<longdesc lang="en">
Instance name of resource agent "ASEHAagent"
</longdesc>
<shortdesc lang="en">
name
</shortdesc>
<content type="string" />
</parameter>
<parameter name="sybase_home" required="1">
<longdesc lang="en">
The home directory of sybase products
</longdesc>
<shortdesc lang="en">
SYBASE home directory
</shortdesc>
<content type="string" />
</parameter>
<parameter name="sybase_ase" required="1">
<longdesc lang="en">
The directory name under sybase_home where ASE products are installed
</longdesc>
<shortdesc lang="en">
SYBASE_ASE directory name
</shortdesc>
<content type="string" default="ASE-15_0" />
</parameter>
<parameter name="sybase_ocs" required="1">
<longdesc lang="en">
The directory name under sybase_home where OCS products are installed, i.e. ASE-15_0
</longdesc>
<shortdesc lang="en">
SYBASE_OCS directory name
</shortdesc>
<content type="string" default="OCS-15_0" />
</parameter>
<parameter name="server_name" required="1">
<longdesc lang="en">
The ASE server name which is configured for the HA service
</longdesc>
<shortdesc lang="en">
ASE server name
</shortdesc>
<content type="string" />
</parameter>
<parameter name="login_file" required="1">
<longdesc lang="en">
The full path of login file which contains the login/password pair
</longdesc>
<shortdesc lang="en">
Login file
</shortdesc>
<content type="string" />
</parameter>
<parameter name="interfaces_file" required="1">
<longdesc lang="en">
The full path of interfaces file which is used to start/access the ASE server
</longdesc>
<shortdesc lang="en">
Interfaces file
</shortdesc>
<content type="string" />
</parameter>
<parameter name="sybase_user" required="1">
<longdesc lang="en">
The user who can run ASE server
</longdesc>
<shortdesc lang="en">
Sybase user
</shortdesc>
<content type="string" default="sybase" />
</parameter>
<parameter name="shutdown_timeout" required="1">
<longdesc lang="en">
The maximum seconds to wait for the ASE server to shutdown before killing the process directly
</longdesc>
<shortdesc>
Shutdown timeout value
</shortdesc>
<content type="integer" default="0" />
</parameter>
<parameter name="start_timeout" required="1">
<longdesc lang="en">
The maximum seconds to wait for an ASE server to complete before determining that the server had failed to start
</longdesc>
<shortdesc lang="en">
Start timeout value
</shortdesc>
<content type="integer" default="0" />
</parameter>
<parameter name="deep_probe_timeout" required="1">
<longdesc lang="en">
The maximum seconds to wait for the response of ASE server before determining that the server had no response while running deep probe
</longdesc>
<shortdesc lang="en">
Deep probe timeout value
</shortdesc>
<content type="integer" default="0" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="300" />
<action name="stop" timeout="300" />
<!-- Checks to see if it''s mounted in the right place -->
<action name="status" interval="30" timeout="100" />
<action name="monitor" interval="30" timeout="100" />
<!--Checks to see if we can read from the mountpoint -->
<action name="status" depth="10" timeout="100" interval="120" />
<action name="monitor" depth="10" timeout="100" interval="120" />
<action name="meta-data" timeout="5" />
<action name="validate-all" timeout="5" />
</actions>
<special tag="rgmanager">
</special>
</resource-agent>
EOT
}
##################################################################################################
# Function Name: verify_all #
# Parameter: None #
# Return value: #
# 0 SUCCESS #
# OCF_ERR_ARGS Parameters are invalid #
# Description: Do some validation on the user-configurable stuff at the beginning of the script. #
##################################################################################################
verify_all()
{
ocf_log debug "ASEHAagent: Start 'verify_all'"
# Check if the parameter 'sybase_home' is set.
if [[ -z "$OCF_RESKEY_sybase_home" ]]
then
ocf_log err "ASEHAagent: The parameter 'sybase_home' is not set."
return $OCF_ERR_ARGS
fi
# Check if the parameter 'sybase_home' is a valid path.
if [[ ! -d $OCF_RESKEY_sybase_home ]]
then
ocf_log err "ASEHAagent: The sybase_home '$OCF_RESKEY_sybase_home' doesn't exist."
return $OCF_ERR_ARGS
fi
# Check if the script file SYBASE.sh exists
if [[ ! -f $OCF_RESKEY_sybase_home/SYBASE.sh ]]
then
ocf_log err "ASEHAagent: The file $OCF_RESKEY_sybase_home/SYBASE.sh is required to run this script. Failed to run the script."
return $OCF_ERR_ARGS
fi
# Check if the parameter 'sybase_ase' is set.
if [[ -z "$OCF_RESKEY_sybase_ase" ]]
then
ocf_log err "ASEHAagent: The parameter 'sybase_ase' is not set."
return $OCF_ERR_ARGS
fi
# Check if the directory /$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase exists.
if [[ ! -d $OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase ]]
then
ocf_log err "ASEHAagent: The directory '$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase' doesn't exist."
return $OCF_ERR_ARGS
fi
# Check if the parameter 'sybase_ocs' is set.
if [[ -z "$OCF_RESKEY_sybase_ocs" ]]
then
ocf_log err "ASEHAagent: The parameter 'sybase_ocs' is not set."
return $OCF_ERR_ARGS
fi
# Check if the directory /$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ocs exists.
if [[ ! -d $OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ocs ]]
then
ocf_log err "ASEHAagent: The directory '$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ocs' doesn't exist."
return $OCF_ERR_ARGS
fi
# Check if the parameter 'server_name' is set.
if [[ -z "$OCF_RESKEY_server_name" ]]
then
ocf_log err "ASEHAagent: The parameter 'server_name' is not set."
return $OCF_ERR_ARGS
fi
# Check if the Run_server file exists.
if [[ ! -f $RUNSERVER_SCRIPT ]]
then
ocf_log err "ASEHAagent: The file $RUNSERVER_SCRIPT doesn't exist. The sybase directory may be incorrect."
return $OCF_ERR_ARGS
fi
# Check if the parameter 'login_file' is set.
if [[ -z "$OCF_RESKEY_login_file" ]]
then
ocf_log err "ASEHAagent: The parameter 'login_file' is not set."
return $OCF_ERR_ARGS
fi
# Check if the login file exist.
if [[ ! -f $OCF_RESKEY_login_file ]]
then
ocf_log err "ASEHAagent: The login file '$OCF_RESKEY_login_file' doesn't exist."
return $OCF_ERR_ARGS
fi
# Check if the parameter 'sybase_user' is set
if [[ -z "$OCF_RESKEY_sybase_user" ]]
then
ocf_log err "ASEHAagent: The parameter 'sybase_user' is not set."
return $OCF_ERR_ARGS
fi
# Check if the user 'sybase_user' exist
id -u $OCF_RESKEY_sybase_user
if [[ $? != 0 ]]
then
ocf_log err "ASEHAagent: The user '$OCF_RESKEY_sybase_user' doesn't exist in the system."
return $OCF_ERR_ARGS
fi
# Check if the parameter 'interfaces_file' is set
if [[ -z "$OCF_RESKEY_interfaces_file" ]]
then
ocf_log err "ASEHAagent: The parameter 'interfaces_file' is not set."
return $OCF_ERR_ARGS
fi
# Check if the file 'interfaces_file' exists
if [[ ! -f $OCF_RESKEY_interfaces_file ]]
then
ocf_log err "ASEHAagent: The interfaces file '$OCF_RESKEY_interfaces_file' doesn't exist."
return $OCF_ERR_ARGS
fi
# Check if the parameter 'shutdown_timeout' is a valid value
if [[ $OCF_RESKEY_shutdown_timeout -eq 0 ]]
then
ocf_log err "ASEHAagent: The parameter 'shutdown_timeout' is not set. Its value cannot be zero."
return $OCF_ERR_ARGS
fi
# Check if the parameter 'start_timeout' is a valid value
if [[ $OCF_RESKEY_start_timeout -eq 0 ]]
then
ocf_log err "ASEHAagent: The parameter 'start_timeout' is not set. Its value cannot be zero."
return $OCF_ERR_ARGS
fi
# Check if the parameter 'deep_probe_timeout' is a valid value
if [[ $OCF_RESKEY_deep_probe_timeout -eq 0 ]]
then
ocf_log err "ASEHAagent: The parameter 'deep_probe_timeout' is not set. Its value cannot be zero."
return $OCF_ERR_ARGS
fi
ocf_log debug "ASEHAagent: End 'verify_all' successfully."
return 0
}
################################################################################################################
# Function name: get_login_string #
# Parameter: None #
# Return value: #
# 0 SUCCESS #
# 1 FAIL #
# Description: Analyze the login_file to format the login string. This function will set the global variable #
# "login_string". If the login/password is clear text, the "login_string" will become to "-Ulogin #
# -Ppassword" if there is no error. If there are any errors in this function, the string #
# "login_string" will be still empty. In current stage, the encrypted string is not supported #
# because "haisql" is not available on this platform. #
################################################################################################################
get_login_string()
{
tmpstring=""
login_sting=""
# Read the first column. The valid value will be "normal" or "encrypted". Any other values are invalid.
login_type=`head -1 $OCF_RESKEY_login_file | awk '{print $1}'`
if [[ $login_type = "normal" ]]
then
# The login/password pair is saved in clear text.
# Abstract the login/password from the line.
tmpstring=`head -1 $OCF_RESKEY_login_file | awk '{print $2}'`
# Abstract "user" from the string.
user=`echo $tmpstring | awk -F'/' '{print $1}'`
# Check if the "user" string is NULL. If it is NULL, it means this is not a valid user.
if [[ -z $user ]]
then
ocf_log err "ASEHAagent: Login username is not specified in the file '$OCF_RESKEY_login_file'"
return 1
fi
# Abstract "password" from the string.
passwd=`echo $tmpstring | awk -F'/' '{print $2}'`
# Format the "login_string".
login_string="-U$user -P$passwd"
else
# The login_type is invalid value.
ocf_log err "ASEHAagent: Login type specified in the file $OCF_RESKEY_login_file is not 'normal' or 'encrypted' which are only supported values."
return 1
fi
# The "login_file" has been analyzed successfully. Now, the value of "login_string" contains the login/password information.
return 0
}
##############################################################################################
# Function name: ase_start #
# Parameter: None #
# Return value: #
# 0 SUCCESS #
# 1 FAIL #
# Description: This function is used to start the ASE server in primary or secondary server. #
##############################################################################################
ase_start()
{
ocf_log debug "ASEHAagent: Start 'ase_start'"
# Check if the server is running. If yes, return SUCCESS directly. Otherwise, continue the start work.
ase_is_running
if [[ $? = 0 ]]
then
# The server is running.
ocf_log info "ASEHAagent: Server is running. Start is success."
return 0
fi
# The server is not running. We need to start it.
# If the log file existed, delete it.
if [[ -f $CONSOLE_LOG ]]
then
rm -f $CONSOLE_LOG
fi
ocf_log debug "ASEHAagent: Starting '$OCF_RESKEY_server_name'..."
# Run runserver script to start the server. Since this script will be run by root and ASE server
# needs to be run by another user, we need to change the user to sybase_user first. Then, run
# the script to start the server.
su $OCF_RESKEY_sybase_user -c ksh << EOF
# set required SYBASE environment by running SYBASE.sh.
. $OCF_RESKEY_sybase_home/SYBASE.sh
# Run the RUNSERVER_SCRIPT to start the server.
. $RUNSERVER_SCRIPT > $CONSOLE_LOG 2>&1 &
EOF
# Monitor every 1 seconds if the server has
# recovered, until RECOVERY_TIMEOUT.
t=0
while [[ $t -le $OCF_RESKEY_start_timeout ]]
do
grep -s "Recovery complete." $CONSOLE_LOG > /dev/null 2>&1
if [[ $? != 0 ]]
then
# The server has not completed the recovery. We need to continue to monitor the recovery
# process.
t=`expr $t + 1`
else
# The server has completed the recovery.
ocf_log info "ASEHAagent: ASE server '$OCF_RESKEY_server_name' started successfully."
break
fi
sleep 1
done
# If $t is larger than start_timeout, it means the ASE server cannot start in given time. Otherwise, it
# means the ASE server has started successfully.
if [[ $t -gt $OCF_RESKEY_start_timeout ]]
then
# The server cannot start in specified time. We think the start is failed.
ocf_log err "ASEHAagent: Failed to start ASE server '$OCF_RESKEY_server_name'. Please check the server error log $CONSOLE_LOG for possible problems."
return 1
fi
ocf_log debug "ASEHAagent: End 'ase_start' successfully."
return 0
}
#############################################################################################
# Function name: ase_stop #
# Parameter: None #
# Return value: #
# 0 SUCCESS #
# 1 FAIL #
# Description: This function is used to stop the ASE server in primary or secondary server. #
#############################################################################################
ase_stop()
{
ocf_log debug "ASEHAagent: Start 'ase_stop'"
# Check if the ASE server is still running.
ase_is_running
if [[ $? != 0 ]]
then
# The ASE server is not running. We need not to shutdown it.
ocf_log info "ASEHAagent: The dataserver $OCF_RESKEY_server_name is not running."
return 0
fi
# Call get_login_string() to parse the login/password string
get_login_string
if [[ $? = 1 ]]
then
# The login account cannot be used. So we will kill the process directly.
ocf_log info "ASEHAagent: Cannot parse the login file $OCF_RESKEY_login_file. Kill the processes of ASE directly."
# Kill the OS processes immediately.
kill_ase 0
return $?
fi
# Just in case things are hung, start a process that will wait for the
# timeout period, then kill any remaining porcesses. We'll need to
# monitor this process (set -m), so we can terminate it later if it is
# not needed.
set -m
$PROG kill &
KILL_PID=$! # If successful, we will also terminate watchdog process
# Run "shutdown with nowait" from isql command line to shutdown the server
su $OCF_RESKEY_sybase_user -c ksh << EOF
# set required SYBASE environment by running SYBASE.sh.
. $OCF_RESKEY_sybase_home/SYBASE.sh
# Run "shutdown with nowait" to shutdown the server immediately.
(echo "use master" ; echo go ; echo "shutdown with nowait"; echo go) | \
\$SYBASE/\$SYBASE_OCS/bin/isql $login_string -S$OCF_RESKEY_server_name -I$OCF_RESKEY_interfaces_file &
EOF
sleep 5
# Check if the server has been shut down successfully
t=0
while [[ $t -lt $OCF_RESKEY_shutdown_timeout ]]
do
# Search "ueshutdown: exiting" in the server log. If found, it means the server has been shut down.
# Otherwise, we need to wait.
tail $CONSOLE_LOG | grep "ueshutdown: exiting" > /dev/null 2>&1
if [[ $? != 0 ]]
then
# The shutdown is still in processing. Wait...
sleep 2
t=`expr $t+2`
else
# The shutdown is success.
ocf_log info "ASEHAagent: ASE server '$OCF_RESKEY_server_name' shutdown with isql successfully."
break
fi
done
# If $t is larger than shutdown_timeout, it means the ASE server cannot be shut down in given time. We need
# to wait for the background kill process to kill the OS processes directly.
if [[ $t -ge $OCF_RESKEY_shutdown_timeout ]]
then
ocf_log err "ASEHAagent: Shutdown of '$OCF_RESKEY_server_name' from isql failed. Server is either down or unreachable."
fi
# Here, the ASE server has been shut down by isql command or killed by background process. We need to do
# further check to make sure all processes have gone away before saying shutdown is complete. This stops the
# other node from starting up the package before it has been stopped and the file system has been unmounted.
# Get all processes ids from log file
declare -a ENGINE_ALL=(`sed -n -e '/engine /s/^.*os pid \([0-9]*\).*online$/\1/p' $CONSOLE_LOG`)
typeset -i num_procs=${#ENGINE_ALL[@]}
# We cannot find any process id from log file. It may be because the log file is corrupted or be deleted.
# In this case, we determine the shutdown is failed.
if [[ "${ENGINE_ALL[@]}" = "" ]]
then
ocf_log err "ASEHAagent: Unable to find the process id from $CONSOLE_LOG."
ocf_log err "ASEHAagent: Stop ASE server failed."
return 1
fi
# Monitor the system processes to make sure all ASE related processes have gone away.
while true
do
# To every engine process, search it in system processes list. If it is not in the
# list, it means this process has gone away. Otherwise, we need to wait for it is
# killed by background process.
for i in ${ENGINE_ALL[@]}
do
ps -fu $OCF_RESKEY_sybase_user | awk '{print $2}' | grep $i | grep -v grep
if [[ $? != 0 ]]
then
ocf_log debug "ASEHAagent: $i process has stopped."
c=0
while (( c < $num_procs ))
do
if [[ ${ENGINE_ALL[$c]} = $i ]]
then
unset ENGINE_ALL[$c]
c=$num_procs
fi
(( c = c + 1 ))
done
fi
done
# To here, all processes should have gone away.
if [[ ${ENGINE_ALL[@]} = "" ]]
then
#
# Looks like shutdown was successful, so kill the
# script to kill any hung processes, which we started earlier.
# Check to see if the script is still running. If jobs
# returns that the script is done, then we don't need to kill
# it.
#
job=$(jobs | grep -v Done)
if [[ ${job} != "" ]]
then
ocf_log debug "ASEHAagent: Killing the kill_ase script."
kill -15 $KILL_PID > /dev/null 2>&1
fi
break
fi
sleep 5
done
ocf_log debug "ASEHAagent: End 'ase_stop'."
return 0
}
####################################################################################
# Function name: ase_is_running #
# Parameter: None #
# Return value: #
# 0 ASE server is running #
# 1 ASE server is not running or there are errors #
# Description: This function is used to check if the ASE server is still running . #
####################################################################################
ase_is_running()
{
# If the error log doesn't exist, we can say there is no ASE is running.
if [[ ! -f $CONSOLE_LOG ]]
then
return 1
fi
# The error log file exists. Check if the engine 0 is alive.
ENGINE_0=(`sed -n -e '/engine 0/s/^.*os pid \([0-9]*\).*online$/\1/p' $CONSOLE_LOG`)
if [[ "$ENGINE_0" = "" ]]
then
# The engine 0 is down.
return 1
else
kill -s 0 $ENGINE_0 > /dev/null 2>&1
if [[ $? != 0 ]]
then
# The engine 0 is not running.
return 1
else
# The engine 0 is running.
return 0
fi
fi
return 1
}
####################################################################################
# Function name: kill_ase #
# Parameter: #
# DELAY The seconds to wait before killing the ASE processes. 0 means #
# kill the ASE processes immediately. #
# Return value: None #
# 1 ASE server is not running or there are errors #
# Description: This function is used to check if the ASE server is still running . #
####################################################################################
kill_ase()
{
ocf_log debug "ASEHAagent: Start 'kill_ase'."
DELAY=$1
# Wait for sometime before sending a kill signal.
t=0
while [[ $t -lt $DELAY ]]
do
sleep 1
t=`expr $t+1`
done
# Get the process ids from log file
declare -a ENGINE_ALL=`sed -n -e '/engine /s/^.*os pid \([0-9]*\).*online$/\1/p' $CONSOLE_LOG`
# If there is no process id found in the log file, we need not to continue.
if [[ "${ENGINE_ALL[@]}" = "" ]]
then
ocf_log err "ASEHAagent: Unable to find the process id from $CONSOLE_LOG."
return
fi
# Kill the datasever process(es)
for pid in ${ENGINE_ALL[@]}
do
kill -9 $pid > /dev/null 2>&1
if [[ $? != 0 ]]
then
ocf_log info "ASEHAagent: kill_ase function did NOT find process $pid running."
else
ocf_log info "ASEHAagent: kill_ase function did find process $pid running. Sent SIGTERM."
fi
done
ocf_log debug "ASEHAagent: End 'kill_ase'."
}
#######################################################################################
# Function name: terminate #
# Parameter: None #
# Return value: Always be 1 #
# Description: This function is called automatically after this script is terminated. #
#######################################################################################
terminate()
{
ocf_log debug "ASEHAagent: This monitor script has been signaled to terminate."
exit 1
}
#####################################################################################
# Function name: ase_status #
# Parameter: #
# 0 Level 0 probe. In this level, we just check if engine 0 is alive #
# 10 Level 10 probe. In this level, we need to probe if the ASE server #
# still has response. #
# Return value: #
# 0 The server is still alive #
# 1 The server is down #
# Description: This function is used to check if the ASE server is still running. #
#####################################################################################
ase_status()
{
ocf_log debug "ASEHAagent: Start 'ase_status'."
# Step 1: Check if the engine 0 is alive
ase_is_running
if [[ $? = 1 ]]
then
# ASE is down. Return fail to rgmanager to trigger the failover process.
ocf_log err "ASEHAagent: ASE server is down."
return 1
fi
# ASE process is still alive.
# Step2: If this is level 10 probe, We need to check if the ASE server still has response.
if [[ $1 -gt 0 ]]
then
ocf_log debug "ASEHAagent: Need to run deep probe."
# Run deep probe
deep_probe
if [[ $? = 1 ]]
then
# Deep probe failed. This means the server has been down.
ocf_log err "ASEHAagent: Deep probe found the ASE server is down."
return 1
fi
fi
ocf_log debug "ASEHAagent: End 'ase_status'."
return 0
}
####################################################################################
# Function name: deep_probe #
# Parameter: None #
# Return value: #
# 0 ASE server is alive #
# 1 ASE server is down #
# Description: This function is used to run deep probe to make sure the ASE server #
# still has response. #
####################################################################################
deep_probe()
{
declare -i rv
ocf_log debug "ASEHAagent: Start 'deep_probe'."
# Declare two temporary files which will be used in this probe.
tmpfile1="$(mktemp /tmp/ASEHAagent.1.XXXXXX)"
tmpfile2="$(mktemp /tmp/ASEHAagent.2.XXXXXX)"
# Get the login_string by analyzing the login_file.
get_login_string
if [[ $? = 1 ]]
then
# Login string cannot be fetched. Cannot continue the deep probe.
ocf_log err "ASEHAagent: Cannot run the deep probe because of incorrect login file $OCF_RESKEY_login_file. Deep probe failed."
return 1
fi
rm -f $tmpfile1
rm -f $tmpfile2
# The login file is correct. We have gotten the login account and password from it.
# Run isql command in background.
su $OCF_RESKEY_sybase_user -c ksh << EOF
# set required SYBASE environment by running SYBASE.sh.
. $OCF_RESKEY_sybase_home/SYBASE.sh
# Run a very simple SQL statement to make sure the server is still ok. The output will be put to
# tmpfile1.
(echo "select 1"; echo "go") |
\$SYBASE/\$SYBASE_OCS/bin/isql $login_string -S$OCF_RESKEY_server_name -I$OCF_RESKEY_interfaces_file -t $OCF_RESKEY_deep_probe_timeout -e -o$tmpfile1 &
# Record the isql command process id to temporary file. If the isql is hung, we need this process id
# to kill the hung process.
echo \$! > $tmpfile2
EOF
declare -i t=0
# Monitor the output file tmpfile1.
while [[ $t -lt $OCF_RESKEY_deep_probe_timeout ]]
do
# If the SQL statement is executed successfully, we will get the following output:
# 1> select 1
#
# -----------
# 1
#
# (1 row affected)
# So, we determine if the execution is success by searching the keyword "(1 row affected)".
grep "(1 row affected)" $tmpfile1
if [[ $? = 0 ]]
then
ocf_log debug "ASEHAagent: Deep probe sucess."
break
else
sleep 1
t=`expr $t+1`
fi
done
# If $t is larger than deep_probe_timeout, it means the isql command line cannot finish in given time.
# This means the deep probe failed. We need to kill the isql process manually.
if [[ $t -ge $OCF_RESKEY_deep_probe_timeout ]]
then
ocf_log err "ASEHAagent: Deep probe fail. The dataserver has no response."
# Read the process id of isql process from tmpfile2
pid=`cat $tmpfile2 | awk '{print $1}'`
rm -f $tmpfile1
rm -f $tmpfile2
# Kill the isql process directly.
kill -9 $pid
return 1
fi
rm -f $tmpfile1
rm -f $tmpfile2
ocf_log debug "ASEHAagent: End 'deep_probe'."
return 0
}
trap terminate SIGTERM
#############################
# Do some real work here... #
#############################
case $1 in
start)
verify_all || exit 1
ase_start
exit $?
;;
stop)
verify_all || exit 1
ase_stop
exit $?
;;
status | monitor)
verify_all || exit 1
ase_status $OCF_CHECK_LEVEL
exit $?
;;
kill)
kill_ase $OCF_RESKEY_shutdown_timeout
;;
meta-data)
meta_data
exit $?
;;
validate-all)
verify_all
exit $?
;;
*)
echo "Usage: $SCRIPT {start|stop|monitor|status|validate-all|meta-data}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit 0
diff --git a/rgmanager/src/resources/apache.sh b/rgmanager/src/resources/apache.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/apache.sh
rename to rgmanager/src/resources/apache.sh.in
index 2230ca8a3..6c021830d
--- a/rgmanager/src/resources/apache.sh
+++ b/rgmanager/src/resources/apache.sh.in
@@ -1,298 +1,298 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
export LC_ALL=C
export LANG=C
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
APACHE_HTTPD=$OCF_RESKEY_httpd
if [ -z "$APACHE_HTTPD" ]; then
if [ -x /usr/sbin/httpd ]; then
declare APACHE_HTTPD=/usr/sbin/httpd
elif [ -x /usr/sbin/apache2 ]; then
declare APACHE_HTTPD=/usr/sbin/apache2
fi
fi
declare APACHE_serverConfigFile
declare APACHE_pid_file="`generate_name_for_pid_file`"
declare APACHE_conf_dir="`generate_name_for_conf_dir`"
declare APACHE_genConfig="$APACHE_conf_dir/httpd.conf"
declare APACHE_parseConfig=$(dirname $0)/utils/httpd-parse-config.pl
apache_serverConfigFile()
{
if $(echo $OCF_RESKEY_config_file | grep -q "^/"); then
APACHE_serverConfigFile="$OCF_RESKEY_config_file"
else
APACHE_serverConfigFile="$OCF_RESKEY_server_root/$OCF_RESKEY_config_file"
fi
return;
}
verify_all()
{
clog_service_verify $CLOG_INIT
if [ -z "$OCF_RESKEY_name" ]; then
clog_service_verify $CLOG_FAILED "Invalid Name Of Service"
return $OCF_ERR_ARGS
fi
if [ -n "$OCF_RESKEY_httpd" ] && ! [ -e $OCF_RESKEY_httpd ]; then
clog_service_verify $CLOG_FAILED "Invalid httpd binary, $OCF_RESKEY_http does not exist"
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_service_name" ]; then
clog_service_verify $CLOG_FAILED_NOT_CHILD
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_server_root" ]; then
clog_service_verify $CLOG_FAILED "Invalid ServerRoot"
return $OCF_ERR_ARGS
fi
if [ ! -d "$OCF_RESKEY_server_root" ]; then
clog_service_verify $CLOG_FAILED "ServerRoot Directory Is Missing"
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_INVALID "$OCF_RESKEY_config_file"
return $OCF_ERR_ARGS
fi
if [ ! -r "$APACHE_serverConfigFile" ]; then
clog_check_file_exist $CLOG_FAILED_NOT_READABLE "$APACHE_serverConfigFile"
return $OCF_ERR_ARGS
fi
if [ -z "$APACHE_pid_file" ]; then
clog_service_verify $CLOG_FAILED "Invalid name of PID file"
return $OCF_ERR_ARGS
fi
clog_check_syntax $CLOG_INIT "$APACHE_serverConfigFile"
"$APACHE_HTTPD" -t \
-D"$OCF_RESKEY_name" \
-d "$OCF_RESKEY_server_root" \
-f "$APACHE_serverConfigFile" \
$OCF_RESKEY_httpd_options &> /dev/null
if [ $? -ne 0 ]; then
clog_check_syntax $CLOG_FAILED "$APACHE_serverConfigFile"
return $OCF_ERR_GENERIC
fi
clog_check_syntax $CLOG_SUCCEED "$APACHE_serverConfigFile"
return 0
}
generate_configFile()
{
declare originalConfigFile=$1;
declare generatedConfigFile=$2;
declare ip_addresses=$3;
if [ -f "$generatedConfigFile" ]; then
sha1_verify "$generatedConfigFile"
if [ $? -ne 0 ]; then
clog_check_sha1 $CLOG_FAILED
return 0
fi
fi
clog_generate_config $CLOG_INIT "$originalConfigFile" "$generatedConfigFile"
generate_configTemplate "$generatedConfigFile" "$1"
cat >> "$generatedConfigFile" << EOT
# From a cluster perspective, the key fields are:
# Listen - must be set to service floating IP address.
# ServerRoot - path to the ServerRoot (initial value is set in service conf)
#
EOT
IFS_old="$IFS"
IFS=$'\n'
for i in `"$APACHE_parseConfig" -D"$OCF_RESKEY_name" < "$originalConfigFile" | grep -P '(^Listen)|(^Port)' `; do
port=`echo $i | sed 's/^Listen \(.*\)/\1/;s/^Port \(.*\)/\1/'`;
testcond=`echo $port|grep :`
if [ $testcond ]; then
port=`echo $port|awk -F : '{print $2}'`
fi
IFS=$' ';
for z in $ip_addresses; do
if [ "${z//:/}" != "$z" ]; then
echo "Listen [$z]:$port" >> "$generatedConfigFile";
else
echo "Listen $z:$port" >> "$generatedConfigFile";
fi
done
IFS=$'\n';
done;
IFS="$IFS_old"
echo "PidFile \"$APACHE_pid_file\"" >> "$generatedConfigFile";
echo >> "$generatedConfigFile"
cat "$originalConfigFile" | sed 's/^Listen/### Listen/;s/^Port/### Port/;s/^PidFile/### PidFile/' | \
"$APACHE_parseConfig" -D"$OCF_RESKEY_name" >> "$generatedConfigFile"
sha1_addToFile "$generatedConfigFile"
clog_generate_config $CLOG_SUCCEED "$originalConfigFile" "$generatedConfigFile"
}
start()
{
if status; then
ocf_log info "Starting Service $OCF_RESOURCE_INSTANCE > Already running"
return $OCF_SUCCESS
fi
declare ip_addresses
clog_service_start $CLOG_INIT
create_pid_directory
create_conf_directory "$APACHE_conf_dir"
check_pid_file "$APACHE_pid_file"
if [ $? -ne 0 ]; then
clog_check_pid $CLOG_FAILED "$APACHE_pid_file"
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_INIT "IP Addresses"
get_service_ip_keys "$OCF_RESKEY_service_name"
ip_addresses=`build_ip_list`
if [ -z "$ip_addresses" ]; then
clog_looking_for $CLOG_FAILED_NOT_FOUND "IP Addresses"
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_SUCCEED "IP Addresses"
generate_configFile "$APACHE_serverConfigFile" "$APACHE_genConfig" "$ip_addresses"
"$APACHE_HTTPD" \
"-D$OCF_RESKEY_name" \
-d "$OCF_RESKEY_server_root" \
-f "$APACHE_genConfig" \
$OCF_RESKEY_httpd_options \
-k start
if [ $? -ne 0 ]; then
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
else
clog_service_start $CLOG_SUCCEED
fi
return 0;
}
stop()
{
clog_service_stop $CLOG_INIT
stop_generic "$APACHE_pid_file" "$OCF_RESKEY_shutdown_wait"
if [ $? -ne 0 ]; then
clog_service_stop $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_service_stop $CLOG_SUCCEED
return 0;
}
status()
{
clog_service_status $CLOG_INIT
status_check_pid "$APACHE_pid_file"
case $? in
$OCF_NOT_RUNNING)
clog_service_status $CLOG_FAILED "$APACHE_pid_file"
return $OCF_NOT_RUNNING
;;
0)
clog_service_status $CLOG_SUCCEED
exit 0
;;
*)
clog_service_status $CLOG_FAILED "$APACHE_pid_file"
return $OCF_ERR_GENERIC
;;
esac
}
if [ "$1" != "meta-data" ]; then
apache_serverConfigFile
fi;
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
exit 0
;;
validate-all|verify-all)
verify_all
exit $?
;;
start)
verify_all && start
exit $?
;;
stop)
verify_all && stop
exit $?
;;
status|monitor)
verify_all
status
exit $?
;;
restart)
verify_all
stop
start
exit $?
;;
*)
echo "Usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/bind-mount.sh b/rgmanager/src/resources/bind-mount.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/bind-mount.sh
rename to rgmanager/src/resources/bind-mount.sh.in
index 077e0a386..db894f8b9
--- a/rgmanager/src/resources/bind-mount.sh
+++ b/rgmanager/src/resources/bind-mount.sh.in
@@ -1,167 +1,167 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright Red Hat Inc., 2014
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to the
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
# MA 02139, USA.
#
#
# Bind mount script - mounts parent file system -o bind in another
# location
#
LC_ALL=C
LANG=C
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LC_ALL LANG PATH
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/fs-lib.sh
export IS_BIND_MOUNT=1
export OCF_RESKEY_use_findmnt=0
export OCF_RESKEY_options="bind"
export OCF_RESKEY_device="$OCF_RESKEY_source"
rv=0
do_metadata()
{
cat <<EOT
<?xml version="1.0" ?>
<resource-agent name="bind-mount" version="rgmanager 2.0">
<version>1.0</version>
<longdesc lang="en">
Defines a bind mount.
</longdesc>
<shortdesc lang="en">
Defines a bind mount.
</shortdesc>
<parameters>
<parameter name="name" primary="1" unique="1">
<longdesc lang="en">
Symbolic name for this bind mount.
</longdesc>
<shortdesc lang="en">
Bind Mount Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="mountpoint" unique="1" required="1">
<longdesc lang="en">
Target of this bind mount
</longdesc>
<shortdesc lang="en">
Target mountpoint
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="source" required="1">
<longdesc lang="en">
Source of the bind mount
</longdesc>
<shortdesc lang="en">
Source of the bind mount
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="force_unmount">
<longdesc lang="en">
If set, the cluster will kill all processes using
this file system when the resource group is
stopped. Otherwise, the unmount will fail, and
the resource group will be restarted.
</longdesc>
<shortdesc lang="en">
Force Unmount
</shortdesc>
<content type="boolean"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="5"/>
<action name="stop" timeout="5"/>
<action name="recover" timeout="5"/>
<action name="status" timeout="5" interval="1h"/>
<action name="monitor" timeout="5" interval="1h"/>
<action name="meta-data" timeout="5"/>
<action name="verify-all" timeout="30"/>
</actions>
<special tag="rgmanager">
<child type="nfsexport" forbid="1"/>
<child type="nfsclient"/>
</special>
</resource-agent>
EOT
}
verify_source()
{
if [ -z "$OCF_RESKEY_source" ]; then
ocf_log err "No source specified."
return $OCF_ERR_ARGS
fi
[ -d "$OCF_RESKEY_source" ] && return 0
ocf_log err "$OCF_RESKEY_source is not a directory"
return $OCF_ERR_ARGS
}
verify_mountpoint()
{
if [ -z "$OCF_RESKEY_mountpoint" ]; then
ocf_log err "No target path specified."
return $OCF_ERR_ARGS
fi
[ -d "$OCF_RESKEY_mountpoint" ] && return 0
mkdir -p $OCF_RESKEY_mountpoint && return 0
ocf_log err "$OCF_RESKEY_mountpoint is not a directory and could not be created"
return $OCF_ERR_ARGS
}
do_validate()
{
declare -i ret=0
verify_source || ret=$OCF_ERR_ARGS
verify_mountpoint || ret=$OCF_ERR_ARGS
return $ret
}
do_pre_mount()
{
do_validate || exit $OCF_ERR_ARGS
}
main $*
diff --git a/rgmanager/src/resources/clusterfs.sh b/rgmanager/src/resources/clusterfs.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/clusterfs.sh
rename to rgmanager/src/resources/clusterfs.sh.in
index ab2c292d5..8f339d426
--- a/rgmanager/src/resources/clusterfs.sh
+++ b/rgmanager/src/resources/clusterfs.sh.in
@@ -1,342 +1,342 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Cluster File System mount/umount/fsck/etc. agent
#
# Copyright (C) 2000 Mission Critical Linux
# Copyright (C) 2002-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
. $(dirname $0)/utils/fs-lib.sh
do_metadata()
{
cat <<EOT
<?xml version="1.0" ?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1-modified.dtd">
<resource-agent name="clusterfs" version="rgmanager 2.0">
<version>1.0</version>
<longdesc lang="en">
This defines a cluster file system mount (i.e. GFS)
</longdesc>
<shortdesc lang="en">
Defines a cluster file system mount.
</shortdesc>
<parameters>
<parameter name="name" primary="1">
<longdesc lang="en">
Symbolic name for this file system.
</longdesc>
<shortdesc lang="en">
File System Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="mountpoint" unique="1" required="1">
<longdesc lang="en">
Path in file system heirarchy to mount this file system.
</longdesc>
<shortdesc lang="en">
Mount Point
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="device" unique="1" required="1">
<longdesc lang="en">
Block device, file system label, or UUID of file system.
</longdesc>
<shortdesc lang="en">
Device or Label
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="fstype">
<longdesc lang="en">
File system type. If not specified, mount(8) will attempt to
determine the file system type.
</longdesc>
<shortdesc lang="en">
File system type
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="force_unmount">
<longdesc lang="en">
If set, the cluster will kill all processes using
this file system when the resource group is
stopped. Otherwise, the unmount will fail, and
the resource group will be restarted.
</longdesc>
<shortdesc lang="en">
Force Unmount
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="self_fence">
<longdesc lang="en">
If set and unmounting the file system fails, the node will
immediately reboot. Generally, this is used in conjunction
with force_unmount support, but it is not required.
</longdesc>
<shortdesc lang="en">
Seppuku Unmount
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="fsid">
<longdesc lang="en">
File system ID for NFS exports. This can be overridden
in individual nfsclient entries.
</longdesc>
<shortdesc lang="en">
NFS File system ID
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="nfslock" inherit="service%nfslock">
<longdesc lang="en">
If set, the node will try to kill lockd and issue
reclaims across all remaining network interface cards.
This happens always, regardless of unmounting failed.
</longdesc>
<shortdesc lang="en">
Enable NFS lock workarounds
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="nfsrestart">
<longdesc lang="en">
If set and unmounting the file system fails, the node will
try to restart nfs daemon and nfs lockd to drop all filesystem
references. Use this option as last resource.
This option requires force_unmount to be set and it is not
compatible with nfsserver resource.
</longdesc>
<shortdesc lang="en">
Enable NFS daemon and lockd workaround
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="options">
<longdesc lang="en">
Options used when the file system is mounted. These
are often file-system specific. See mount(8) and/or
mount.gfs2(8) for supported mount options.
</longdesc>
<shortdesc lang="en">
Mount Options
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="use_findmnt">
<longdesc lang="en">
Use findmnt to determine if and where a filesystem is mounted.
Disabling this uses the failback method (should be used if autofs
maps are located on network storage (ie. nfs, iscsi, etc).
</longdesc>
<shortdesc lang="en">
Utilize findmnt to detect if and where filesystems are mounted
</shortdesc>
<content type="boolean"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="900"/>
<action name="stop" timeout="30"/>
<!-- Recovery isn't possible; we don't know if resources are using
the file system. -->
<!-- Checks to see if it's mounted in the right place -->
<action name="status" interval="1m" timeout="10"/>
<action name="monitor" interval="1m" timeout="10"/>
<!-- Checks to see if we can read from the mountpoint -->
<action name="status" depth="10" timeout="30" interval="5m"/>
<action name="monitor" depth="10" timeout="30" interval="5m"/>
<!-- Checks to see if we can write to the mountpoint (if !ROFS) -->
<action name="status" depth="20" timeout="30" interval="10m"/>
<action name="monitor" depth="20" timeout="30" interval="10m"/>
<action name="meta-data" timeout="5"/>
<action name="validate-all" timeout="5"/>
</actions>
<special tag="rgmanager">
<child type="fs" start="1" stop="3"/>
<child type="clusterfs" start="1" stop="3"/>
<child type="nfsexport" start="3" stop="1"/>
</special>
</resource-agent>
EOT
}
verify_fstype()
{
# Auto detect?
[ -z "$OCF_RESKEY_fstype" ] && return $OCF_SUCCESS
case $OCF_RESKEY_fstype in
gfs|gfs2)
return $OCF_SUCCESS
;;
*)
ocf_log err "File system type $OCF_RESKEY_fstype not supported"
return $OCF_ERR_ARGS
;;
esac
}
verify_options()
{
declare -i ret=$OCF_SUCCESS
#
# From mount(8)
#
for o in `echo $OCF_RESKEY_options | sed -e s/,/\ /g`; do
case $o in
async|atime|auto|defaults|dev|exec|_netdev|noatime)
continue
;;
noauto|nodev|noexec|nosuid|nouser|ro|rw|suid|sync)
continue
;;
dirsync|user|users)
continue
;;
esac
case $OCF_RESKEY_fstype in
gfs)
case $o in
lockproto=*|locktable=*|hostdata=*)
continue;
;;
localcaching|localflocks|ignore_local_fs)
continue;
;;
num_glockd|acl|suiddir)
continue
;;
esac
;;
gfs2)
# XXX
continue
;;
esac
ocf_log err "Option $o not supported for $OCF_RESKEY_fstype"
ret=$OCF_ERR_ARGS
done
return $ret
}
do_verify()
{
verify_name || return $OCF_ERR_ARGS
verify_fstype || return $OCF_ERR_ARGS
verify_device || return $OCF_ERR_ARGS
verify_mountpoint || return $OCF_ERR_ARGS
verify_options || return $OCF_ERR_ARGS
}
do_pre_unmount() {
#
# Check the rgmanager-supplied reference count if one exists.
# If the reference count is <= 1, we can safely proceed
#
if [ -n "$OCF_RESKEY_RGMANAGER_meta_refcnt" ]; then
refs=$OCF_RESKEY_RGMANAGER_meta_refcnt
if [ $refs -gt 0 ]; then
ocf_log debug "Not unmounting $OCF_RESOURCE_INSTANCE - still in use by $refs other service(s)"
return 2
fi
fi
if [ -z "$force_umount" ]; then
ocf_log debug "Not umounting $dev (clustered file system)"
return 2
fi
#
# Always do this hackery on clustered file systems.
#
if [ "$OCF_RESKEY_nfslock" = "yes" ] || \
[ "$OCF_RESKEY_nfslock" = "1" ]; then
ocf_log warning "Dropping node-wide NFS locks"
mkdir -p $mp/.clumanager/statd
chown rpcuser.rpcuser $mp/.clumanager/statd
pkill -KILL -x lockd
# Copy out the notify list; our
# IPs are already torn down
if notify_list_store $mp/.clumanager/statd; then
notify_list_broadcast $mp/.clumanager/statd
fi
fi
# Always invalidate buffers on clusterfs resources
clubufflush -f $dev
return 0
}
do_force_unmount() {
if [ "$OCF_RESKEY_nfsrestart" = "yes" ] || \
[ "$OCF_RESKEY_nfsrestart" = "1" ]; then
ocf_log warning "Restarting nfsd/nfslock"
nfsexports=$(cat /var/lib/nfs/etab)
service nfslock stop
service nfs stop
service nfs start
service nfslock start
echo "$nfsexports" | { while read line; do
nfsexp=$(echo $line | awk '{print $1}')
nfsopts=$(echo $line | sed -e 's#.*(##g' -e 's#).*##g')
nfsacl=$(echo $line | awk '{print $2}' | sed -e 's#(.*##g')
if [ -n "$nfsopts" ]; then
exportfs -i -o "$nfsopts" "$nfsacl":$nfsexp
else
exportfs -i "$nfsacl":$nfsexp
fi
done; }
fi
return 1
}
main $*
diff --git a/rgmanager/src/resources/db2.sh b/rgmanager/src/resources/db2.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/db2.sh
rename to rgmanager/src/resources/db2.sh.in
index 57991f926..cfedf1b2e
--- a/rgmanager/src/resources/db2.sh
+++ b/rgmanager/src/resources/db2.sh.in
@@ -1,133 +1,133 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (c) 2011 Holger Teutsch <holger.teutsch@web.de>
# Copyright (c) 2014 David Vossel <davidvossel@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# NOTE:
#
# This agent is a wrapper around the heartbeat/db2 agent which limits the heartbeat
# db2 agent to Standard role support. This allows cluster managers such as rgmanager
# which do not have multi-state resource support to manage db2 instances with
# a limited feature set.
#
export LC_ALL=C
export LANG=C
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
. $(dirname $0)/ocf-shellfuncs
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="db2.sh">
<version>1.0</version>
<longdesc lang="en">
Resource Agent that manages an IBM DB2 LUW databases in Standard role. Multiple partitions are supported.
When partitions are in use, each partition must be configured as a separate primitive resource.
</longdesc>
<shortdesc lang="en">Resource Agent that manages an IBM DB2 LUW databases in Standard role with multiple partition support.</shortdesc>
<parameters>
<parameter name="instance" unique="1" required="1">
<longdesc lang="en">
The instance of the database(s).
</longdesc>
<shortdesc lang="en">instance</shortdesc>
<content type="string" default="" />
</parameter>
<parameter name="dblist" unique="0" required="0">
<longdesc lang="en">
List of databases to be managed, e.g "db1 db2".
Defaults to all databases in the instance.
</longdesc>
<shortdesc lang="en">List of databases to be managed</shortdesc>
<content type="string"/>
</parameter>
<parameter name="dbpartitionnum" unique="0" required="0">
<longdesc lang="en">
The number of the partion (DBPARTITIONNUM) to be managed.
</longdesc>
<shortdesc lang="en">database partition number (DBPARTITIONNUM)</shortdesc>
<content type="string" default="0" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="120"/>
<action name="stop" timeout="120"/>
<action name="monitor" depth="0" timeout="60" interval="20"/>
<action name="monitor" depth="0" timeout="60" role="Master" interval="22"/>
<action name="validate-all" timeout="5"/>
<action name="meta-data" timeout="5"/>
</actions>
</resource-agent>
END
}
heartbeat_db2_wrapper()
{
# default heartbeat agent ocf root.
export OCF_ROOT=/usr/lib/ocf
heartbeat_db2="${OCF_ROOT}/resource.d/heartbeat/db2"
if ! [ -a $heartbeat_db2 ]; then
echo "heartbeat db2 agent not found at '${heartbeat_db2}'"
exit $OCF_ERR_INSTALLED
fi
$heartbeat_db2 $1
}
case $1 in
meta-data)
meta_data
exit 0
;;
validate-all)
heartbeat_db2_wrapper $1
exit $?
;;
start)
heartbeat_db2_wrapper $1
exit $?
;;
stop)
heartbeat_db2_wrapper $1
exit $?
;;
status|monitor)
heartbeat_db2_wrapper "monitor"
exit $?
;;
restart)
heartbeat_db2_wrapper "stop"
rc=$?
if [ $rc -ne 0 ]; then
exit $rc
fi
heartbeat_db2_wrapper "start"
exit $?
;;
*)
echo "Usage: db2.sh {start|stop|monitor|validate-all|meta-data}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/drbd.sh b/rgmanager/src/resources/drbd.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/drbd.sh
rename to rgmanager/src/resources/drbd.sh.in
index 51f88f769..febe658ac
--- a/rgmanager/src/resources/drbd.sh
+++ b/rgmanager/src/resources/drbd.sh.in
@@ -1,144 +1,144 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright LINBIT, 2008
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to the
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
# MA 02139, USA.
#
#
# DRBD resource management using the drbdadm utility.
#
LC_ALL=C
LANG=C
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LC_ALL LANG PATH
. $(dirname $0)/ocf-shellfuncs
drbd_verify_all()
{
# Do we have the drbdadm utility?
if ! which drbdadm >/dev/null 2>&1 ; then
ocf_log error "drbdadm not installed, not found in PATH ($PATH), or not executable."
return $OCF_ERR_INSTALLED
fi
# Is drbd loaded?
if ! grep drbd /proc/modules >/dev/null 2>&1; then
ocf_log error "drbd not found in /proc/modules. Do you need to modprobe?"
return $OCF_ERR_INSTALLED
fi
# Do we have the "resource" parameter?
if [ -n "$OCF_RESKEY_resource" ]; then
# Can drbdadm parse the resource name?
if ! drbdadm sh-dev $OCF_RESKEY_resource >/dev/null 2>&1; then
ocf_log error "DRBD resource \"$OCF_RESKEY_resource\" not found."
return $OCF_ERR_CONFIGURED
fi
# Is the backing device a locally available block device?
backing_dev=$(drbdadm sh-ll-dev $OCF_RESKEY_resource)
if [ ! -b $backing_dev ]; then
ocf_log error "Backing device for DRBD resource \"$OCF_RESKEY_resource\" ($backing_dev) not found or not a block device."
return $OCF_ERR_INSTALLED
fi
fi
return 0
}
drbd_status() {
role=$(drbdadm role $OCF_RESKEY_resource)
case $role in
Primary/*)
return $OCF_SUCCESS
;;
Secondary/*)
return $OCF_NOT_RUNNING
;;
esac
return $OCF_ERR_GENERIC
}
drbd_promote() {
drbdadm primary $OCF_RESKEY_resource || return $?
}
drbd_demote() {
drbdadm secondary $OCF_RESKEY_resource || return $?
}
if [ -z "$OCF_CHECK_LEVEL" ]; then
OCF_CHECK_LEVEL=0
fi
# This one doesn't need to pass the verify check
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'` && exit 0
exit $OCF_ERR_GENERIC
;;
esac
# Everything else does
drbd_verify_all || exit $?
case $1 in
start)
if drbd_status; then
ocf_log debug "DRBD resource ${OCF_RESKEY_resource} already configured"
exit 0
fi
drbd_promote
if [ $? -ne 0 ]; then
exit $OCF_ERR_GENERIC
fi
exit $?
;;
stop)
if drbd_status; then
drbd_demote
if [ $? -ne 0 ]; then
exit $OCF_ERR_GENERIC
fi
else
ocf_log debug "DRBD resource ${OCF_RESKEY_resource} is not configured"
fi
exit 0
;;
status|monitor)
drbd_status
exit $?
;;
restart)
$0 stop || exit $OCF_ERR_GENERIC
$0 start || exit $OCF_ERR_GENERIC
exit 0
;;
verify-all)
exit 0
;;
*)
echo "usage: $0 {start|stop|status|monitor|restart|meta-data|verify-all}"
exit $OCF_ERR_GENERIC
;;
esac
diff --git a/rgmanager/src/resources/fs.sh.in b/rgmanager/src/resources/fs.sh.in
index 6d99f9561..fb43dabe5 100644
--- a/rgmanager/src/resources/fs.sh.in
+++ b/rgmanager/src/resources/fs.sh.in
@@ -1,504 +1,504 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# File system (normal) mount/umount/fsck/etc. agent
#
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
. $(dirname $0)/utils/fs-lib.sh
do_metadata()
{
cat <<EOT
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1-modified.dtd">
<resource-agent name="fs" version="rgmanager 2.0">
<version>1.0</version>
<longdesc lang="en">
This defines a standard file system mount (= not a clustered
or otherwise shared file system).
</longdesc>
<shortdesc lang="en">
Defines a file system mount.
</shortdesc>
<parameters>
<parameter name="name" primary="1">
<longdesc lang="en">
Symbolic name for this file system.
</longdesc>
<shortdesc lang="en">
File System Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="mountpoint" unique="1" required="1">
<longdesc lang="en">
Path in file system heirarchy to mount this file system.
</longdesc>
<shortdesc lang="en">
Mount Point
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="device" unique="1" required="1">
<longdesc lang="en">
Block device, file system label, or UUID of file system.
</longdesc>
<shortdesc lang="en">
Device or Label
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="fstype">
<longdesc lang="en">
File system type. If not specified, mount(8) will attempt to
determine the file system type.
</longdesc>
<shortdesc lang="en">
File system type
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="force_unmount">
<longdesc lang="en">
If set, the cluster will kill all processes using
this file system when the resource group is
stopped. Otherwise, the unmount will fail, and
the resource group will be restarted.
</longdesc>
<shortdesc lang="en">
Force Unmount
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="quick_status">
<longdesc lang="en">
Use quick status checks. When set to 0 (the default), this
agent behaves normally. When set to 1, this agent will not
log errors incurred or perform the file system accessibility
check (e.g. it will not try to read from/write to the file
system). You should only set this to 1 if you have lots of
file systems on your cluster or you are seeing very high load
spikes as a direct result of this agent.
</longdesc>
<shortdesc lang="en">
Quick/brief status checks.
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="self_fence">
<longdesc lang="en">
If set and unmounting the file system fails, the node will
immediately reboot. Generally, this is used in conjunction
with force_unmount support, but it is not required.
</longdesc>
<shortdesc lang="en">
Seppuku Unmount
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="nfslock" inherit="nfslock">
<longdesc lang="en">
If set and unmounting the file system fails, the node will
try to kill lockd and issue reclaims across all remaining
network interface cards.
</longdesc>
<shortdesc lang="en">
Enable NFS lock workarounds
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="nfsrestart">
<longdesc lang="en">
If set and unmounting the file system fails, the node will
try to restart nfs daemon and nfs lockd to drop all filesystem
references. Use this option as last resource.
This option requires force_unmount to be set and it is not
compatible with nfsserver resource.
</longdesc>
<shortdesc lang="en">
Enable NFS daemon and lockd workaround
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="fsid">
<longdesc lang="en">
File system ID for NFS exports. This can be overridden
in individual nfsclient entries.
</longdesc>
<shortdesc lang="en">
NFS File system ID
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="force_fsck">
<longdesc lang="en">
If set, the file system will be checked (even if
it is a journalled file system). This option is
ignored for non-journalled file systems such as
ext2.
</longdesc>
<shortdesc lang="en">
Force fsck support
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="options">
<longdesc lang="en">
Options used when the file system is mounted. These
are often file-system specific. See mount(8) for supported
mount options.
</longdesc>
<shortdesc lang="en">
Mount Options
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="use_findmnt">
<longdesc lang="en">
Use findmnt to determine if and where a filesystem is mounted.
Disabling this uses the failback method (should be used if autofs
maps are located on network storage (ie. nfs, iscsi, etc).
</longdesc>
<shortdesc lang="en">
Utilize findmnt to detect if and where filesystems are mounted
</shortdesc>
<content type="boolean"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="900"/>
<action name="stop" timeout="30"/>
<!-- Recovery isn't possible; we don't know if resources are using
the file system. -->
<!-- Checks to see if it's mounted in the right place -->
<action name="status" interval="1m" timeout="10"/>
<action name="monitor" interval="1m" timeout="10"/>
<!-- Note: active monitoring is constant and supplants all
check depths -->
<!-- Checks to see if we can read from the mountpoint -->
<action name="status" depth="10" timeout="30" interval="30"/>
<action name="monitor" depth="10" timeout="30" interval="30"/>
<!-- Checks to see if we can write to the mountpoint (if !ROFS) -->
<action name="status" depth="20" timeout="30" interval="1m"/>
<action name="monitor" depth="20" timeout="30" interval="1m"/>
<action name="meta-data" timeout="5"/>
<action name="validate-all" timeout="5"/>
</actions>
<special tag="rgmanager">
<attributes maxinstances="1"/>
<child type="fs" start="1" stop="3"/>
<child type="clusterfs" start="1" stop="3"/>
<child type="nfsexport" start="3" stop="1"/>
</special>
</resource-agent>
EOT
}
verify_fstype()
{
# Auto detect?
[ -z "$OCF_RESKEY_fstype" ] && return 0
case $OCF_RESKEY_fstype in
ext2|ext3|ext4|btrfs|jfs|xfs|reiserfs|vfat|vxfs)
return 0
;;
*)
echo "File system type $OCF_RESKEY_fstype not supported"
return $OCF_ERR_ARGS
;;
esac
}
verify_options()
{
declare -i ret=$OCF_SUCCESS
declare o
#
# From mount(8)
#
for o in `echo $OCF_RESKEY_options | sed -e s/,/\ /g`; do
case $o in
async|atime|auto|defaults|dev|exec|_netdev|noatime)
continue
;;
noauto|nodev|noexec|nosuid|nouser|ro|rw|suid|sync)
continue
;;
dirsync|user|users)
continue
;;
esac
do_verify_option $OCF_RESKEY_fstype "$o"
case $OCF_RESKEY_fstype in
ext2|ext3|ext4)
case $o in
bsddf|minixdf|check|check=*|nocheck|debug)
continue
;;
errors=*|grpid|bsdgroups|nogrpid|sysvgroups)
continue
;;
resgid=*|resuid=*|sb=*|grpquota|noquota)
continue
;;
quota|usrquota|nouid32)
continue
;;
esac
if [ "$OCF_RESKEY_fstype" = "ext3" ] ||
[ "$OCF_RESKEY_fstype" = "ext4" ]; then
case $o in
noload|data=*)
continue
;;
esac
fi
;;
vfat)
case $o in
blocksize=512|blocksize=1024|blocksize=2048)
continue
;;
uid=*|gid=*|umask=*|dmask=*|fmask=*)
continue
;;
check=r*|check=n*|check=s*|codepage=*)
continue
;;
conv=b*|conv=t*|conv=a*|cvf_format=*)
continue
;;
cvf_option=*|debug|fat=12|fat=16|fat=32)
continue
;;
iocharset=*|quiet)
continue
;;
esac
;;
jfs)
case $o in
conv|hash=rupasov|hash=tea|hash=r5|hash=detect)
continue
;;
hashed_relocation|no_unhashed_relocation)
continue
;;
noborder|nolog|notail|resize=*)
continue
;;
esac
;;
xfs)
case $o in
biosize=*|dmapi|xdsm|logbufs=*|logbsize=*)
continue
;;
logdev=*|rtdev=*|noalign|noatime)
continue
;;
norecovery|osyncisdsync|quota|userquota)
continue
;;
uqnoenforce|grpquota|gqnoenforce)
continue
;;
sunit=*|swidth=*)
continue
;;
esac
;;
btrfs)
# tbd
continue
;;
esac
echo Option $o not supported for $OCF_RESKEY_fstype
ret=$OCF_ERR_ARGS
done
return $ret
}
do_validate()
{
verify_name || return $OCF_ERR_ARGS
verify_fstype || return $OCF_ERR_ARGS
verify_device || return $OCF_ERR_ARGS
verify_mountpoint || return $OCF_ERR_ARGS
verify_options || return $OCF_ERR_ARGS
}
do_pre_mount()
{
declare fstype="$OCF_RESKEY_fstype"
#
# Check to determine if we need to fsck the filesystem.
#
# Note: this code should not indicate in any manner suggested
# file systems to use in the cluster. Known filesystems are
# listed here for correct operation.
#
case "$fstype" in
reiserfs) typeset fsck_needed="" ;;
ext3) typeset fsck_needed="" ;;
ext4) typeset fsck_needed="" ;;
btrfs) typeset fsck_needed="" ;;
jfs) typeset fsck_needed="" ;;
xfs) typeset fsck_needed="" ;;
vxfs) typeset fsck_needed="" ;;
ext2) typeset fsck_needed=yes ;;
minix) typeset fsck_needed=yes ;;
vfat) typeset fsck_needed=yes ;;
msdos) typeset fsck_needed=yes ;;
"") typeset fsck_needed=yes ;; # assume fsck
*)
typeset fsck_needed=yes # assume fsck
ocf_log warn "\
Unknown file system type '$fstype' for device $dev. Assuming fsck is required."
;;
esac
#
# Fsck the device, if needed.
#
if [ -n "$fsck_needed" ] || [ "${OCF_RESKEY_force_fsck}" = "yes" ] ||\
[ "${OCF_RESKEY_force_fsck}" = "1" ]; then
typeset fsck_log=@LOGDIR@/$(basename $dev).fsck.log
ocf_log debug "Running fsck on $dev"
fsck -p $dev >> $fsck_log 2>&1
ret_val=$?
if [ $ret_val -gt 1 ]; then
ocf_log err "\
'fsck -p $dev' failed, error=$ret_val; check $fsck_log for errors"
ocf_log debug "Invalidating buffers for $dev"
$INVALIDATEBUFFERS -f $dev
return $OCF_ERR_GENERIC
fi
rm -f $fsck_log
fi
return 0
}
do_post_mount() {
#
# Create this for the NFS NLM broadcast bit
#
if [ $NFS_TRICKS -eq 0 ]; then
if [ "$OCF_RESKEY_nfslock" = "yes" ] || \
[ "$OCF_RESKEY_nfslock" = "1" ]; then
mkdir -p "$mp"/.clumanager/statd
chown rpcuser.rpcuser "$mp"/.clumanager/statd
notify_list_merge "$mp"/.clumanager/statd
fi
fi
return 0
}
do_force_unmount() {
if [ "$OCF_RESKEY_nfslock" = "yes" ] || \
[ "$OCF_RESKEY_nfslock" = "1" ]; then
ocf_log warning "Dropping node-wide NFS locks"
pkill -KILL -x lockd
mkdir -p "$mp"/.clumanager/statd
chown rpcuser.rpcuser "$mp"/.clumanager/statd
# Copy out the notify list; our
# IPs are already torn down
notify_list_store "$mp"/.clumanager/statd
# Save for post-umount phase
export nfslock_reclaim=1
fi
if [ "$OCF_RESKEY_nfsrestart" = "yes" ] || \
[ "$OCF_RESKEY_nfsrestart" = "1" ]; then
ocf_log warning "Restarting nfsd/nfslock"
nfsexports=$(cat /var/lib/nfs/etab)
service nfslock stop
service nfs stop
service nfs start
service nfslock start
echo "$nfsexports" | { while read line; do
nfsexp=$(echo $line | awk '{print $1}')
nfsopts=$(echo $line | sed -e 's#.*(##g' -e 's#).*##g')
nfsacl=$(echo $line | awk '{print $2}' | sed -e 's#(.*##g')
if [ -n "$nfsopts" ]; then
exportfs -i -o "$nfsopts" "$nfsacl":$nfsexp
else
exportfs -i "$nfsacl":$nfsexp
fi
done; }
fi
# Proceed with fuser -kvm...
return 1
}
do_post_unmount() {
if [ "$nfslock_reclaim" = "1" ]; then
# If we have this flag set, do a full reclaim broadcast
notify_list_broadcast "$mp"/.clumanager/statd
fi
return 0
}
main $*
diff --git a/rgmanager/src/resources/ip.sh b/rgmanager/src/resources/ip.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/ip.sh
rename to rgmanager/src/resources/ip.sh.in
index 6391fabc5..750708ff0
--- a/rgmanager/src/resources/ip.sh
+++ b/rgmanager/src/resources/ip.sh.in
@@ -1,1052 +1,1052 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# IPv4/IPv6 address management using iproute2 (formerly: ifcfg, ifconfig).
#
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
LC_ALL=C
LANG=C
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LC_ALL LANG PATH
SENDUA=/usr/libexec/heartbeat/send_ua
# Grab nfs lock tricks if available
export NFS_TRICKS=1
if [ -f "$(dirname $0)/svclib_nfslock" ]; then
. $(dirname $0)/svclib_nfslock
NFS_TRICKS=0
fi
. $(dirname $0)/ocf-shellfuncs
meta_data()
{
cat <<EOT
<?xml version="1.0" ?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1-modified.dtd">
<resource-agent version="rgmanager 2.0" name="ip">
<version>1.0</version>
<longdesc lang="en">
This is an IP address. Both IPv4 and IPv6 addresses are supported,
as well as NIC link monitoring for each IP address.
</longdesc>
<shortdesc lang="en">
This is an IP address.
</shortdesc>
<parameters>
<parameter name="address" unique="1" primary="1">
<longdesc lang="en">
IPv4 or IPv6 address to use as a virtual IP
resource. It may be followed by a slash and a decimal
number that encodes the network prefix length.
</longdesc>
<shortdesc lang="en">
IP Address
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="family">
<longdesc lang="en">
IPv4 or IPv6 address protocol family.
</longdesc>
<shortdesc lang="en">
Family
</shortdesc>
<!--
<val>auto</val>
<val>inet</val>
<val>inet6</val>
-->
<content type="string"/>
</parameter>
<parameter name="monitor_link">
<longdesc lang="en">
Enabling this causes the status check to fail if
the link on the NIC to which this IP address is
bound is not present.
</longdesc>
<shortdesc lang="en">
Monitor NIC Link
</shortdesc>
<content type="boolean" default="1"/>
</parameter>
<parameter name="nfslock" inherit="service%nfslock">
<longdesc lang="en">
If set and unmounting the file system fails, the node will
try to kill lockd and issue reclaims across all remaining
network interface cards.
</longdesc>
<shortdesc lang="en">
Enable NFS lock workarounds
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="sleeptime">
<longdesc lang="en">
Amount of time to sleep after removing an IP address.
Value is specified in seconds. Default value is 10.
</longdesc>
<shortdesc lang="en">
Amount of time (seconds) to sleep.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="disable_rdisc">
<longdesc lang="en">
Disable updating of routing using RDISC protocol and
preserve static routes.
</longdesc>
<shortdesc lang="en">
Disable updating of routing using RDISC protocol
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="prefer_interface">
<longdesc lang="en">
The network interface to which the IP address should be added. The interface must already be configured and active. This parameter should be used only when at least two active interfaces have IP addresses on the same subnet and it is desired to have the IP address added to a particular interface.
</longdesc>
<shortdesc lang="en">
Network interface
</shortdesc>
<content type="string"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="20"/>
<action name="stop" timeout="20"/>
<!-- No recover action. If the IP address is not useable, then
resources may or may not depend on it. If it's been
deconfigured, resources using it are in a bad state. -->
<!-- Checks to see if the IP is up and (optionally) the link is
working -->
<action name="status" interval="20" timeout="10"/>
<action name="monitor" interval="20" timeout="10"/>
<!-- Checks to see if we can ping the IP address locally -->
<action name="status" depth="10" interval="60" timeout="20"/>
<action name="monitor" depth="10" interval="60" timeout="20"/>
<action name="meta-data" timeout="20"/>
<action name="validate-all" timeout="20"/>
</actions>
<special tag="rgmanager">
<attributes maxinstances="1"/>
<child type="nfsclient" forbid="1"/>
<child type="nfsexport" forbid="1"/>
</special>
</resource-agent>
EOT
}
verify_address()
{
# XXX TBD
return 0
}
verify_all()
{
# XXX TBD
return 0
}
#
# Expand an IPv6 address.
#
ipv6_expand()
{
typeset addr=$1
typeset maskbits
typeset -i x
typeset tempaddr
maskbits=${addr/*\//}
if [ "$maskbits" = "$addr" ]; then
maskbits=""
else
# chop off mask bits
addr=${addr/\/*/}
fi
# grab each hex quad and expand it to 4 digits if it isn't already
# leave doublecolon in place for expansion out to the proper number of zeros later
tempaddr=""
for count in `seq 1 8`; do
quad=`echo $addr|awk -v count=$count -F : '{print $count}'`
quadlen=${#quad}
if [ $quadlen -eq 0 ]; then
quad=::
elif [ $quadlen -eq 1 ]; then
quad=000$quad
elif [ $quadlen -eq 2 ]; then
quad=00$quad
elif [ $quadlen -eq 3 ]; then
quad=0$quad
fi
tempaddr=$tempaddr$quad
done
addr=$tempaddr
# use space as placeholder
addr=${addr/::/\ }
# get rid of colons
addr=${addr//:/}
# add in zeroes where the doublecolon was
len=$((${#addr}-1))
zeroes=
while [ $len -lt 32 ]; do
zeroes="0$zeroes"
((len++))
done
addr=${addr/\ /$zeroes}
# probably a better way to do this
for (( x=0; x < ${#addr} ; x++)); do
naddr=$naddr${addr:x:1}
if (( x < (${#addr} - 1) && x%4 == 3)); then
naddr=$naddr:
fi
done
if [ -n "$maskbits" ]; then
echo "$naddr/$maskbits"
return 0
fi
echo "$naddr"
return 0
}
#
# see if two ipv6 addrs are in the same subnet
#
ipv6_same_subnet()
{
declare addrl=$1
declare addrr=$2
declare m=$3
declare r x llsb rlsb
if [ $# -lt 2 ]; then
ocf_log err "usage: ipv6_same_subnet addr1 addr2 [mask]"
return 255
fi
if [ -z "$m" ]; then
m=${addrl/*\//}
[ -n "$m" ] || return 1
fi
if [ "${addrr}" != "${addrr/*\//}" ] &&
[ "$m" != "${addrr/*\//}" ]; then
return 1
fi
addrl=${addrl/\/*/}
if [ ${#addrl} -lt 39 ]; then
addrl=$(ipv6_expand $addrl)
fi
addrr=${addrr/\/*/}
if [ ${#addrr} -lt 39 ]; then
addrr=$(ipv6_expand $addrr)
fi
# Calculate the amount to compare directly
x=$(($m/4+$m/16-(($m%4)==0)))
# and the remaining number of bits
r=$(($m%4))
if [ $r -ne 0 ]; then
# If we have any remaining bits, we will need to compare
# them later. Get them now.
llsb=`printf "%d" 0x${addrl:$x:1}`
rlsb=`printf "%d" 0x${addrr:$x:1}`
# One less byte to compare directly, please
((--x))
fi
# direct (string comparison) to see if they are equal
if [ "${addrl:0:$x}" != "${addrr:0:$x}" ]; then
return 1
fi
case $r in
0)
return 0
;;
1)
[ $(($llsb & 8)) -eq $(($rlsb & 8)) ]
return $?
;;
2)
[ $(($llsb & 12)) -eq $(($rlsb & 12)) ]
return $?
;;
3)
[ $(($llsb & 14)) -eq $(($rlsb & 14)) ]
return $?
;;
esac
return 1
}
ipv4_same_subnet()
{
declare addrl=$1
declare addrr=$2
declare m=$3
declare r x llsb rlsb
if [ $# -lt 2 ]; then
ocf_log err "usage: ipv4_same_subnet current_addr new_addr [maskbits]"
return 255
fi
#
# Chop the netmask off of the ipaddr:
# e.g. 1.2.3.4/22 -> 22
#
if [ -z "$m" ]; then
m=${addrl/*\//}
[ -n "$m" ] || return 1
fi
#
# Check to see if there was a subnet mask provided on the
# new IP address. If there was one and it does not match
# our expected subnet mask, we are done.
#
if [ "${addrr}" != "${addrr/\/*/}" ] &&
[ "$m" != "${addrr/*\//}" ]; then
return 1
fi
#
# Chop off subnet bits for good.
#
addrl=${addrl/\/*/}
addrr=${addrr/\/*/}
#
# Remove '.' characters from dotted decimal notation and save
# in arrays. i.e.
#
# 192.168.1.163 -> array[0] = 192
# array[1] = 168
# array[2] = 1
# array[3] = 163
#
let x=0
for quad in ${addrl//./\ }; do
ip1[((x++))]=$quad
done
x=0
for quad in ${addrr//./\ }; do
ip2[((x++))]=$quad
done
x=0
while [ $m -ge 8 ]; do
((m-=8))
if [ ${ip1[x]} -ne ${ip2[x]} ]; then
return 1
fi
((x++))
done
case $m in
0)
return 0
;;
1)
[ $((${ip1[x]} & 128)) -eq $((${ip2[x]} & 128)) ]
return $?
;;
2)
[ $((${ip1[x]} & 192)) -eq $((${ip2[x]} & 192)) ]
return $?
;;
3)
[ $((${ip1[x]} & 224)) -eq $((${ip2[x]} & 224)) ]
return $?
;;
4)
[ $((${ip1[x]} & 240)) -eq $((${ip2[x]} & 240)) ]
return $?
;;
5)
[ $((${ip1[x]} & 248)) -eq $((${ip2[x]} & 248)) ]
return $?
;;
6)
[ $((${ip1[x]} & 252)) -eq $((${ip2[x]} & 252)) ]
return $?
;;
7)
[ $((${ip1[x]} & 254)) -eq $((${ip2[x]} & 254)) ]
return $?
;;
esac
return 1
}
ipv6_list_interfaces()
{
declare idx dev ifaddr
declare ifaddr_exp
while read idx dev ifaddr; do
isSlave $dev
if [ $? -ne 2 ]; then
continue
fi
idx=${idx/:/}
ifaddr_exp=$(ipv6_expand $ifaddr)
echo $dev ${ifaddr_exp/\/*/} ${ifaddr_exp/*\//}
done < <(/sbin/ip -o -f inet6 addr | awk '{print $1,$2,$4}')
return 0
}
isSlave()
{
declare intf=$1
declare line
if [ -z "$intf" ]; then
ocf_log err "usage: isSlave <I/F>"
return $OCF_ERR_ARGS
fi
line=$(/sbin/ip link list dev $intf)
if [ $? -ne 0 ]; then
ocf_log err "$intf not found"
return $OCF_ERR_GENERIC
fi
if [ "$line" = "${line/<*SLAVE*>/}" ]; then
return 2
fi
# Yes, it is a slave device. Ignore.
return 0
}
#
# Check if interface is in UP state
#
interface_up()
{
declare intf=$1
if [ -z "$intf" ]; then
ocf_log err "usage: interface_up <I/F>"
return 1
fi
line=$(/sbin/ip -o link show up dev $intf 2> /dev/null)
[ -z "$line" ] && return 2
return 0
}
ethernet_link_up()
{
declare linkstate=$(ethtool $1 | grep "Link detected:" |\
awk '{print $3}')
[ -n "$linkstate" ] || return 0
case $linkstate in
yes)
return 0
;;
*)
return 1
;;
esac
return 1
}
#
# Checks the physical link status of an ethernet or bonded interface.
#
network_link_up()
{
declare slaves
declare intf_arg=$1
declare link_up=1 # Assume link down
declare intf_test
if [ -z "$intf_arg" ]; then
ocf_log err "usage: network_link_up <intf>"
return 1
fi
ethernet_link_up $intf_arg
link_up=$?
if [ $link_up -eq 0 ]; then
ocf_log debug "Link for $intf_arg: Detected"
else
ocf_log warn "Link for $intf_arg: Not detected"
fi
return $link_up
}
ipv4_list_interfaces()
{
declare idx dev ifaddr
while read idx dev ifaddr; do
isSlave $dev
if [ $? -ne 2 ]; then
continue
fi
idx=${idx/:/}
echo $dev ${ifaddr/\/*/} ${ifaddr/*\//}
done < <(/sbin/ip -o -f inet addr | awk '{print $1,$2,$4}')
return 0
}
#
# Add an IP address to our interface or remove it.
#
ipv6()
{
declare dev maskbits
declare addr=$2
declare addr_exp=$(ipv6_expand $addr)
while read dev ifaddr_exp maskbits; do
if [ -z "$dev" ]; then
continue
fi
if [ "$1" = "add" ]; then
if [ -n "$OCF_RESKEY_prefer_interface" ] && \
[ "$OCF_RESKEY_prefer_interface" != $dev ]; then
continue
fi
ipv6_same_subnet $ifaddr_exp/$maskbits $addr_exp
if [ $? -ne 0 ]; then
continue
fi
interface_up $dev
if [ $? -ne 0 ]; then
continue
fi
if [ "$OCF_RESKEY_monitor_link" = "yes" ]; then
network_link_up $dev
if [ $? -ne 0 ]; then
continue
fi
fi
if [ "${addr/\/*/}" = "${addr}" ]; then
addr="$addr/$maskbits"
fi
ocf_log info "Adding IPv6 address $addr to $dev"
fi
if [ "$1" = "del" ]; then
if [ "${addr_exp/\/*/}" != "$ifaddr_exp" ]; then
continue
fi
addr=`/sbin/ip addr list | grep "$addr" | head -n 1 | awk '{print $2}'`
ocf_log info "Removing IPv6 address $addr from $dev"
fi
/sbin/ip -f inet6 addr $1 dev $dev $addr
[ $? -ne 0 ] && return 1
# Duplicate Address Detection [DAD]
# Kernel will flag the IP as 'tentative' until it ensured that
# there is no duplicates.
# if there is, it will flag it as 'dadfailed'
if [ "$1" = "add" ]; then
for i in {1..10}; do
ipstatus=$(/sbin/ip -o -f inet6 addr show dev $dev to $addr)
if [[ $ipstatus == *dadfailed* ]]; then
ocf_log err "IPv6 address collision ${addr%%/*} [DAD]"
ip -f inet6 addr del dev $dev $addr
if [[ $? -ne 0 ]]; then
ocf_log err "Could not delete IPv6 address"
fi
return 1
elif [[ $ipstatus != *tentative* ]]; then
break
elif [[ $i -eq 10 ]]; then
ofc_log warn "IPv6 address : DAD is still in tentative"
fi
sleep 0.5
done
# Now the address should be useable
# Try to send Unsolicited Neighbor Advertisements if send_ua is available
if [ -x $SENDUA ]; then
ARGS="-i 200 -c 5 ${addr%%/*} $maskbits $dev"
ocf_log info "$SENDUA $ARGS"
$SENDUA $ARGS || ocf_log err "Could not send ICMPv6 Unsolicited Neighbor Advertisements."
fi
fi
#
# NDP should take of figuring out our new address. Plus,
# we do not have something (like arping) to do this for ipv6
# anyway.
#
# RFC 2461, section 7.2.6 states thusly:
#
# Note that because unsolicited Neighbor Advertisements do not
# reliably update caches in all nodes (the advertisements might
# not be received by all nodes), they should only be viewed as
# a performance optimization to quickly update the caches in
# most neighbors.
#
# Not sure if this is necessary for ipv6 either.
file=$(which rdisc 2>/dev/null)
if [ -f "$file" ]; then
if [ "$OCF_RESKEY_disable_rdisc" != "yes" ] && \
[ "$OCF_RESKEY_disable_rdisc" != "1" ]; then
killall -HUP rdisc || rdisc -fs
fi
fi
return 0
done < <(ipv6_list_interfaces)
return 1
}
#
# Add an IP address to our interface or remove it.
#
ipv4()
{
declare dev ifaddr maskbits
declare addr=$2
while read dev ifaddr maskbits; do
if [ -z "$dev" ]; then
continue
fi
if [ "$1" = "add" ]; then
if [ -n "$OCF_RESKEY_prefer_interface" ] && \
[ "$OCF_RESKEY_prefer_interface" != $dev ]; then
continue
fi
ipv4_same_subnet $ifaddr/$maskbits $addr
if [ $? -ne 0 ]; then
continue
fi
interface_up $dev
if [ $? -ne 0 ]; then
continue
fi
if [ "$OCF_RESKEY_monitor_link" = "yes" ]; then
network_link_up $dev
if [ $? -ne 0 ]; then
continue
fi
fi
if [ "${addr/\/*/}" = "${addr}" ]; then
addr="$addr/$maskbits"
fi
ocf_log info "Adding IPv4 address $addr to $dev"
fi
if [ "$1" = "del" ]; then
if [ "${addr/\/*/}" != "$ifaddr" ]; then
continue
fi
addr=`/sbin/ip addr list | grep "$ifaddr/" | head -n 1 | awk '{print $2}'`
ocf_log info "Removing IPv4 address $addr from $dev"
fi
if [ "$1" = "add" ]; then
ocf_log debug "Pinging addr ${addr%%/*} from dev $dev"
if ping_check inet ${addr%%/*} $dev; then
ocf_log err "IPv4 address collision ${addr%%/*}"
return 1
fi
fi
/sbin/ip -f inet addr $1 dev $dev $addr
[ $? -ne 0 ] && return 1
#
# XXX: Following needed? ifconfig:YES, ifcfg:NO, iproute2:???
#
if [ "$1" = "add" ]; then
# do that freak arp thing
hwaddr=$(/sbin/ip -o link show $dev)
hwaddr=${hwaddr/*link\/ether\ /}
hwaddr=${hwaddr/\ \*/}
addr=${addr/\/*/}
ocf_log debug "Sending gratuitous ARP: $addr $hwaddr"
arping -q -c 2 -U -I $dev $addr
fi
file=$(which rdisc 2>/dev/null)
if [ -f "$file" ]; then
if [ "$OCF_RESKEY_disable_rdisc" != "yes" ] && \
[ "$OCF_RESKEY_disable_rdisc" != "1" ]; then
killall -HUP rdisc || rdisc -fs
fi
fi
return 0
done < <(ipv4_list_interfaces)
return 1
}
#
# Usage:
# ping_check <family> <address> [interface]
#
ping_check()
{
declare ops="-c 1 -w 2"
declare pingcmd=""
if [ "$1" = "inet6" ]; then
pingcmd="ping6"
else
pingcmd="ping"
fi
if [ -n "$3" ]; then
ops="$ops -I $3"
fi
return $($pingcmd $ops $2 &> /dev/null)
}
#
# Usage:
# check_interface_up <family> <address>
#
check_interface_up()
{
declare dev
declare addr=${2/\/*/}
declare currentAddr caExpanded
if [ "$1" == "inet6" ]; then
addrExpanded=$(ipv6_expand $addr)
for currentAddr in `/sbin/ip -f $1 -o addr|awk '{print $4}'`; do
caExpanded=$(ipv6_expand $currentAddr)
caExpanded=${caExpanded/\/*/}
if [ "$addrExpanded" == "$caExpanded" ]; then
dev=$(/sbin/ip -f $1 -o addr | grep " ${currentAddr/\/*/}" | awk '{print $2}')
break
fi
done
else
dev=$(/sbin/ip -f $1 -o addr | grep " $addr/" | awk '{print $2}')
fi
if [ -z "$dev" ]; then
return 1
fi
interface_up $dev
return $?
}
#
# Usage:
# address_configured <family> <address>
#
address_configured()
{
declare line
declare addr
declare currentAddr caExpanded
# Chop off mask bits
addr=${2/\/*/}
if [ "$1" == "inet6" ]; then
addrExpanded=$(ipv6_expand $addr)
for currentAddr in `/sbin/ip -f $1 -o addr|awk '{print $4}'`; do
caExpanded=$(ipv6_expand $currentAddr)
caExpanded=${caExpanded/\/*/}
if [ "$addrExpanded" == "$caExpanded" ]; then
line=$(/sbin/ip -f $1 -o addr | grep " ${currentAddr/\/*/}");
break
fi
done
else
line=$(/sbin/ip -f $1 -o addr | grep " $addr/")
fi
if [ -z "$line" ]; then
return 1
fi
return 0
}
#
# Usage:
# ip_op <family> <operation> <address> [quiet]
#
ip_op()
{
declare dev
declare rtr
declare addr=${3/\/*/}
declare caExpanded currentAddr
if [ "$2" = "status" ]; then
ocf_log debug "Checking $3, Level $OCF_CHECK_LEVEL"
if [ "$1" == "inet6" ]; then
addrExpanded=$(ipv6_expand $addr)
for currentAddr in `/sbin/ip -f $1 -o addr|awk '{print $4}'`; do
caExpanded=$(ipv6_expand $currentAddr)
caExpanded=${caExpanded/\/*/}
if [ "$addrExpanded" == "$caExpanded" ]; then
dev=$(/sbin/ip -f $1 -o addr | grep " ${currentAddr/\/*/}" | awk '{print $2}')
break
fi
done
else
dev=$(/sbin/ip -f $1 -o addr | grep " $addr/" | awk '{print $2}')
fi
if [ -z "$dev" ]; then
ocf_log warn "$3 is not configured"
return 1
fi
ocf_log debug "$3 present on $dev"
if [ "$OCF_RESKEY_monitor_link" = "yes" ]; then
if ! network_link_up $dev; then
ocf_log warn "No link on $dev..."
return 1
fi
ocf_log debug "Link detected on $dev"
fi
[ $OCF_CHECK_LEVEL -lt 10 ] && return 0
if ! ping_check $1 $addr $dev; then
ocf_log warn "Failed to ping $addr"
return 1
fi
ocf_log debug "Local ping to $addr succeeded"
return 0
fi
case $1 in
inet)
ipv4 $2 $3
return $?
;;
inet6)
if [ "$2" = "del" ]; then
addrExpanded=$(ipv6_expand $addr)
for currentAddr in `/sbin/ip -f $1 -o addr|awk '{print $4}'`; do
caExpanded=$(ipv6_expand $currentAddr)
caExpanded=${caExpanded/\/*/}
if [ "$addrExpanded" == "$caExpanded" ]; then
addr6=$(/sbin/ip -f $1 -o addr | grep " ${currentAddr/\/*/}" | awk '{print $4}')
ipv6 $2 $addr6
return $?
fi
done
fi
ipv6 $2 $3
return $?
;;
esac
return 1
}
case ${OCF_RESKEY_family} in
inet)
;;
inet6)
;;
*)
if [ "${OCF_RESKEY_address//:/}" != "${OCF_RESKEY_address}" ]; then
export OCF_RESKEY_family=inet6
else
export OCF_RESKEY_family=inet
fi
;;
esac
# Force ipv6 addresses to lower case
if [ "$OCF_RESKEY_family" = "inet6" ]; then
OCF_RESKEY_address=$(echo $OCF_RESKEY_address | tr '[:upper:]' '[:lower:]')
fi
if [ -z "$OCF_CHECK_LEVEL" ]; then
OCF_CHECK_LEVEL=0
fi
if [ "${OCF_RESKEY_monitor_link}" = "no" ] ||
[ "${OCF_RESKEY_monitor_link}" = "0" ]; then
OCF_RESKEY_monitor_link="no"
else
OCF_RESKEY_monitor_link="yes"
fi
case $1 in
start)
if address_configured ${OCF_RESKEY_family} ${OCF_RESKEY_address}; then
ocf_log debug "${OCF_RESKEY_address} already configured"
exit 0
fi
ip_op ${OCF_RESKEY_family} add ${OCF_RESKEY_address}
if [ $? -ne 0 ]; then
exit $OCF_ERR_GENERIC
fi
if [ $NFS_TRICKS -eq 0 ]; then
if [ "$OCF_RESKEY_nfslock" = "yes" ] || \
[ "$OCF_RESKEY_nfslock" = "1" ]; then
notify_list_broadcast /var/lib/nfs/statd
fi
fi
exit $?
;;
stop)
if address_configured ${OCF_RESKEY_family} ${OCF_RESKEY_address}; then
ip_op ${OCF_RESKEY_family} del ${OCF_RESKEY_address}
# Make sure it's down
if address_configured ${OCF_RESKEY_family} ${OCF_RESKEY_address}; then
ocf_log err "Failed to remove ${OCF_RESKEY_address}"
exit 1
fi
# XXX Let nfsd/lockd clear their queues; we hope to have a
# way to enforce this in the future
if [ -z "$OCF_RESKEY_sleeptime" ]; then
sleep 10
else
if [ "$OCF_RESKEY_sleeptime" -gt "0" ]; then
sleep $OCF_RESKEY_sleeptime
fi
fi
else
ocf_log debug "${OCF_RESKEY_address} is not configured"
fi
exit 0
;;
status|monitor)
ip_op ${OCF_RESKEY_family} status ${OCF_RESKEY_address}
[ $? -ne 0 ] && exit $OCF_NOT_RUNNING
check_interface_up ${OCF_RESKEY_family} ${OCF_RESKEY_address}
exit $?
;;
restart)
$0 stop || exit $OCF_ERR_GENERIC
$0 start || exit $OCF_ERR_GENERIC
exit 0
;;
meta-data)
meta_data
exit 0
;;
validate-all|verify_all)
verify_all
exit $?
;;
*)
echo "usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/lvm.sh b/rgmanager/src/resources/lvm.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/lvm.sh
rename to rgmanager/src/resources/lvm.sh.in
index 97ddc5272..a3a6c30a0
--- a/rgmanager/src/resources/lvm.sh
+++ b/rgmanager/src/resources/lvm.sh.in
@@ -1,180 +1,180 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# LVM Failover Script.
# NOTE: Changes to /etc/lvm/lvm.conf are required for proper operation.
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
LC_ALL=C
LANG=C
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LC_ALL LANG PATH
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/member_util.sh
. $(dirname $0)/lvm_by_lv.sh
. $(dirname $0)/lvm_by_vg.sh
rv=0
################################################################################
# ha_lvm_proper_setup_check
#
################################################################################
function ha_lvm_proper_setup_check
{
##
# Does the Volume Group exist?
# 1) User may have forgotten to create it
# 2) User may have misspelled it in the config file
##
if ! vgs $OCF_RESKEY_vg_name --config 'global{locking_type=0}'>& /dev/null; then
ocf_log err "HA LVM: Unable to get volume group attributes for $OCF_RESKEY_vg_name"
return $OCF_ERR_GENERIC
fi
##
# Are we using the "tagging" or "CLVM" variant?
# The CLVM variant will have the cluster attribute set
##
if [[ "$(vgs -o attr --noheadings --config 'global{locking_type=0}' $OCF_RESKEY_vg_name 2>/dev/null)" =~ .....c ]]; then
# Is clvmd running?
if ! ps -C clvmd >& /dev/null; then
ocf_log err "HA LVM: $OCF_RESKEY_vg_name has the cluster attribute set, but 'clvmd' is not running"
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
fi
##
# The "tagging" variant is being used if we have gotten this far.
##
##
# The default for lvm.conf:activation/volume_list is empty,
# this must be changed for HA LVM.
##
if ! lvm dumpconfig activation/volume_list >& /dev/null; then
ocf_log err "HA LVM: Improper setup detected"
ocf_log err "* \"volume_list\" not specified in lvm.conf."
return $OCF_ERR_GENERIC
fi
##
# Machine's cluster node name must be present as
# a tag in lvm.conf:activation/volume_list
##
if ! lvm dumpconfig activation/volume_list | grep $(local_node_name); then
ocf_log err "HA LVM: Improper setup detected"
ocf_log err "* @$(local_node_name) missing from \"volume_list\" in lvm.conf"
return $OCF_ERR_GENERIC
fi
##
# The volume group to be failed over must NOT be in
# lvm.conf:activation/volume_list; otherwise, machines
# will be able to activate the VG regardless of the tags
##
if lvm dumpconfig activation/volume_list | grep "\"$OCF_RESKEY_vg_name\""; then
ocf_log err "HA LVM: Improper setup detected"
ocf_log err "* $OCF_RESKEY_vg_name found in \"volume_list\" in lvm.conf"
return $OCF_ERR_GENERIC
fi
##
# Next, we need to ensure that their initrd has been updated
# If not, the machine could boot and activate the VG outside
# the control of rgmanager
##
# Fixme: we might be able to perform a better check...
if [ "$(find /boot -name *.img -newer /etc/lvm/lvm.conf)" == "" ]; then
ocf_log err "HA LVM: Improper setup detected"
ocf_log err "* initrd image needs to be newer than lvm.conf"
# While dangerous if not done the first time, there are many
# cases where we don't simply want to fail here. Instead,
# keep warning until the user remakes the initrd - or has
# it done for them by upgrading the kernel.
#return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
################################################################################
# MAIN
################################################################################
case $1 in
start)
ha_lvm_proper_setup_check || exit 1
if [ -z "$OCF_RESKEY_lv_name" ]; then
vg_start || exit 1
else
lv_start || exit 1
fi
;;
status|monitor)
ocf_log notice "Getting status"
if [ -z "$OCF_RESKEY_lv_name" ]; then
vg_status
exit $?
else
lv_status
exit $?
fi
;;
stop)
ha_lvm_proper_setup_check
if [ -z "$OCF_RESKEY_lv_name" ]; then
vg_stop || exit 1
else
lv_stop || exit 1
fi
;;
recover|restart)
$0 stop || exit $OCF_ERR_GENERIC
$0 start || exit $OCF_ERR_GENERIC
;;
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
;;
validate-all|verify-all)
if [ -z "$OCF_RESKEY_lv_name" ]; then
vg_verify || exit 1
else
lv_verify || exit 1
fi
;;
*)
echo "usage: $0 {start|status|monitor|stop|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit $rv
diff --git a/rgmanager/src/resources/lvm_by_lv.sh b/rgmanager/src/resources/lvm_by_lv.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/lvm_by_lv.sh
rename to rgmanager/src/resources/lvm_by_lv.sh.in
index ef70366a9..78befd388
--- a/rgmanager/src/resources/lvm_by_lv.sh
+++ b/rgmanager/src/resources/lvm_by_lv.sh.in
@@ -1,534 +1,534 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# lv_verify
#
# Verify the parameters passed in
#
lv_verify()
{
# Anything to verify? Perhaps the names?
return $OCF_SUCCESS
}
# lv_owner
#
# Returns:
# 1 == We are the owner
# 2 == We can claim it
# 0 == Owned by someone else
function lv_owner
{
local my_name=$1
local owner=$2
if [ -z "$my_name" ]; then
ocf_log err "Unable to determine cluster node name"
return 0
fi
if [ -z "$owner" ]; then
# No-one owns this LV yet, so we can claim it
return 2
fi
if [ $owner != $my_name ]; then
if is_node_member_clustat $owner ; then
return 0
fi
return 2
fi
return 1
}
steal_tag()
{
local owner=$1
local lv_path=$2
ocf_log notice "Owner of $lv_path is not in the cluster"
ocf_log notice "Stealing $lv_path"
lvchange --deltag $owner $lv_path
if [ $? -ne 0 ]; then
ocf_log err "Failed to steal $lv_path from $owner"
return $OCF_ERR_GENERIC
fi
# Warning --deltag doesn't always result in failure
if [ ! -z `lvs -o tags --noheadings $lv_path` ]; then
ocf_log err "Failed to steal $lv_path from $owner."
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
restore_transient_failed_pvs()
{
local a=0
local -a results
results=(`pvs -o name,vg_name,attr --noheadings | grep $OCF_RESKEY_vg_name | grep -v 'unknown device'`)
while [ ! -z "${results[$a]}" ] ; do
if [[ ${results[$(($a + 2))]} =~ ..m ]] &&
[ $OCF_RESKEY_vg_name == ${results[$(($a + 1))]} ]; then
ocf_log notice "Attempting to restore missing PV, ${results[$a]} in $OCF_RESKEY_vg_name"
vgextend --restoremissing $OCF_RESKEY_vg_name ${results[$a]}
if [ $? -ne 0 ]; then
ocf_log notice "Failed to restore ${results[$a]}"
else
ocf_log notice " ${results[$a]} restored"
fi
fi
a=$(($a + 3))
done
}
# lv_exec_resilient
#
# Sometimes, devices can come back. Their metadata will conflict
# with the good devices that remain. This function filters out those
# failed devices when executing the given command
#
# Finishing with vgscan resets the cache/filter
lv_exec_resilient()
{
declare command=$1
declare all_pvs
ocf_log notice "Making resilient : $command"
if [ -z "$command" ]; then
ocf_log err "lv_exec_resilient: Arguments not supplied"
return $OCF_ERR_ARGS
fi
# pvs will print out only those devices that are valid
# If a device dies and comes back, it will not appear
# in pvs output (but you will get a Warning).
all_pvs=(`pvs --noheadings -o pv_name | grep -v Warning`)
# Now we use those valid devices in a filter which we set up.
# The device will then be activated because there are no
# metadata conflicts.
command=$command" --config devices{filter=["
for i in ${all_pvs[*]}; do
command=$command'"a|'$i'|",'
done
command=$command"\"r|.*|\"]}"
ocf_log notice "Resilient command: $command"
if ! $command ; then
ocf_log err "lv_exec_resilient failed"
vgscan
return $OCF_ERR_GENERIC
else
vgscan
return $OCF_SUCCESS
fi
}
# lv_activate_resilient
#
# Sometimes, devices can come back. Their metadata will conflict
# with the good devices that remain. We must filter out those
# failed devices when trying to reactivate
lv_activate_resilient()
{
declare action=$1
declare lv_path=$2
declare op="-ay"
if [ -z "$action" ] || [ -z "$lv_path" ]; then
ocf_log err "lv_activate_resilient: Arguments not supplied"
return $OCF_ERR_ARGS
fi
if [ $action != "start" ]; then
op="-an"
elif [[ "$(lvs -o attr --noheadings $lv_path)" =~ r.......p ]] ||
[[ "$(lvs -o attr --noheadings $lv_path)" =~ R.......p ]]; then
# We can activate partial RAID LVs and run just fine.
ocf_log notice "Attempting activation of partial RAID LV, $lv_path"
op="-ay --partial"
fi
if ! lv_exec_resilient "lvchange $op $lv_path" ; then
ocf_log err "lv_activate_resilient $action failed on $lv_path"
return $OCF_ERR_GENERIC
else
return $OCF_SUCCESS
fi
}
lv_status_clustered()
{
declare lv_path="$OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
#
# Check if device is active
#
if [[ ! "$(lvs -o attr --noheadings $lv_path)" =~ ....a. ]]; then
return $OCF_NOT_RUNNING
fi
return $OCF_SUCCESS
}
# lv_status
#
# Is the LV active?
lv_status_single()
{
declare lv_path="$OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
declare dev="/dev/$lv_path"
declare realdev
declare owner
declare my_name
#
# Check if device is active
#
if [[ ! "$(lvs -o attr --noheadings $lv_path)" =~ ....a. ]]; then
return $OCF_NOT_RUNNING
fi
if [[ "$(vgs -o attr --noheadings $OCF_RESKEY_vg_name)" =~ .....c ]]; then
ocf_log notice "$OCF_RESKEY_vg_name is a cluster volume. Ignoring..."
return $OCF_SUCCESS
fi
#
# Check if all links/device nodes are present
#
if [ -h "$dev" ]; then
realdev=$(readlink -f $dev)
if [ $? -ne 0 ]; then
ocf_log err "Failed to follow link, $dev"
return $OCF_ERR_ARGS
fi
if [ ! -b $realdev ]; then
ocf_log err "Device node for $lv_path is not present"
return $OCF_ERR_GENERIC
fi
else
ocf_log err "Symbolic link for $lv_path is not present"
return $OCF_ERR_GENERIC
fi
#
# Verify that we are the correct owner
#
owner=`lvs -o tags --noheadings $lv_path | tr -d ' '`
my_name=$(local_node_name)
if [ -z "$my_name" ]; then
ocf_log err "Unable to determine local machine name"
# FIXME: I don't really want to fail on 1st offense
return $OCF_SUCCESS
fi
if [ -z "$owner" ] || [ "$my_name" != "$owner" ]; then
ocf_log err "WARNING: $lv_path should not be active"
ocf_log err "WARNING: $my_name does not own $lv_path"
ocf_log err "WARNING: Attempting shutdown of $lv_path"
lv_activate_resilient "stop" $lv_path
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
function lv_status
{
# We pass in the VG name to see of the logical volume is clustered
if [[ $(vgs -o attr --noheadings $OCF_RESKEY_vg_name) =~ .....c ]]; then
lv_status_clustered
else
lv_status_single
fi
}
# lv_activate_and_tag
lv_activate_and_tag()
{
declare action=$1
declare tag=$2
declare lv_path=$3
typeset self_fence=""
case ${OCF_RESKEY_self_fence} in
"yes") self_fence=1 ;;
1) self_fence=1 ;;
*) self_fence="" ;;
esac
if [ -z "$action" ] || [ -z "$tag" ] || [ -z "$lv_path" ]; then
ocf_log err "Supplied args: 1) $action, 2) $tag, 3) $lv_path"
return $OCF_ERR_ARGS
fi
if [ "$action" == "start" ]; then
ocf_log notice "Activating $lv_path"
lvchange --addtag $tag $lv_path
if [ $? -ne 0 ]; then
ocf_log err "Unable to add tag to $lv_path"
return $OCF_ERR_GENERIC
fi
if ! lv_activate_resilient $action $lv_path; then
ocf_log err "Unable to activate $lv_path"
return $OCF_ERR_GENERIC
fi
else
ocf_log notice "Deactivating $lv_path"
if ! lv_activate_resilient $action $lv_path; then
if [ "$self_fence" ]; then
ocf_log err "Unable to deactivate $lv_path: REBOOTING"
sync
reboot -fn
else
ocf_log err "Unable to deactivate $lv_path"
fi
return $OCF_ERR_GENERIC
fi
# Only try to remove tag if it is our tag
if [ "`lvs --noheadings -o lv_tags $lv_path | tr -d ' '`" == $tag ]; then
ocf_log notice "Removing ownership tag ($tag) from $lv_path"
lvchange --deltag $tag $lv_path
if [ $? -ne 0 ]; then
ocf_log err "Unable to delete tag from $lv_path"
# Newer versions of LVM require the missing PVs to
# be removed from the VG via a separate call before
# the tag can be removed.
ocf_log err "Attempting volume group clean-up and retry"
vgreduce --removemissing --mirrorsonly --force $OCF_RESKEY_vg_name
# Retry tag deletion
lvchange --deltag $tag $lv_path
if [ $? -ne 0 ]; then
if [ "$self_fence" ]; then
ocf_log err "Failed to delete tag from $lv_path: REBOOTING"
sync
reboot -fn
else
ocf_log err "Failed to delete tag from $lv_path"
fi
return $OCF_ERR_GENERIC
fi
fi
fi
fi
return $OCF_SUCCESS
}
# lv_activate
# $1: start/stop only
#
# Basically, if we want to [de]activate an LVM volume,
# we must own it. That means that our tag must be on it.
# This requires a change to /etc/lvm/lvm.conf:
# volume_list = [ "root_volume", "@my_hostname" ]
# where "root_volume" is your root volume group and
# "my_hostname" is $(local_node_name)
#
# If there is a node failure, we may wish to "steal" the
# LV. For that, we need to check if the node that owns
# it is still part of the cluster. We use the tag to
# determine who owns the volume then query for their
# liveness. If they are dead, we can steal.
lv_activate()
{
declare lv_path="$OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
declare owner=`lvs -o tags --noheadings $lv_path | tr -d ' '`
declare my_name=$(local_node_name)
local owned
lv_owner $my_name $owner
owned=$?
if [ $owned -eq 0 ]; then
ocf_log info "Someone else owns this logical volume"
return $OCF_ERR_GENERIC
fi
# If this is a partial VG, attempt to
# restore any transiently failed PVs
if [[ $(vgs -o attr --noheadings $OCF_RESKEY_vg_name) =~ ...p ]]; then
ocf_log err "Volume group \"$OCF_RESKEY_vg_name\" has PVs marked as missing"
restore_transient_failed_pvs
fi
if [ ! -z "$owner" ] && [ $owned -eq 2 ]; then
steal_tag $owner $lv_path
fi
if ! lv_activate_and_tag $1 $my_name $lv_path; then
ocf_log err "Failed to $1 $lv_path"
ocf_log notice "Attempting cleanup of $OCF_RESKEY_vg_name"
if vgreduce --removemissing --mirrorsonly --force --config \
"activation { volume_list = \"$OCF_RESKEY_vg_name\" }" \
$OCF_RESKEY_vg_name; then
ocf_log notice "$OCF_RESKEY_vg_name now consistent"
owner=`lvs -o tags --noheadings $lv_path | tr -d ' '`
lv_owner $my_name $owner
owned=$?
if [ ! -z "$owner" ] && [ $owned -eq 2 ]; then
steal_tag $owner $lv_path
ret=$?
if [ $ret -ne $OCF_SUCCESS ]; then
return $ret
fi
elif [ $owned -eq 0 ]; then
ocf_log info "Someone else owns this logical volume"
return $OCF_ERR_GENERIC
fi
if ! lv_activate_and_tag $1 $my_name $lv_path; then
ocf_log err "Failed second attempt to $1 $lv_path"
return $OCF_ERR_GENERIC
else
ocf_log notice "Second attempt to $1 $lv_path successful"
return $OCF_SUCCESS
fi
else
ocf_log err "Failed to $1 $lv_path"
return $OCF_ERR_GENERIC
fi
fi
return $OCF_SUCCESS
}
function lv_start_clustered
{
if lvchange -aey $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name; then
return $OCF_SUCCESS
fi
# FAILED exclusive activation:
# This can be caused by an LV being active remotely.
# Before attempting a repair effort, we should attempt
# to deactivate the LV cluster-wide; but only if the LV
# is not open. Otherwise, it is senseless to attempt.
if ! [[ "$(lvs -o attr --noheadings $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name)" =~ ....ao ]]; then
# We'll wait a small amount of time for some settling before
# attempting to deactivate. Then the deactivate will be
# immediately followed by another exclusive activation attempt.
sleep 5
if ! lvchange -an $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name; then
# Someone could have the device open.
# We can't do anything about that.
ocf_log err "Unable to perform required deactivation of $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name before starting"
return $OCF_ERR_GENERIC
fi
if lvchange -aey $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name; then
# Second attempt after deactivation was successful, we now
# have the lock exclusively
return $OCF_SUCCESS
fi
fi
# Failed to activate:
# This could be due to a device failure (or another machine could
# have snuck in between the deactivation/activation). We don't yet
# have a mechanism to check for remote activation, so we will proceed
# with repair action.
ocf_log err "Failed to activate logical volume, $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
ocf_log notice "Attempting cleanup of $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
if ! lvconvert --repair --use-policies $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name; then
ocf_log err "Failed to cleanup $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
return $OCF_ERR_GENERIC
fi
if ! lvchange -aey $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name; then
ocf_log err "Failed second attempt to activate $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
return $OCF_ERR_GENERIC
fi
ocf_log notice "Second attempt to activate $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name successful"
return $OCF_SUCCESS
}
function lv_start_single
{
if ! lvs $OCF_RESKEY_vg_name >& /dev/null; then
lv_count=0
else
lv_count=`lvs --noheadings -o name $OCF_RESKEY_vg_name | grep -v _mlog | grep -v _mimage | grep -v nconsistent | wc -l`
fi
if [ $lv_count -gt 1 ]; then
ocf_log err "HA LVM requires Only one logical volume per volume group."
ocf_log err "There are currently $lv_count logical volumes in $OCF_RESKEY_vg_name"
ocf_log err "Failing HA LVM start of $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name"
exit $OCF_ERR_GENERIC
fi
if ! lv_activate start; then
return 1
fi
return 0
}
function lv_start
{
# We pass in the VG name to see of the logical volume is clustered
if [[ "$(vgs -o attr --noheadings $OCF_RESKEY_vg_name)" =~ .....c ]]; then
lv_start_clustered
else
lv_start_single
fi
}
function lv_stop_clustered
{
lvchange -aln $OCF_RESKEY_vg_name/$OCF_RESKEY_lv_name
}
function lv_stop_single
{
if ! lv_activate stop; then
return 1
fi
return 0
}
function lv_stop
{
# We pass in the VG name to see of the logical volume is clustered
if [[ "$(vgs -o attr --noheadings $OCF_RESKEY_vg_name)" =~ .....c ]]; then
lv_stop_clustered
else
lv_stop_single
fi
}
diff --git a/rgmanager/src/resources/lvm_by_vg.sh b/rgmanager/src/resources/lvm_by_vg.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/lvm_by_vg.sh
rename to rgmanager/src/resources/lvm_by_vg.sh.in
index ab60970f7..4f40545ac
--- a/rgmanager/src/resources/lvm_by_vg.sh
+++ b/rgmanager/src/resources/lvm_by_vg.sh.in
@@ -1,529 +1,529 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# vg_owner
#
# Returns:
# 1 == We are the owner
# 2 == We can claim it
# 0 == Owned by someone else
function vg_owner
{
local owner=`vgs -o tags --noheadings $OCF_RESKEY_vg_name | tr -d ' '`
local my_name=$(local_node_name)
if [ -z "$my_name" ]; then
ocf_log err "Unable to determine cluster node name"
return 0
fi
if [ -z "$owner" ]; then
# No-one owns this VG yet, so we can claim it
return 2
fi
if [ $owner != $my_name ]; then
if is_node_member_clustat $owner ; then
ocf_log err " $owner owns $OCF_RESKEY_vg_name and is still a cluster member"
return 0
fi
return 2
fi
return 1
}
restore_transient_failed_pvs()
{
local a=0
local -a results
results=(`pvs -o name,vg_name,attr --noheadings | grep $OCF_RESKEY_vg_name | grep -v 'unknown device'`)
while [ ! -z "${results[$a]}" ] ; do
if [[ ${results[$(($a + 2))]} =~ ..m ]] &&
[ $OCF_RESKEY_vg_name == ${results[$(($a + 1))]} ]; then
ocf_log notice "Attempting to restore missing PV, ${results[$a]} in $OCF_RESKEY_vg_name"
vgextend --restoremissing $OCF_RESKEY_vg_name ${results[$a]}
if [ $? -ne 0 ]; then
ocf_log notice "Failed to restore ${results[$a]}"
else
ocf_log notice " ${results[$a]} restored"
fi
fi
a=$(($a + 3))
done
}
function strip_tags
{
local i
for i in `vgs --noheadings -o tags $OCF_RESKEY_vg_name | sed s/","/" "/g`; do
ocf_log info "Stripping tag, $i"
# LVM version 2.02.98 allows changing tags if PARTIAL
vgchange --deltag $i $OCF_RESKEY_vg_name
done
if [ ! -z `vgs -o tags --noheadings $OCF_RESKEY_vg_name | tr -d ' '` ]; then
ocf_log err "Failed to remove ownership tags from $OCF_RESKEY_vg_name"
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
function strip_and_add_tag
{
if ! strip_tags; then
ocf_log err "Failed to remove tags from volume group, $OCF_RESKEY_vg_name"
return $OCF_ERR_GENERIC
fi
vgchange --addtag $(local_node_name) $OCF_RESKEY_vg_name
if [ $? -ne 0 ]; then
ocf_log err "Failed to add ownership tag to $OCF_RESKEY_vg_name"
return $OCF_ERR_GENERIC
fi
ocf_log info "New tag \"$(local_node_name)\" added to $OCF_RESKEY_vg_name"
return $OCF_SUCCESS
}
function vg_status_clustered
{
return $OCF_SUCCESS
}
# vg_status
#
# Are all the LVs active?
function vg_status_single
{
local i
local dev
local my_name=$(local_node_name)
#
# Check that all LVs are active
#
for i in `lvs $OCF_RESKEY_vg_name --noheadings -o attr`; do
if [[ ! $i =~ ....a. ]]; then
return $OCF_NOT_RUNNING
fi
done
#
# Check if all links/device nodes are present
#
for i in `lvs $OCF_RESKEY_vg_name --noheadings -o name`; do
dev="/dev/$OCF_RESKEY_vg_name/$i"
if [ -h $dev ]; then
realdev=$(readlink -f $dev)
if [ $? -ne 0 ]; then
ocf_log err "Failed to follow link, $dev"
return $OCF_ERR_GENERIC
fi
if [ ! -b $realdev ]; then
ocf_log err "Device node for $dev is not present"
return $OCF_ERR_GENERIC
fi
else
ocf_log err "Symbolic link for $lv_path is not present"
return $OCF_ERR_GENERIC
fi
done
#
# Verify that we are the correct owner
#
vg_owner
if [ $? -ne 1 ]; then
ocf_log err "WARNING: $OCF_RESKEY_vg_name should not be active"
ocf_log err "WARNING: $my_name does not own $OCF_RESKEY_vg_name"
ocf_log err "WARNING: Attempting shutdown of $OCF_RESKEY_vg_name"
# FIXME: may need more force to shut this down
vgchange -an $OCF_RESKEY_vg_name
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
##
# Main status function for volume groups
##
function vg_status
{
if [[ "$(vgs -o attr --noheadings $OCF_RESKEY_vg_name)" =~ .....c ]]; then
vg_status_clustered
else
vg_status_single
fi
}
function vg_verify
{
# Anything to verify?
return $OCF_SUCCESS
}
function vg_start_clustered
{
local a
local results
local all_pvs
local resilience
local try_again=false
ocf_log info "Starting volume group, $OCF_RESKEY_vg_name"
if ! vgchange -aey $OCF_RESKEY_vg_name; then
try_again=true
# Failure to activate:
# This could be caused by a remotely active LV. Before
# attempting any repair of the VG, we will first attempt
# to deactivate the VG cluster-wide.
# We must check for open LVs though, since these cannot
# be deactivated. We have no choice but to go one-by-one.
# Allow for some settling
sleep 5
results=(`lvs -o name,attr --noheadings $OCF_RESKEY_vg_name 2> /dev/null`)
a=0
while [ ! -z "${results[$a]}" ]; do
if [[ ! ${results[$(($a + 1))]} =~ ....ao ]]; then
if ! lvchange -an $OCF_RESKEY_vg_name/${results[$a]}; then
ocf_log err "Unable to perform required deactivation of $OCF_RESKEY_vg_name before starting"
return $OCF_ERR_GENERIC
fi
fi
a=$(($a + 2))
done
fi
if $try_again && ! vgchange -aey $OCF_RESKEY_vg_name; then
ocf_log err "Failed to activate volume group, $OCF_RESKEY_vg_name"
ocf_log notice "Attempting cleanup of $OCF_RESKEY_vg_name"
if ! vgreduce --removemissing --mirrorsonly --force $OCF_RESKEY_vg_name; then
ocf_log err "Failed to make $OCF_RESKEY_vg_name consistent"
return $OCF_ERR_GENERIC
fi
if ! vgchange -aey $OCF_RESKEY_vg_name; then
ocf_log err "Failed second attempt to activate $OCF_RESKEY_vg_name"
return $OCF_ERR_GENERIC
fi
ocf_log notice "Second attempt to activate $OCF_RESKEY_vg_name successful"
return $OCF_SUCCESS
else
# The activation commands succeeded, but did they do anything?
# Make sure all the logical volumes are active
results=(`lvs -o name,attr --noheadings 2> /dev/null $OCF_RESKEY_vg_name`)
a=0
while [ ! -z "${results[$a]}" ]; do
if [[ ! ${results[$(($a + 1))]} =~ ....a. ]]; then
all_pvs=(`pvs --noheadings -o name 2> /dev/null`)
resilience=" --config devices{filter=["
for i in ${all_pvs[*]}; do
resilience=$resilience'"a|'$i'|",'
done
resilience=$resilience"\"r|.*|\"]}"
vgchange -aey $OCF_RESKEY_vg_name $resilience
break
fi
a=$(($a + 2))
done
# We need to check the LVs again if we made the command resilient
if [ ! -z "$resilience" ]; then
results=(`lvs -o name,attr --noheadings $OCF_RESKEY_vg_name $resilience 2> /dev/null`)
a=0
while [ ! -z ${results[$a]} ]; do
if [[ ! ${results[$(($a + 1))]} =~ ....a. ]]; then
ocf_log err "Failed to activate $OCF_RESKEY_vg_name"
return $OCF_ERR_GENERIC
fi
a=$(($a + 2))
done
ocf_log err "Orphan storage device in $OCF_RESKEY_vg_name slowing operations"
fi
fi
return $OCF_SUCCESS
}
function vg_start_single
{
local a
local results
local all_pvs
local resilience
ocf_log info "Starting volume group, $OCF_RESKEY_vg_name"
vg_owner
case $? in
0)
ocf_log info "Someone else owns this volume group"
return $OCF_ERR_GENERIC
;;
1)
ocf_log info "I own this volume group"
;;
2)
ocf_log info "I can claim this volume group"
;;
esac
if ! strip_and_add_tag; then
# Errors printed by sub-function
return $OCF_ERR_GENERIC
fi
if ! vgchange -ay $OCF_RESKEY_vg_name; then
ocf_log err "Failed to activate volume group, $OCF_RESKEY_vg_name"
ocf_log err "Attempting activation of logical volumes one-by-one."
results=(`lvs -o name,attr --noheadings $OCF_RESKEY_vg_name 2> /dev/null`)
a=0
while [ ! -z ${results[$a]} ]; do
if [[ ${results[$(($a + 1))]} =~ r.......p ]] ||
[[ ${results[$(($a + 1))]} =~ R.......p ]]; then
# Attempt "partial" activation of any RAID LVs
ocf_log err "Attempting partial activation of ${OCF_RESKEY_vg_name}/${results[$a]}"
if ! lvchange -ay --partial ${OCF_RESKEY_vg_name}/${results[$a]}; then
ocf_log err "Failed attempt to activate ${OCF_RESKEY_vg_name}/${results[$a]} in partial mode"
return $OCF_ERR_GENERIC
fi
ocf_log notice "Activation of ${OCF_RESKEY_vg_name}/${results[$a]} in partial mode succeeded"
elif [[ ${results[$(($a + 1))]} =~ m.......p ]] ||
[[ ${results[$(($a + 1))]} =~ M.......p ]]; then
ocf_log err "Attempting repair and activation of ${OCF_RESKEY_vg_name}/${results[$a]}"
if ! lvconvert --repair --use-policies ${OCF_RESKEY_vg_name}/${results[$a]}; then
ocf_log err "Failed to repair ${OCF_RESKEY_vg_name}/${results[$a]}"
return $OCF_ERR_GENERIC
fi
if ! lvchange -ay ${OCF_RESKEY_vg_name}/${results[$a]}; then
ocf_log err "Failed to activate ${OCF_RESKEY_vg_name}/${results[$a]}"
return $OCF_ERR_GENERIC
fi
ocf_log notice "Repair and activation of ${OCF_RESKEY_vg_name}/${results[$a]} succeeded"
else
ocf_log err "Attempting activation of non-redundant LV ${OCF_RESKEY_vg_name}/${results[$a]}"
if ! lvchange -ay ${OCF_RESKEY_vg_name}/${results[$a]}; then
ocf_log err "Failed to activate ${OCF_RESKEY_vg_name}/${results[$a]}"
return $OCF_ERR_GENERIC
fi
ocf_log notice "Successfully activated non-redundant LV ${OCF_RESKEY_vg_name}/${results[$a]}"
fi
a=$(($a + 2))
done
return $OCF_SUCCESS
else
# The activation commands succeeded, but did they do anything?
# Make sure all the logical volumes are active
results=(`lvs -o name,attr --noheadings $OCF_RESKEY_vg_name 2> /dev/null`)
a=0
while [ ! -z ${results[$a]} ]; do
if [[ ! ${results[$(($a + 1))]} =~ ....a. ]]; then
all_pvs=(`pvs --noheadings -o name 2> /dev/null`)
resilience=" --config devices{filter=["
for i in ${all_pvs[*]}; do
resilience=$resilience'"a|'$i'|",'
done
resilience=$resilience"\"r|.*|\"]}"
vgchange -ay $OCF_RESKEY_vg_name $resilience
break
fi
a=$(($a + 2))
done
# We need to check the LVs again if we made the command resilient
if [ ! -z "$resilience" ]; then
results=(`lvs -o name,attr --noheadings $OCF_RESKEY_vg_name $resilience 2> /dev/null`)
a=0
while [ ! -z ${results[$a]} ]; do
if [[ ! ${results[$(($a + 1))]} =~ ....a. ]]; then
ocf_log err "Failed to activate $OCF_RESKEY_vg_name"
return $OCF_ERR_GENERIC
fi
a=$(($a + 2))
done
ocf_log err "Orphan storage device in $OCF_RESKEY_vg_name slowing operations"
fi
fi
return $OCF_SUCCESS
}
##
# Main start function for volume groups
##
function vg_start
{
local a=0
local results
if [[ $(vgs -o attr --noheadings $OCF_RESKEY_vg_name) =~ ...p ]]; then
ocf_log err "Volume group \"$OCF_RESKEY_vg_name\" has PVs marked as missing"
restore_transient_failed_pvs
fi
if [[ "$(vgs -o attr --noheadings $OCF_RESKEY_vg_name)" =~ .....c ]]; then
vg_start_clustered
else
vg_start_single
fi
}
function vg_stop_clustered
{
local a
local results
typeset self_fence=""
case ${OCF_RESKEY_self_fence} in
"yes") self_fence=1 ;;
1) self_fence=1 ;;
*) self_fence="" ;;
esac
# Shut down the volume group
# Do we need to make this resilient?
a=0
while ! vgchange -aln $OCF_RESKEY_vg_name; do
a=$(($a + 1))
if [ $a -gt 10 ]; then
break;
fi
ocf_log err "Unable to deactivate $OCF_RESKEY_vg_name, retrying($a)"
sleep 1
which udevadm >& /dev/null && udevadm settle
done
# Make sure all the logical volumes are inactive
active=0
results=(`lvs -o name,attr --noheadings $OCF_RESKEY_vg_name 2> /dev/null`)
a=0
while [ ! -z ${results[$a]} ]; do
if [[ ${results[$(($a + 1))]} =~ ....a. ]]; then
active=1
break
fi
a=$(($a + 2))
done
# lvs may not show active volumes if all PVs in VG are gone
dmsetup table | grep -q "^${OCF_RESKEY_vg_name//-/--}-[^-]"
if [ $? -eq 0 ]; then
active=1
fi
if [ $active -ne 0 ]; then
if [ "$self_fence" ]; then
ocf_log err "Unable to deactivate $lv_path REBOOT"
sync
reboot -fn
else
ocf_log err "Logical volume $OCF_RESKEY_vg_name/${results[$a]} failed to shutdown"
fi
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
function vg_stop_single
{
local a
local results
typeset self_fence=""
case ${OCF_RESKEY_self_fence} in
"yes") self_fence=1 ;;
1) self_fence=1 ;;
*) self_fence="" ;;
esac
# Shut down the volume group
# Do we need to make this resilient?
vgchange -an $OCF_RESKEY_vg_name
# Make sure all the logical volumes are inactive
active=0
results=(`lvs -o name,attr --noheadings $OCF_RESKEY_vg_name 2> /dev/null`)
a=0
while [ ! -z ${results[$a]} ]; do
if [[ ${results[$(($a + 1))]} =~ ....a. ]]; then
active=1
break
fi
a=$(($a + 2))
done
# lvs may not show active volumes if all PVs in VG are gone
dmsetup table | grep -q "^${OCF_RESKEY_vg_name//-/--}-[^-]"
if [ $? -eq 0 ]; then
active=1
fi
if [ $active -ne 0 ]; then
if [ "$self_fence" ]; then
ocf_log err "Unable to deactivate $lv_path REBOOT"
sync
reboot -fn
else
ocf_log err "Logical volume $OCF_RESKEY_vg_name/${results[$a]} failed to shutdown"
fi
return $OCF_ERR_GENERIC
fi
# Make sure we are the owner before we strip the tags
vg_owner
if [ $? -eq 1 ]; then
strip_tags
fi
return $OCF_SUCCESS
}
##
# Main stop function for volume groups
##
function vg_stop
{
if [[ "$(vgs -o attr --noheadings $OCF_RESKEY_vg_name)" =~ .....c ]]; then
vg_stop_clustered
else
vg_stop_single
fi
}
diff --git a/rgmanager/src/resources/mysql.sh b/rgmanager/src/resources/mysql.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/mysql.sh
rename to rgmanager/src/resources/mysql.sh.in
index c4ec8ba2b..a69cd8037
--- a/rgmanager/src/resources/mysql.sh
+++ b/rgmanager/src/resources/mysql.sh.in
@@ -1,232 +1,232 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
export LC_ALL=C
export LANG=C
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
declare MYSQL_MYSQLD=/usr/bin/mysqld_safe
declare MYSQL_ipAddress
declare MYSQL_pid_file="`generate_name_for_pid_file`"
verify_all()
{
clog_service_verify $CLOG_INIT
if [ -z "$OCF_RESKEY_name" ]; then
clog_service_verify $CLOG_FAILED "Invalid Name Of Service"
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_service_name" ]; then
clog_service_verify $CLOG_FAILED_NOT_CHILD
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_INVALID "$OCF_RESKEY_config_file"
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
if [ ! -r "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_NOT_READABLE $OCF_RESKEY_config_file
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
if [ -z "$MYSQL_pid_file" ]; then
clog_service_verify $CLOG_FAILED "Invalid name of PID file"
return $OCF_ERR_ARGS
fi
clog_service_verify $CLOG_SUCCEED
return 0
}
start()
{
declare username=""
if status; then
ocf_log info "Starting Service $OCF_RESOURCE_INSTANCE > Already running"
return $OCF_SUCCESS
fi
clog_service_start $CLOG_INIT
# Pull out the user name from the options argument if it is set.
# We need this to properly set the pidfile permissions
if [ -n "$OCF_RESKEY_mysqld_options" ]; then
username=$(echo "$OCF_RESKEY_mysqld_options" | sed -n -e 's/^.*--user=\(\S*\)[[:space:]]*.*$/\1/p;s/^.*-u[[:space:]]*\(\S*\)[[:space:]]*.*$/\1/p')
fi
create_pid_directory "$username"
check_pid_file "$MYSQL_pid_file"
if [ $? -ne 0 ]; then
clog_check_pid $CLOG_FAILED "$MYSQL_pid_file"
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
if [ -n "$OCF_RESKEY_listen_address" ]; then
MYSQL_ipAddress="$OCF_RESKEY_listen_address"
else
clog_looking_for $CLOG_INIT "IP Address"
get_service_ip_keys "$OCF_RESKEY_service_name"
ip_addresses=`build_ip_list`
if [ -n "$ip_addresses" ]; then
for i in $ip_addresses; do
MYSQL_ipAddress="$i"
break;
done
else
clog_looking_for $CLOG_FAILED_NOT_FOUND "IP Address"
fi
fi
clog_looking_for $CLOG_SUCCEED "IP Address"
$MYSQL_MYSQLD --defaults-file="$OCF_RESKEY_config_file" \
--pid-file="$MYSQL_pid_file" \
--bind-address="$MYSQL_ipAddress" \
$OCF_RESKEY_mysqld_options > /dev/null 2>&1 &
if [ $? -ne 0 ]; then
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_service_start $CLOG_SUCCEED
# Sleep 1 sec before checking status so mysqld can start
sleep 1
status
return $?;
}
stop()
{
clog_service_stop $CLOG_INIT
stop_generic "$MYSQL_pid_file" "$OCF_RESKEY_shutdown_wait"
if [ $? -ne 0 ]; then
clog_service_stop $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_service_stop $CLOG_SUCCEED
return 0;
}
status()
{
clog_service_status $CLOG_INIT
status_check_pid "$MYSQL_pid_file"
case $? in
$OCF_NOT_RUNNING)
ps auxww | grep -Pv "grep|$MYSQL_MYSQLD" | grep "$MYSQL_pid_file" &> /dev/null
if [ "$?" -eq "0" ];then
declare i=$OCF_RESKEY_startup_wait
while [ "$i" -gt 0 ]; do
if [ -f "$MYSQL_pid_file" ]; then
break;
fi
sleep 1
let i=$i-1
done
if [ "$i" -eq 0 ]; then
clog_service_start $CLOG_FAILED_TIMEOUT
return $OCF_ERR_GENERIC
else
clog_service_status $CLOG_SUCCEED
exit 0
fi
fi
clog_service_status $CLOG_FAILED "$MYSQL_pid_file"
return $OCF_NOT_RUNNING
;;
0)
clog_service_status $CLOG_SUCCEED
exit 0
;;
*)
clog_service_status $CLOG_FAILED "$MYSQL_pid_file"
return $OCF_ERR_GENERIC
;;
esac
if [ $? -ne 0 ]; then
clog_service_status $CLOG_FAILED "$MYSQL_pid_file"
return $OCF_ERR_GENERIC
fi
clog_service_status $CLOG_SUCCEED
return 0
}
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
exit 0
;;
validate-all)
verify_all
exit $?
;;
start)
verify_all && start
exit $?
;;
stop)
verify_all && stop
exit $?
;;
status|monitor)
verify_all
status
exit $?
;;
restart)
verify_all
stop
start
exit $?
;;
*)
echo "Usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/named.sh b/rgmanager/src/resources/named.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/named.sh
rename to rgmanager/src/resources/named.sh.in
index e0d8ebe7a..5e1ef35b5
--- a/rgmanager/src/resources/named.sh
+++ b/rgmanager/src/resources/named.sh.in
@@ -1,224 +1,224 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
export LC_ALL=C
export LANG=C
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
declare NAMED_NAMED=/usr/sbin/named
declare NAMED_pid_file="`generate_name_for_pid_file`"
declare NAMED_conf_dir="`generate_name_for_conf_dir`"
declare NAMED_gen_config_file="$NAMED_conf_dir/named.conf"
declare NAMED_url_list
declare NAMED_parse_config=$(dirname $0)/utils/named-parse-config.pl
declare NAMED_update_src="false"
verify_all()
{
clog_service_verify $CLOG_INIT
if [ -z "$OCF_RESKEY_name" ]; then
clog_service_verify $CLOG_FAILED "Invalid Name Of Service"
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_service_name" ]; then
clog_service_verify $CLOG_FAILED_NOT_CHILD
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_INVALID "$OCF_RESKEY_config_file"
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
if [ ! -r "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_NOT_READABLE $OCF_RESKEY_config_file
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
if [ -n "$OCF_RESKEY_update_source" ]; then
NAMED_update_src=$OCF_RESKEY_update_source
fi
clog_service_verify $CLOG_SUCCEED
return 0
}
generate_config_file()
{
declare original_file="$1"
declare generated_file="$2"
declare ip_address="$3"
if [ -f "$generated_file" ]; then
sha1_verify "$generated_file"
if [ $? -ne 0 ]; then
clog_check_sha1 $CLOG_FAILED
return 0
fi
fi
clog_generate_config $CLOG_INIT "$original_file" "$generated_file"
generate_configTemplate "$generated_file" "$1"
cat "$original_file" | grep -v "^[[:space:]]*listen-on" | \
grep -v "^[[:space:]]*pid-file" | \
grep -v "^[[:space:]]*directory" >> "$generated_file"
declare tmp_file=`mktemp -t cluster.XXXXXXXXXX`
mv "$generated_file" "$tmp_file"
"$NAMED_parse_config" "$OCF_RESKEY_named_working_dir" "$NAMED_pid_file" "$ip_address" "$NAMED_update_src"\
< "$tmp_file" > "$generated_file"
rm "$tmp_file"
sha1_addToFile "$generated_file"
clog_generate_config $CLOG_SUCCEED "$original_file" "$generated_file"
return 0;
}
start()
{
declare ip_list;
declare username=""
clog_service_start $CLOG_INIT
# Pull out the user name from the options argument if it is set.
# We need this to properly set the pidfile permissions
if [ -n "$OCF_RESKEY_named_options" ]; then
username=$(echo "$OCF_RESKEY_named_options" | sed -n -e 's/^.*-u[[:space:]]*\(\S*\)[[:space:]]*.*$/\1/p')
fi
create_pid_directory "$username"
create_conf_directory "$NAMED_conf_dir"
check_pid_file "$NAMED_pid_file"
if [ $? -ne 0 ]; then
clog_check_pid $CLOG_FAILED "$NAMED_pid_file"
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_INIT "IP Addresses"
get_service_ip_keys "$OCF_RESKEY_service_name"
ip_addresses=`build_ip_list`
if [ -z "$ip_addresses" ]; then
clog_looking_for $CLOG_FAILED_NOT_FOUND "IP Addresses"
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_SUCCEED "IP Addresses"
ip_list=`echo $ip_addresses | sed 's/ /;/;s/\([[:digit:]]\)$/\1;/' `
if [ -z "$ip_list" ]; then
clog_looking_for $CLOG_FAILED_NOT_FOUND "IP Addresses"
return $OCF_ERR_GENERIC
fi
[ -x /sbin/portrelease ] && /sbin/portrelease named &>/dev/null
generate_config_file "$OCF_RESKEY_config_file" "$NAMED_gen_config_file" "$ip_list"
$NAMED_NAMED -c "$NAMED_gen_config_file" $OCF_RESKEY_named_options
if [ $? -ne 0 ]; then
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_service_start $CLOG_SUCCEED
return 0;
}
stop()
{
clog_service_stop $CLOG_INIT
stop_generic "$NAMED_pid_file" "$OCF_RESKEY_shutdown_wait"
if [ $? -ne 0 ]; then
clog_service_stop $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_service_stop $CLOG_SUCCEED
return 0;
}
status()
{
clog_service_status $CLOG_INIT
status_check_pid "$NAMED_pid_file"
if [ $? -ne 0 ]; then
clog_service_status $CLOG_FAILED "$NAMED_pid_file"
return $OCF_ERR_GENERIC
fi
clog_service_status $CLOG_SUCCEED
return 0
}
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
exit 0
;;
validate-all)
verify_all
exit $?
;;
start)
verify_all && start
exit $?
;;
stop)
verify_all && stop
exit $?
;;
status|monitor)
verify_all
status
exit $?
;;
restart)
verify_all
stop
start
exit $?
;;
*)
echo "Usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/netfs.sh b/rgmanager/src/resources/netfs.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/netfs.sh
rename to rgmanager/src/resources/netfs.sh.in
index dc64cd722..5b75f9d8f
--- a/rgmanager/src/resources/netfs.sh
+++ b/rgmanager/src/resources/netfs.sh.in
@@ -1,488 +1,488 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# NFS/CIFS file system mount/umount/etc. agent
#
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
. $(dirname $0)/utils/fs-lib.sh
do_metadata()
{
cat <<EOT
<?xml version="1.0" ?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1-modified.dtd">
<resource-agent name="netfs" version="rgmanager 2.0">
<version>1.0</version>
<longdesc lang="en">
This defines an NFS/CIFS mount for use by cluster services.
</longdesc>
<shortdesc lang="en">
Defines an NFS/CIFS file system mount.
</shortdesc>
<parameters>
<parameter name="name" primary="1">
<longdesc lang="en">
Symbolic name for this file system.
</longdesc>
<shortdesc lang="en">
File System Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="mountpoint" unique="1" required="1">
<longdesc lang="en">
Path in file system heirarchy to mount this file system.
</longdesc>
<shortdesc lang="en">
Mount Point
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="host" required="1">
<longdesc lang="en">
Server IP address or hostname
</longdesc>
<shortdesc lang="en">
IP or Host
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="export" required="1">
<longdesc lang="en">
NFS Export directory name or CIFS share
</longdesc>
<shortdesc lang="en">
Export
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="fstype">
<longdesc lang="en">
File System type (nfs, nfs4 or cifs)
</longdesc>
<shortdesc lang="en">
File System Type
</shortdesc>
<content type="string" default="nfs"/>
</parameter>
<parameter name="no_unmount" required="0">
<longdesc lang="en">
Do not unmount the filesystem during a stop or relocation operation
</longdesc>
<shortdesc lang="en">
Skip unmount opration
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="force_unmount">
<longdesc lang="en">
If set, the cluster will kill all processes using
this file system when the resource group is
stopped. Otherwise, the unmount will fail, and
the resource group will be restarted.
</longdesc>
<shortdesc lang="en">
Force Unmount
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="self_fence">
<longdesc lang="en">
If set and unmounting the file system fails, the node will
immediately reboot. Generally, this is used in conjunction
with force_unmount support, but it is not required.
</longdesc>
<shortdesc lang="en">
Seppuku Unmount
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="options">
<longdesc lang="en">
Provides a list of mount options. If none are specified,
the NFS file system is mounted -o sync.
</longdesc>
<shortdesc lang="en">
Mount Options
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="use_findmnt">
<longdesc lang="en">
Use findmnt to determine if and where a filesystem is mounted.
Disabling this uses the failback method (should be used if autofs
maps are located on network storage (ie. nfs, iscsi, etc).
</longdesc>
<shortdesc lang="en">
Utilize findmnt to detect if and where filesystems are mounted
</shortdesc>
<content type="boolean"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="900"/>
<action name="stop" timeout="30"/>
<!-- Recovery isn't possible; we don't know if resources are using
the file system. -->
<!-- Checks to see if it's mounted in the right place -->
<action name="status" interval="1m" timeout="10"/>
<action name="monitor" interval="1m" timeout="10"/>
<!-- Checks to see if we can read from the mountpoint -->
<action name="status" depth="10" timeout="30" interval="5m"/>
<action name="monitor" depth="10" timeout="30" interval="5m"/>
<!-- Checks to see if we can write to the mountpoint (if !ROFS) -->
<action name="status" depth="20" timeout="30" interval="10m"/>
<action name="monitor" depth="20" timeout="30" interval="10m"/>
<action name="meta-data" timeout="5"/>
<action name="validate-all" timeout="5"/>
</actions>
<special tag="rgmanager">
<child type="nfsexport" forbid="1"/>
<child type="nfsclient" forbid="1"/>
</special>
</resource-agent>
EOT
}
verify_host()
{
if [ -z "$OCF_RESKEY_host" ]; then
ocf_log err "No server hostname or IP address specified."
return 1
fi
host $OCF_RESKEY_host 2>&1 | grep -vq "not found"
if [ $? -eq 0 ]; then
return 0
fi
ocf_log err "Hostname or IP address \"$OCF_RESKEY_host\" not valid"
return $OCF_ERR_ARGS
}
verify_fstype()
{
# Auto detect?
[ -z "$OCF_RESKEY_fstype" ] && return 0
case $OCF_RESKEY_fstype in
nfs|nfs4|cifs)
return 0
;;
*)
ocf_log err "File system type $OCF_RESKEY_fstype not supported"
return $OCF_ERR_ARGS
;;
esac
}
verify_options()
{
declare -i ret=0
#
# From mount(1)
#
for o in `echo $OCF_RESKEY_options | sed -e s/,/\ /g`; do
case $o in
async|atime|auto|defaults|dev|exec|_netdev|noatime)
continue
;;
noauto|nodev|noexec|nosuid|nouser|ro|rw|suid|sync)
continue
;;
dirsync|user|users)
continue
;;
esac
case $OCF_RESKEY_fstype in
cifs)
continue
;;
nfs|nfs4)
case $o in
#
# NFS / NFS4 common
#
rsize=*|wsize=*|timeo=*|retrans=*|acregmin=*)
continue
;;
acregmax=*|acdirmin=*|acdirmax=*|actimeo=*)
continue
;;
retry=*|port=*|bg|fg|soft|hard|intr|cto|ac|noac)
continue
;;
esac
#
# NFS v2/v3 only
#
if [ "$OCF_RESKEY_fstype" = "nfs" ]; then
case $o in
mountport=*|mounthost=*)
continue
;;
mountprog=*|mountvers=*|nfsprog=*|nfsvers=*)
continue
;;
namelen=*)
continue
;;
tcp|udp|lock|nolock)
continue
;;
esac
fi
#
# NFS4 only
#
if [ "$OCF_RESKEY_fstype" = "nfs4" ]; then
case $o in
proto=*|clientaddr=*|sec=*)
continue
;;
esac
fi
;;
esac
ocf_log err "Option $o not supported for $OCF_RESKEY_fstype"
ret=$OCF_ERR_ARGS
done
return $ret
}
do_validate()
{
verify_name || return $OCF_ERR_ARGS
verify_fstype|| return $OCF_ERR_ARGS
verify_host || return $OCF_ERR_ARGS
verify_mountpoint || return $OCF_ERR_ARGS
verify_options || return $OCF_ERR_ARGS
# verify_target || return $OCF_ERR_ARGS
}
#
# Override real_device to use fs-lib's functions for start/stop_filesystem
#
real_device() {
export REAL_DEVICE="$1"
}
#
# do_mount - nfs / cifs are mounted differently than blockdevs
#
do_mount() {
declare opts=""
declare mount_options=""
declare ret_val
declare mp="$OCF_RESKEY_mountpoint"
#
# Get the filesystem type, if specified.
#
fstype_option=""
fstype=${OCF_RESKEY_fstype}
case "$fstype" in
""|"[ ]*")
fstype=""
;;
*) # found it
fstype_option="-t $fstype"
;;
esac
#
# Get the mount options, if they exist.
#
mount_options=""
opts=${OCF_RESKEY_options}
case "$opts" in
""|"[ ]*")
opts=""
;;
*) # found it
mount_options="-o $opts"
;;
esac
case $OCF_RESKEY_fstype in
nfs|nfs4)
mount -t $OCF_RESKEY_fstype $mount_options $OCF_RESKEY_host:"$OCF_RESKEY_export" "$mp"
;;
cifs)
mount -t $OCF_RESKEY_fstype $mount_options //$OCF_RESKEY_host/"$OCF_RESKEY_export" "$mp"
;;
esac
ret_val=$?
if [ $ret_val -ne 0 ]; then
ocf_log err "\
'mount $fstype_option $mount_options $OCF_RESKEY_host:$OCF_RESKEY_export $mp' failed, error=$ret_val"
return 1
fi
return 0
}
do_nfs_rpc_check() {
# see man nfs TRANSPORT PROTOCOL section for defaults
local nfsproto=tcp
local nfsmountproto=udp
# follow the same logic as mount.nfs option parser.
# the rightmost option wins over previous ones, so don't break when
# we find something.
for o in $(echo ${OCF_RESKEY_options} | sed -e s/,/\ /g); do
if echo $o | grep -q "^proto=" ; then
nfsproto="$(echo $o | cut -d "=" -f 2)"
fi
if echo $o | grep -q "^mountproto=" ; then
nfsmountproto="$(echo $o | cut -d "=" -f 2)"
fi
case $o in
tcp) nfsproto=tcp;;
udp) nfsproto=udp;;
rdma) nfsproto=rdma;;
esac
done
ocf_log debug "Testing generic rpc access on server ${OCF_RESKEY_host} with protocol $nfsproto"
if ! rpcinfo -T $nfsproto ${OCF_RESKEY_host} > /dev/null 2>&1; then
ocf_log alert "RPC server on ${OCF_RESKEY_host} with $nfsproto is not responding"
return 1
fi
ocf_log debug "Testing nfs rcp access on server ${OCF_RESKEY_host} with protocol $nfsproto"
if ! rpcinfo -T $nfsproto ${OCF_RESKEY_host} nfs > /dev/null 2>&1; then
ocf_log alert "NFS server on ${OCF_RESKEY_host} with $nfsproto is not responding"
return 1
fi
if [ "$OCF_RESKEY_fstype" = nfs ]; then
ocf_log debug "Testing mountd rpc access on server ${OCF_RESKEY_host} with protocol $nfsmountproto"
if ! rpcinfo -T $nfsmountproto ${OCF_RESKEY_host} mountd; then
ocf_log alert "MOUNTD server on ${OCF_RESKEY_host} with $nfsmountproto is not responding"
return 1
fi
fi
return 0
}
do_pre_unmount() {
case $OCF_RESKEY_fstype in
nfs|nfs4)
if [ "$self_fence" != $YES ]; then
ocf_log debug "Skipping pre unmount checks: self_fence is disabled"
return 0
fi
is_mounted "$dev" "$mp"
case $? in
$NO)
ocf_log debug "Skipping pre unmount checks: device is not mounted"
return 0
;;
esac
ocf_log info "pre unmount: checking if nfs server ${OCF_RESKEY_host} is alive"
if ! do_nfs_rpc_check; then
ocf_log alert "NFS server not responding - REBOOTING"
sleep 2
reboot -fn
fi
;;
esac
return 0
}
do_force_unmount() {
case $OCF_RESKEY_fstype in
nfs|nfs4)
ocf_log warning "Calling 'umount -f $mp'"
umount -f "$OCF_RESKEY_mountpoint"
return $?
;;
*)
;;
esac
return 1 # Returning 1 lets stop_filesystem do add'l checks
}
populate_defaults()
{
case $OCF_RESKEY_fstype in
nfs|nfs4)
export OCF_RESKEY_device="$OCF_RESKEY_host:$OCF_RESKEY_export"
if [ -z "$OCF_RESKEY_options" ]; then
export OCF_RESKEY_options=sync,soft,noac
fi
;;
cifs)
export OCF_RESKEY_device="//$OCF_RESKEY_host/$OCF_RESKEY_export"
if [ -z "$OCF_RESKEY_options" ]; then
export OCF_RESKEY_options=guest
fi
;;
esac
}
#
# Main...
#
populate_defaults
main $*
diff --git a/rgmanager/src/resources/nfsclient.sh b/rgmanager/src/resources/nfsclient.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/nfsclient.sh
rename to rgmanager/src/resources/nfsclient.sh.in
index 3d0e3f1f5..0ca79e9e3
--- a/rgmanager/src/resources/nfsclient.sh
+++ b/rgmanager/src/resources/nfsclient.sh.in
@@ -1,471 +1,471 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# NFS Export Client handler agent script
#
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
LC_ALL=C
LANG=C
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LC_ALL LANG PATH
. $(dirname $0)/ocf-shellfuncs
meta_data()
{
cat <<EOT
<?xml version="1.0" ?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1-modified.dtd">
<resource-agent version="rgmanager 2.0" name="nfsclient">
<version>1.0</version>
<longdesc lang="en">
This defines how a machine or group of machines may access
an NFS export on the cluster. IP addresses, IP wildcards,
hostnames, hostname wildcards, and netgroups are supported.
</longdesc>
<shortdesc lang="en">
Defines an NFS client.
</shortdesc>
<parameters>
<parameter name="name" unique="1" primary="1">
<longdesc lang="en">
This is a symbolic name of a client used to reference
it in the resource tree. This is NOT the same thing
as the target option.
</longdesc>
<shortdesc lang="en">
Client Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="target" required="1">
<longdesc lang="en">
This is either a hostname, a wildcard (IP address or
hostname based), or a netgroup to which defining a
host or hosts to export to.
</longdesc>
<shortdesc lang="en">
Target Hostname, Wildcard, or Netgroup
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="path" inherit="path">
<longdesc lang="en">
This is the path to export to the target. This
field is generally left blank, as it inherits the
path from the parent export.
</longdesc>
<shortdesc lang="en">
Path to Export
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="svcname" inherit="service%name">
<longdesc lang="en">
</longdesc>
<shortdesc lang="en">
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="fsid" inherit="fsid">
<longdesc lang="en">
File system ID inherited from the parent nfsexport/
clusterfs/fs resource. Putting fsid in the options
field will override this.
</longdesc>
<shortdesc lang="en">
File system ID
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="options">
<longdesc lang="en">Defines a list of options for this
particular client. See 'man 5 exports' for a list
of available options.
</longdesc>
<shortdesc lang="en">
Export Options
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="allow_recover">
<longdesc lang="en">
Allows recovery of this NFS client (default = 1) if it
disappears from the export list. If set to 0, the service
will be restarted. This is useful to help preserve export
ordering.
</longdesc>
<shortdesc lang="en">
Allow recovery
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="service_name" inherit="service%name">
<longdesc lang="en">
Service this NFS export belongs to. Used for caching
exports on a per-service basis.
</longdesc>
<shortdesc lang="en">
Service Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="use_cache" inherit="service%nfs_client_cache">
<longdesc lang="en">
On systems with large numbers of exports, a performance
problem in the exportfs command can cause inordinately long
status check times for services with lots of mounted
NFS clients. This occurs because exportfs does DNS queries
on all clients in the export list.
Setting this option to '1' will enable caching of the export
list returned from the exportfs command on a per-service
basis. The cache will last for 30 seconds before expiring
instead of being generated each time an nfsclient resource
is called.
</longdesc>
<shortdesc lang="en">
Enable exportfs list caching
</shortdesc>
<content type="integer"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="90"/>
<action name="stop" timeout="5"/>
<action name="recover" timeout="90"/>
<!-- Checks to see if the export exists in /var/lib/nfs/etab -->
<action name="status" timeout="5" interval="1m"/>
<action name="monitor" timeout="5" interval="1m"/>
<action name="meta-data" timeout="5"/>
<action name="validate-all" timeout="30"/>
</actions>
</resource-agent>
EOT
}
verify_options()
{
declare o
declare -i ret=0
[ -z "$OCF_RESKEY_options" ] && return 0
#
# From exports(5)
#
for o in `echo $OCF_RESKEY_options | sed -e s/,/\ /g`; do
case $o in
fsid=*)
ocf_log debug "Using designated $o instead of fsid=$OCF_RESKEY_fsid"
unset OCF_RESKEY_fsid
;;
secure)
;;
insecure)
;;
sec=*)
;;
rw)
;;
ro)
;;
async)
;;
sync)
;;
wdelay)
;;
no_wdelay)
;;
hide)
;;
nohide)
;;
subtree_check)
;;
no_subtree_check)
;;
secure_locks)
;;
insecure_locks)
;;
auth_nlm)
;;
no_auth_nlm)
;;
mountpoint=*)
;;
mp=*)
;;
root_squash)
;;
no_root_squash)
;;
all_squash)
;;
no_all_squash)
;;
anonuid=*)
;;
anongid=*)
;;
*)
ocf_log err "Export Option $o invalid"
ret=$OCF_ERR_ARGS
;;
esac
done
return $ret
}
verify_target()
{
# XXX need to add wildcards, hostname, ip, etc.
[ -n "$OCF_RESKEY_target" ] && return 0
return $OCF_ERR_ARGS
}
verify_path()
{
if [ -z "$OCF_RESKEY_path" ]; then
ocf_log err "No export path specified."
return $OCF_ERR_ARGS
fi
OCF_RESKEY_path="${OCF_RESKEY_path%/}"
[ -d "$OCF_RESKEY_path" ] && return 0
ocf_log err "$OCF_RESKEY_path is not a directory"
return $OCF_ERR_ARGS
}
verify_type()
{
[ -z "$OCF_RESKEY_type" ] && return 0
[ "$OCF_RESKEY_type" = "nfs" ] && return 0
ocf_log err "Export type $OCF_RESKEY_type not supported yet"
return $OCF_ERR_ARGS
}
verify_all()
{
declare -i ret=0
verify_type || ret=$OCF_ERR_ARGS
verify_options || ret=$OCF_ERR_ARGS
verify_target || ret=$OCF_ERR_ARGS
verify_path || ret=$OCF_ERR_ARGS
return $ret
}
case $1 in
start)
declare option_str
verify_all || exit $OCF_ERR_ARGS
#
# XXX
# Bad: Side-effect of verify_options: unset OCF_RESKEY_fsid if
# fsid is specified in the options string.
#
if [ -z "$OCF_RESKEY_options" ] && [ -n "$OCF_RESKEY_fsid" ]; then
option_str="fsid=$OCF_RESKEY_fsid"
elif [ -n "$OCF_RESKEY_options" ] && [ -z "$OCF_RESKEY_fsid" ]; then
option_str="$OCF_RESKEY_options"
elif [ -n "$OCF_RESKEY_fsid" ] && [ -n "$OCF_RESKEY_options" ]; then
option_str="fsid=$OCF_RESKEY_fsid,$OCF_RESKEY_options"
fi
if [ -z "$option_str" ]; then
ocf_log info "Adding export: ${OCF_RESKEY_target}:${OCF_RESKEY_path}"
exportfs -i "${OCF_RESKEY_target}:${OCF_RESKEY_path}"
rv=$?
else
ocf_log info "Adding export: ${OCF_RESKEY_target}:${OCF_RESKEY_path} ($option_str)"
exportfs -i -o $option_str "${OCF_RESKEY_target}:${OCF_RESKEY_path}"
rv=$?
fi
;;
stop)
verify_all || exit $OCF_ERR_ARGS
ocf_log info "Removing export: ${OCF_RESKEY_target}:${OCF_RESKEY_path}"
exportfs -u "${OCF_RESKEY_target}:${OCF_RESKEY_path}"
rv=$?
;;
status|monitor)
verify_all || exit $OCF_ERR_ARGS
if [ "${OCF_RESKEY_target}" = "*" ]; then
export OCF_RESKEY_target="\<world\>"
fi
#
# Status check fix from Birger Wathne:
# * Exports longer than 14 chars have line breaks inserted, which
# broke the way the status check worked.
#
# Status check fix from Craig Lewis:
# * Exports with RegExp metacharacters need to be escaped.
# These metacharacters are: * ? .
#
export OCF_RESKEY_target_regexp=$(echo $OCF_RESKEY_target | \
sed -e 's/*/[*]/g' -e 's/?/[?]/g' -e 's/\./\\./g')
declare tmpfn
declare time_created time_now
declare -i delta=0
#
# Don't let anyone read the cache files.
#
umask 066
mkdir -p /var/cache/cluster
if [ -n "$OCF_RESKEY_service_name" ] && [ "$OCF_RESKEY_use_cache" = "1" ]; then
#
# For large #s of exports, we need to cache the information
#
tmpfn=/var/cache/cluster/nfsclient-status-cache-$OCF_RESKEY_service_name
if [ -f "$tmpfn" ]; then
time_created=$(stat -c "%Y" $tmpfn)
time_now=$(date +"%s")
delta=$((time_now-time_created))
fi
#echo "Cache age = $delta seconds"
else
delta=100
#
# Create a different file if this is a separate instance
#
tmpfn=/var/cache/cluster/nfsclient-status-cache-$$
fi
if ! [ -f "$tmpfn" ] || [ $delta -gt 30 ]; then
#echo "Create $tmpfn. Nonexistent / expired / no service name"
exportfs -v > $tmpfn
fi
cat $tmpfn | tr -d "\n" | sed -e 's/([^)]*)/\n/g' | grep -Piq \
"^${OCF_RESKEY_path}[\t ]+${OCF_RESKEY_target_regexp}"
rv=$?
if [ $rv -eq 0 ]; then
[ "$OCF_RESKEY_use_cache" = "1" ] || rm -f $tmpfn
exit 0
fi
declare OCF_RESKEY_target_tmp
OCF_RESKEY_target_tmp=$(clufindhostname -i "$OCF_RESKEY_target")
if [ $? -ne 0 ]; then
OCF_RESKEY_target_tmp=$(clufindhostname -n "$OCF_RESKEY_target")
if [ $? -ne 0 ]; then
[ "$OCF_RESKEY_use_cache" = "1" ] || rm -f $tmpfn
ocf_log err "nfsclient:$OCF_RESKEY_name is missing!"
exit 1
fi
fi
cat $tmpfn | tr -d "\n" | sed -e 's/([^)]*)/\n/g' | grep -Pq \
"^${OCF_RESKEY_path}[\t ]+${OCF_RESKEY_target_tmp}"
rv=$?
[ "$OCF_RESKEY_use_cache" = "1" ] || rm -f $tmpfn
if [ $rv -eq 0 ]; then
exit 0
fi
ocf_log err "nfsclient:$OCF_RESKEY_name is missing!"
exit $OCF_NOT_RUNNING
;;
recover)
if [ "$OCF_RESKEY_allow_recover" = "0" ] || \
[ "$OCF_RESKEY_allow_recover" = "no" ] || \
[ "$OCF_RESKEY_allow_recover" = "false" ]; then
exit 1
fi
$0 stop || exit 1
$0 start || exit 1
;;
restart)
#
# Recover might better be "exportfs -r" - reexport
#
$0 stop || exit 1
$0 start || exit 1
;;
meta-data)
meta_data
exit 0
;;
validate-all)
verify_all
rv=$?
;;
*)
echo "usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
rv=$OCF_ERR_UNIMPLEMENTED
;;
esac
exit $rv
diff --git a/rgmanager/src/resources/nfsexport.sh b/rgmanager/src/resources/nfsexport.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/nfsexport.sh
rename to rgmanager/src/resources/nfsexport.sh.in
index f69eab58d..26084a2fe
--- a/rgmanager/src/resources/nfsexport.sh
+++ b/rgmanager/src/resources/nfsexport.sh.in
@@ -1,256 +1,256 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# NFS Export Script. Handles starting/stopping clurmtabd and doing
# the strange NFS stuff to get it to fail over properly.
#
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
LC_ALL=C
LANG=C
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LC_ALL LANG PATH
. $(dirname $0)/ocf-shellfuncs
rmtabpid=""
nfsop_arg=""
rv=0
meta_data()
{
cat <<EOT
<?xml version="1.0" ?>
<resource-agent name="nfsexport" version="rgmanager 2.0">
<version>1.0</version>
<longdesc lang="en">
This defines an NFS export path. Generally, these are
defined inline and implicitly; you should not have to
configure one of these. All of the relevant information
is inherited from the parent.
</longdesc>
<shortdesc lang="en">
This defines an NFS export.
</shortdesc>
<parameters>
<parameter name="name" primary="1">
<longdesc lang="en">
Descriptive name for this export. Generally, only
one export is ever defined, and it's called "generic
nfs export".
</longdesc>
<shortdesc lang="en">
Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="device" inherit="device">
<longdesc lang="en">
If you can see this, your GUI is broken.
</longdesc>
<shortdesc lang="en">
If you can see this, your GUI is broken.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="path" inherit="mountpoint">
<longdesc lang="en">
If you can see this, your GUI is broken.
</longdesc>
<shortdesc lang="en">
If you can see this, your GUI is broken.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="fsid" inherit="fsid">
<longdesc lang="en">
If you can see this, your GUI is broken.
</longdesc>
<shortdesc lang="en">
If you can see this, your GUI is broken.
</shortdesc>
<content type="string"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="5"/>
<action name="stop" timeout="5"/>
<action name="recover" timeout="5"/>
<!-- NFS Exports really don't do anything except provide a path
for nfs clients. So, status and monitor are no-ops -->
<action name="status" timeout="5" interval="1h"/>
<action name="monitor" timeout="5" interval="1h"/>
<action name="meta-data" timeout="5"/>
<action name="validate-all" timeout="30"/>
</actions>
<special tag="rgmanager">
<child type="nfsexport" forbid="1"/>
<child type="nfsclient"/>
</special>
</resource-agent>
EOT
}
verify_device()
{
if [ -z "$OCF_RESKEY_device" ]; then
ocf_log err "No device or label specified."
return $OCF_ERR_ARGS
fi
[ -b "$OCF_RESKEY_device" ] && return 0
[ -b "`findfs $OCF_RESKEY_device`" ] && return 0
ocf_log err "Device or label \"$OCF_RESKEY_device\" not valid"
return $OCF_ERR_ARGS
}
verify_path()
{
if [ -z "$OCF_RESKEY_path" ]; then
ocf_log err "No export path specified."
return $OCF_ERR_ARGS
fi
[ -d "$OCF_RESKEY_path" ] && return 0
ocf_log err "$OCF_RESKEY_path is not a directory"
return $OCF_ERR_ARGS
}
verify_all()
{
declare -i ret=0
verify_device || ret=$OCF_ERR_ARGS
verify_path || ret=$OCF_ERR_ARGS
return $ret
}
#
# Check if the NFS daemons are running.
#
nfs_daemons_running()
{
declare NFS_DAEMONS="nfsd rpc.mountd rpc.statd"
for daemon in $NFS_DAEMONS; do
ps -ef | grep "$daemon" | grep -v grep >/dev/null 2>&1
if [ $? -ne 0 ]; then
ocf_log err \
"NFS daemon $daemon is not running."
ocf_log err \
"Verify that the NFS service run level script is enabled."
return 1
fi
done
return 0
}
nfs_check()
{
declare junk
if nfs_daemons_running; then
return 0
fi
#
# Don't restart daemons during status check.
#
if [ "$1" = "status" ]; then
return 1;
fi
ocf_log err "Restarting NFS daemons"
# Note restart does less than stop/start
junk=$(/sbin/service nfslock stop)
junk=$(/sbin/service nfslock start)
junk=$(/sbin/service nfs stop)
junk=$(/sbin/service nfs start)
sleep 2
if ! nfs_daemons_running; then
ocf_log err "Failed restarting NFS daemons"
return 1
fi
ocf_log notice "Successfully restarted NFS daemons"
}
case $1 in
start)
nfs_check start || exit 1
rv=0
;;
status|monitor)
nfs_check status || exit 1
rv=0
;;
stop)
nfs_check restart || exit 1
rv=0
;;
recover|restart)
$0 stop || exit $OCF_ERR_GENERIC
$0 start || exit $OCF_ERR_GENERIC
rv=0
;;
meta-data)
meta_data
rv=0
;;
validate-all)
verify_all
rv=$?
;;
*)
echo "usage: $0 {start|status|monitor|stop|recover|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit $rv
diff --git a/rgmanager/src/resources/nfsserver.sh b/rgmanager/src/resources/nfsserver.sh.in
similarity index 97%
rename from rgmanager/src/resources/nfsserver.sh
rename to rgmanager/src/resources/nfsserver.sh.in
index 04911c7c3..e7130f054 100644
--- a/rgmanager/src/resources/nfsserver.sh
+++ b/rgmanager/src/resources/nfsserver.sh.in
@@ -1,611 +1,611 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# NFS Server Script. Handles starting/stopping Servand doing
# the strange NFS stuff to get it to fail over properly.
#
LC_ALL=C
LANG=C
PATH=/bin:/sbin:/usr/bin:/usr/sbin
V4RECOVERY="/var/lib/nfs/v4recovery"
PROC_V4RECOVERY="/proc/fs/nfsd/nfsv4recoverydir"
export LC_ALL LANG PATH
. $(dirname $0)/ocf-shellfuncs
# SELinux information
which restorecon &> /dev/null && selinuxenabled &> /dev/null
export SELINUX_ENABLED=$?
if [ $SELINUX_ENABLED ]; then
export SELINUX_LABEL="$(ls -ldZ /var/lib/nfs/statd | cut -f4 -d' ')"
fi
# strip trailing / off so pattern matching will work consistently.
while [ "${OCF_RESKEY_path#${OCF_RESKEY_path%?}}" = "/" ]
do
OCF_RESKEY_path="${OCF_RESKEY_path%/}"
done
log_do()
{
ocf_log debug $*
$* &> /dev/null
ret=$?
if [ $ret -ne 0 ]; then
ocf_log debug "Failed: $*"
fi
return $ret
}
meta_data()
{
cat <<EOT
<?xml version="1.0" ?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1-modified.dtd">
<resource-agent name="nfsserver" version="rgmanager 2.0">
<version>1.0</version>
<longdesc lang="en">
This defines an NFS server resource. The NFS server
resource is useful for exporting NFSv4 file systems
to clients. Because of the way NFSv4 works, only
one NFSv4 resource may exist on a server at a
time. Additionally, it is not possible to use
the nfsserver resource when also using local instances
of NFS on each cluster node.
</longdesc>
<shortdesc lang="en">
This defines an NFS server resource.
</shortdesc>
<parameters>
<parameter name="name" primary="1">
<longdesc lang="en">
Descriptive name for this server. Generally, only
one server is ever defined per service.
</longdesc>
<shortdesc lang="en">
Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="path" inherit="mountpoint">
<longdesc lang="en">
This is the path you intend to export. Usually, this is
left blank, and the mountpoint of the parent file system
is used. This path is passed to nfsclient resources as
the export path when exportfs is called.
</longdesc>
<shortdesc lang="en">
This is the path you intend to export.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="nfspath">
<longdesc lang="en">
This is the path containing shared NFS information which
is used for NFS recovery after a failover. This
is relative to the export path, and defaults to
".clumanager/nfs".
</longdesc>
<shortdesc lang="en">
This is the path containing shared NFS recovery
information, relative to the path parameter.
</shortdesc>
<content type="string" default=".clumanager/nfs"/>
</parameter>
<parameter name="statdport">
<longdesc lang="en">
Specifies the port number used for RPC listener sockets. If
this option is not specified, rpc.statd chooses a random
ephemeral port for each listener socket. This option can be
used to fix the port value of its listeners when SM_NOTIFY
requests must traverse a firewall between
clients and servers.
</longdesc>
<shortdesc lang="en">
This is the port where rpc.statd should listen on.
</shortdesc>
<content type="integer" default=""/>
</parameter>
<parameter name="krbhost">
<longdesc lang="en">
This is the Kerberos hostname, which should be set according
to the floating IP.
</longdesc>
<shortdesc lang="en">
This is the Kerberos hostname.
</shortdesc>
<content type="string"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="5"/>
<action name="stop" timeout="5"/>
<action name="recover" timeout="5"/>
<action name="status" timeout="5" interval="30"/>
<action name="monitor" timeout="5" interval="30"/>
<action name="meta-data" timeout="5"/>
<action name="validate-all" timeout="30"/>
</actions>
<special tag="rgmanager">
<attributes maxinstances="1"/>
<child type="nfsexport" forbid="1"/>
<child type="nfsserver" forbid="1"/>
<child type="nfsclient" start="1" stop="2"/>
<child type="ip" start="2" stop="1"/>
</special>
</resource-agent>
EOT
}
verify_path()
{
if [ -z "$OCF_RESKEY_path" ]; then
ocf_log err "No server path specified."
return $OCF_ERR_ARGS
fi
[ -d "$OCF_RESKEY_path" ] && return 0
ocf_log err "$OCF_RESKEY_path is not a directory"
return $OCF_ERR_ARGS
}
verify_nfspath()
{
if [ -z "$OCF_RESKEY_nfspath" ]; then
echo No NFS data path specified.
return 1
fi
[ -d "$OCF_RESKEY_path" ] && return 0
# xxx do nothing for now.
return 0
}
verify_statdport()
{
if [ -z "$OCF_RESKEY_statdport" ]; then
# this is fine, statdport is optional
return 0
fi
[ $OCF_RESKEY_statdport -gt 0 && $OCF_RESKEY_statdport -le 65535 ] && return 0
ocf_log err "$OCF_RESKEY_statdport is not a valid port number"
return $OCF_ERR_ARGS
}
verify_all()
{
verify_path || return 1
verify_nfspath || return 1
verify_statdport || return 1
return 0
}
nfs_daemons()
{
declare oper
declare val
case $1 in
start)
ocf_log info "Starting NFS daemons"
if [ -z "$OCF_RESKEY_krbhost" ]; then
/etc/init.d/nfs start
rv=$?
else
- unshare -u /bin/bash -c "hostname $OCF_RESKEY_krbhost; /etc/init.d/nfs start"
+ unshare -u @BASH_SHELL@ -c "hostname $OCF_RESKEY_krbhost; /etc/init.d/nfs start"
rv=$?
- unshare -u /bin/bash -c "hostname $OCF_RESKEY_krbhost; /etc/init.d/rpcgssd start"
+ unshare -u @BASH_SHELL@ -c "hostname $OCF_RESKEY_krbhost; /etc/init.d/rpcgssd start"
if [ $rv -ne 0 ]; then
ocf_log err "Failed to start rpcgssd"
return $OCF_ERR_GENERIC
fi
- unshare -u /bin/bash -c "hostname $OCF_RESKEY_krbhost; /etc/init.d/rpcidmapd start"
+ unshare -u @BASH_SHELL@ -c "hostname $OCF_RESKEY_krbhost; /etc/init.d/rpcidmapd start"
if [ $rv -ne 0 ]; then
ocf_log err "Failed to start rpcidmapd"
return $OCF_ERR_GENERIC
fi
fi
if [ $rv -ne 0 ]; then
ocf_log err "Failed to start NFS daemons"
return $OCF_ERR_GENERIC
fi
ocf_log debug "NFS daemons are running"
return $OCF_SUCCESS
;;
stop)
ocf_log info "Stopping NFS daemons"
if [ -n "$OCF_RESKEY_krbhost"]; then
if ! /etc/init.d/rpcidmapd stop; then
ocf_log err "Failed to stop rpcidmapd"
return $OCF_ERR_GENERIC
fi
if ! /etc/init.d/rpcgssd stop; then
ocf_log err "Failed to stop rpcgssd"
return $OCF_ERR_GENERIC
fi
fi
if ! /etc/init.d/nfs stop; then
ocf_log err "Failed to stop NFS daemons"
return $OCF_ERR_GENERIC
fi
ocf_log debug "NFS daemons are stopped"
return $OCF_SUCCESS
;;
status|monitor)
declare recoverydir="$OCF_RESKEY_path/$OCF_RESKEY_nfspath/v4recovery"
val=$(cat $PROC_V4RECOVERY)
[ "$val" = "$recoverydir" ] || ocf_log warning \
"NFSv4 recovery directory is $val instead of $recoverydir"
/etc/init.d/nfs status
if [ $? -ne 0 ]; then
ocf_log err "NFS is not running"
return $OCF_NOT_RUNNING
fi
/etc/init.d/rpcgssd status
if [ $? -ne 0 ]; then
ocf_log err "rpcgssd is not running"
return $OCF_NOT_RUNNING
fi
/etc/init.d/rpcidmapd status
if [ $? -ne 0 ]; then
ocf_log err "rpcidmapd is not running"
return $OCF_NOT_RUNNING
fi
ocf_log debug "NFS daemons are running"
return $OCF_SUCCESS
;;
esac
}
create_tree()
{
declare fp="$OCF_RESKEY_path/$OCF_RESKEY_nfspath"
[ -d "$fp" ] || mkdir -p "$fp"
[ -d "$fp/statd" ] || mkdir -p "$fp/statd"
[ -d "$fp/v4recovery" ] || mkdir -p "$fp/v4recovery"
#
# Create our own private copy which we use for notifies.
# This way, we can be sure to advertise on possibly multiple
# IP addresses.
#
[ -d "$fp/statd/sm" ] || mkdir -p "$fp/statd/sm"
[ -d "$fp/statd/sm.bak" ] || mkdir -p "$fp/statd/sm.bak"
[ -d "$fp/statd/sm-ha" ] || mkdir -p "$fp/statd/sm-ha"
[ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown -R rpcuser.rpcuser "$fp/statd"
# Create if they don't exist
[ -f "$fp/etab" ] || touch "$fp/etab"
[ -f "$fp/xtab" ] || touch "$fp/xtab"
[ -f "$fp/rmtab" ] || touch "$fp/rmtab"
[ $SELINUX_ENABLED ] && chcon -R "$SELINUX_LABEL" "$fp"
#
# Generate a random state file. If this ends up being what a client
# already has in its list, that's bad, but the chances of this
# are small - and relocations should be rare.
#
dd if=/dev/urandom of=$fp/state bs=1 count=4 &> /dev/null
[ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown rpcuser.rpcuser "$fp/state"
}
setup_v4recovery()
{
declare recoverydir="$OCF_RESKEY_path/$OCF_RESKEY_nfspath/v4recovery"
# mounts /proc/fs/nfsd for us
lsmod | grep -q nfsd
if [ $? -ne 0 ]; then
modprobe nfsd
fi
val=$(cat "$PROC_V4RECOVERY")
# Ensure start-after-start works
if [ "$val" = "$recoverydir" ]; then
return 0
fi
#
# If the value is not default, there may be another
# cluster service here already which has replaced
# the v4 recovery directory. In that case,
# we must refuse to go any further.
#
if [ "$val" != "$V4RECOVERY" ]; then
ocf_log err "NFSv4 recovery directory has an unexpected value: $val"
return 1
fi
#
# Redirect nfs v4 recovery dir to shared storage
#
echo "$recoverydir" > "$PROC_V4RECOVERY"
if [ $? -ne 0 ]; then
echo "Uh oh... echo failed!?"
fi
val="$(cat $PROC_V4RECOVERY)"
if [ "$val" != "$recoverydir" ]; then
ocf_log err "Failed to change NFSv4 recovery path"
ocf_log err "Wanted: $recoverydir; got $val"
return 1
fi
return 0
}
cleanup_v4recovery()
{
#
# Restore nfsv4 recovery directory to default
#
echo "$V4RECOVERY" > "$PROC_V4RECOVERY"
return $?
}
is_bound()
{
mount | grep -q "$1 on $2 type none (.*bind.*)"
return $?
}
setup_tree()
{
declare fp="$OCF_RESKEY_path/$OCF_RESKEY_nfspath"
if is_bound $fp/statd /var/lib/nfs/statd; then
ocf_log debug "$fp is already bound to /var/lib/nfs/statd"
return 0
fi
mount -o bind "$fp/statd" /var/lib/nfs/statd
cp -a "$fp"/*tab /var/lib/nfs
[ $SELINUX_ENABLED ] && restorecon /var/lib/nfs
}
cleanup_tree()
{
declare fp="$OCF_RESKEY_path/$OCF_RESKEY_nfspath"
if is_bound "$fp/statd" /var/lib/nfs/statd; then
log_do umount /var/lib/nfs/statd || return 1
else
ocf_log debug "$fp is not bound to /var/lib/nfs/statd"
fi
cp -a /var/lib/nfs/*tab "$fp"
return 0
}
start_locking()
{
declare ret
declare statdport=""
[ -x /sbin/rpc.statd ] || return 1
#
# Synchronize these before starting statd
#
cp -f /var/lib/nfs/statd/sm-ha/* /var/lib/nfs/statd/sm 2> /dev/null
cp -f /var/lib/nfs/statd/sm/* /var/lib/nfs/statd/sm-ha 2> /dev/null
if pidof rpc.statd &> /dev/null; then
ocf_log debug "rpc.statd is already running"
return 0
fi
if [ -n "$OCF_RESKEY_statdport" ]; then
statdport="-p $OCF_RESKEY_statdport"
fi
#
# Set this resrouce script as the callout program. We are evil.
# In cases where we want to preserve lock information, this is needed
# because we can't do the "copy" that we do on the down-state...
#
ocf_log info "Starting rpc.statd"
rm -f /var/run/sm-notify.pid
rpc.statd -H $0 -d $statdport
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=$(pidof $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=$(pidof $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
}
stop_locking()
{
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=1
fi
stop_process rpc.statd
if [ $? -ne 0 ]; then
ret=1
fi
return $ret
}
case $1 in
start)
# Check for and source configuration file
ocf_log info "Starting NFS Server $OCF_RESKEY_name"
create_tree || exit 1
setup_tree || exit 1
setup_v4recovery || exit 1
start_locking
nfs_daemons start
rv=$?
if [ $rv -eq 0 ]; then
ocf_log info "Started NFS Server $OCF_RESKEY_name"
exit 0
fi
ocf_log err "Failed to start NFS Server $OCF_RESKEY_name"
exit $rv
;;
status|monitor)
nfs_daemons status
exit $?
;;
stop)
if ! nfs_daemons stop; then
ocf_log err "Failed to stop NFS Server $OCF_RESKEY_name"
exit $OCF_ERR_GENERIC
fi
# Copy the current notify list into our private area
ocf_log debug "Copying sm files for future notification..."
rm -f /var/lib/nfs/statd/sm-ha/* &> /dev/null
cp -f /var/lib/nfs/statd/sm/* /var/lib/nfs/statd/sm-ha &> /dev/null
stop_locking || exit 1
cleanup_v4recovery
cleanup_tree || exit 1
exit 0
;;
add-client)
ocf_log debug "$0 $1 $2 $3"
touch /var/lib/nfs/statd/sm/$2
touch /var/lib/nfs/statd/sm-ha/$2
exit 0
;;
del-client)
ocf_log debug "$0 $1 $2 $3"
touch /var/lib/nfs/statd/sm/$2
rm -f /var/lib/nfs/statd/sm-ha/$2
exit 0
;;
recover|restart)
$0 stop || exit $OCF_ERR_GENERIC
$0 start || exit $OCF_ERR_GENERIC
exit 0
;;
meta-data)
meta_data
exit 0
;;
validate-all)
verify_all
exit $?
;;
*)
echo "usage: $0 {start|stop|status|monitor|restart|recover|add-client|del-client|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit 0
diff --git a/rgmanager/src/resources/ocf-shellfuncs b/rgmanager/src/resources/ocf-shellfuncs.in
similarity index 99%
rename from rgmanager/src/resources/ocf-shellfuncs
rename to rgmanager/src/resources/ocf-shellfuncs.in
index 97097f73c..e895f5d42 100644
--- a/rgmanager/src/resources/ocf-shellfuncs
+++ b/rgmanager/src/resources/ocf-shellfuncs.in
@@ -1,167 +1,167 @@
-#! /bin/bash
+#!@BASH_SHELL@
#
# $Id$
#
# Common helper functions for the OCF Resource Agents supplied by
# heartbeat.
#
# Copyright (C) 2004 SUSE LINUX AG, Lars Marowsky-Bree. All Rights Reserved.
#
# 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.
#
__SCRIPT_NAME=`basename $0`
# lhh - determine if we're a dumb terminal
consoletype &> /dev/null
if [ $? -eq 1 ]; then
__SERIAL="yes"
fi
__LOG_PID=$PPID
__LOG_NAME=$(basename $(readlink /proc/$PPID/exe))
pretty_echo() {
declare pretty
declare n=""
declare __OCF_PRIO="$1"
shift
declare __OCF_MSG="$*"
if [ -n "$__SERIAL" ]; then
echo "<$__OCF_PRIO> $__OCF_MSG"
return 0
fi
case $__OCF_PRIO in
emerg) pretty="";;
alert) pretty="";;
crit|critical) pretty="";;
err|error) pretty="";;
warn|warning) pretty="";;
note|notice) pretty="";;
info) pretty="";;
debug|dbg) pretty="";;
*) pretty="";;
esac
echo "$n<$pretty$__OCF_PRIO$n> $__OCF_MSG"
return 0
}
__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...
OCF_SUCCESS=0
OCF_ERR_GENERIC=1
OCF_ERR_ARGS=2
OCF_ERR_UNIMPLEMENTED=3
OCF_ERR_PERM=4
OCF_ERR_INSTALLED=5
OCF_ERR_CONFIGURED=6
OCF_NOT_RUNNING=7
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 [ -z "$OCF_ROOT" ]; then
OCF_ROOT=$(dirname $0)
fi
if [ ! -d "$OCF_ROOT" ]; then
ocf_log err "OCF_ROOT points to non-directory $OCF_ROOT."
exit $OCF_ERR_GENERIC
fi
# TODO: Anything else we should be setting and thus checking?
# There is nothing in this script which depends on the version
# of the API. TESTING THIS HERE IS A BUG. THIS SHOULD BE
# tested by the script that's invoked us. FIXME!!
if [ "x$OCF_RA_VERSION_MAJOR" != "x1" ]; then
ocf_log err "This script is OCF RA API 1.x compliant only!"
exit $OCF_ERR_UNIMPLEMENTED
fi
# TODO: Should the minor level really be a number and not rather
# a list of flags...?
# AlanR says -- absolutely not -- a list of flags is good for a list
# of implemented features, not a version compiliance
# perhaps some future version might have such a list of
# flags, but that would be _in addition to_ the minor version number
if [ -z "$OCF_RA_VERSION_MINOR" ]; then
ocf_log err "No OCF RA minor version set."
exit $OCF_ERR_UNIMPLEMENTED
fi
if [ "x$__OCF_ACTION" = "xmeta-data" ]; then
OCF_RESOURCE_INSTANCE="undef"
fi
if [ -z "$OCF_RESOURCE_INSTANCE" ]; then
ocf_log err "Need to tell us our resource instance name."
exit $OCF_ERR_ARGS
fi
}
ocf_log() {
# TODO: Revisit and implement internally.
if
[ $# -lt 2 ]
then
ocf_log err "Not enough arguments [$#] to ocf_log."
fi
declare __OCF_PRIO="$1"
declare -i __OCF_PRIO_N
shift
declare __OCF_MSG="$*"
case "${__OCF_PRIO}" in
emerg) __OCF_PRIO_N=0;; # Not in original ocf-shellfuncs
alert) __OCF_PRIO_N=1;; # Not in original ocf-shellfuncs
crit|critical) __OCF_PRIO_N=2;;
err|error) __OCF_PRIO_N=3;;
warn|warning) __OCF_PRIO_N=4;;
note|notice) __OCF_PRIO_N=5;; # Not in original ocf-shellfuncs
info) __OCF_PRIO_N=6;;
debug|dbg) __OCF_PRIO_N=7;;
*) __OCF_PRIO_N=5;; # Defaults to INFO
esac
pretty_echo $__OCF_PRIO "$__OCF_MSG"
if [ -z "`which clulog 2> /dev/null`" ]; then
return 0
fi
clulog -m "$OCF_RESOURCE_TYPE" -s $__OCF_PRIO_N "$__OCF_MSG"
}
__ocf_set_defaults "$@"
diff --git a/rgmanager/src/resources/openldap.sh b/rgmanager/src/resources/openldap.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/openldap.sh
rename to rgmanager/src/resources/openldap.sh.in
index 0df81d249..62377c6e3
--- a/rgmanager/src/resources/openldap.sh
+++ b/rgmanager/src/resources/openldap.sh.in
@@ -1,227 +1,227 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
export LC_ALL=C
export LANG=C
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
declare LDAP_SLAPD=/usr/sbin/slapd
declare LDAP_pid_file="`generate_name_for_pid_file`"
declare LDAP_conf_dir="`generate_name_for_conf_dir`"
declare LDAP_gen_config_file="$LDAP_conf_dir/slapd.conf"
declare LDAP_url_list
verify_all()
{
clog_service_verify $CLOG_INIT
if [ -z "$OCF_RESKEY_name" ]; then
clog_service_verify $CLOG_FAILED "Invalid Name Of Service"
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_service_name" ]; then
clog_service_verify $CLOG_FAILED_NOT_CHILD
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_INVALID "$OCF_RESKEY_config_file"
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
if [ ! -r "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_NOT_READABLE $OCF_RESKEY_config_file
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
clog_service_verify $CLOG_SUCCEED
return 0
}
generate_url_list()
{
declare ldap_url_source=$1
declare ip_addresses=$2
declare url_list
declare tmp;
for u in $ldap_url_source; do
if [[ "$u" =~ ':///' ]]; then
for z in $ip_addresses; do
tmp=`echo $u | sed "s,://,://$z,"`
url_list="$url_list $tmp"
done
elif [[ "$u" =~ '://0:' ]]; then
for z in $ip_addresses; do
tmp=`echo $u | sed "s,://0:,://$z:,"`
url_list="$url_list $tmp"
done
else
url_list="$url_list $u"
fi
done
echo $url_list
}
generate_config_file()
{
declare original_file="$1"
declare generated_file="$2"
if [ -f "$generated_file" ]; then
sha1_verify "$generated_file"
if [ $? -ne 0 ]; then
clog_check_sha1 $CLOG_FAILED
return 0
fi
fi
clog_generate_config $CLOG_INIT "$original_file" "$generated_file"
generate_configTemplate "$generated_file" "$1"
echo "pidfile \"$LDAP_pid_file\"" >> $generated_file
echo >> $generated_file
sed 's/^[[:space:]]*pidfile/### pidfile/i' < "$original_file" >> "$generated_file"
sha1_addToFile "$generated_file"
clog_generate_config $CLOG_SUCCEED "$original_file" "$generated_file"
return 0;
}
start()
{
clog_service_start $CLOG_INIT
create_pid_directory
create_conf_directory "$LDAP_conf_dir"
check_pid_file "$LDAP_pid_file"
if [ $? -ne 0 ]; then
clog_check_pid $CLOG_FAILED "$LDAP_pid_file"
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_INIT "IP Addresses"
get_service_ip_keys "$OCF_RESKEY_service_name"
ip_addresses=`build_ip_list`
if [ -z "$ip_addresses" ]; then
clog_looking_for $CLOG_FAILED_NOT_FOUND "IP Addresses"
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_SUCCEED "IP Addresses"
LDAP_url_list=`generate_url_list "$OCF_RESKEY_url_list" "$ip_addresses"`
if [ -z "$LDAP_url_list" ]; then
ocf_log error "Generating URL List for $OCF_RESOURCE_INSTANCE > Failed"
return $OCF_ERR_GENERIC
fi
generate_config_file "$OCF_RESKEY_config_file" "$LDAP_gen_config_file"
$LDAP_SLAPD -f "$LDAP_gen_config_file" -n "$OCF_RESOURCE_INSTANCE" \
-h "$LDAP_url_list" $OCF_RESKEY_slapd_options
if [ $? -ne 0 ]; then
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_service_start $CLOG_SUCCEED
return 0;
}
stop()
{
clog_service_stop $CLOG_INIT
stop_generic "$LDAP_pid_file" "$OCF_RESKEY_shutdown_wait"
if [ $? -ne 0 ]; then
clog_service_stop $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_service_stop $CLOG_SUCCEED
return 0;
}
status()
{
clog_service_status $CLOG_INIT
status_check_pid "$LDAP_pid_file"
if [ $? -ne 0 ]; then
clog_service_status $CLOG_FAILED "$LDAP_pid_file"
return $OCF_ERR_GENERIC
fi
clog_service_status $CLOG_SUCCEED
return 0
}
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
exit 0
;;
validate-all)
verify_all
exit $?
;;
start)
verify_all && start
exit $?
;;
stop)
verify_all && stop
exit $?
;;
status|monitor)
verify_all
status
exit $?
;;
restart)
verify_all
stop
start
exit $?
;;
*)
echo "Usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/oracledb.sh b/rgmanager/src/resources/oracledb.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/oracledb.sh
rename to rgmanager/src/resources/oracledb.sh.in
index a27a55f11..0ff4d4a1e
--- a/rgmanager/src/resources/oracledb.sh
+++ b/rgmanager/src/resources/oracledb.sh.in
@@ -1,1031 +1,1031 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Author(s):
# Hardy Merrill <hmerrill at redhat.com>
# Lon Hohberger <lhh at redhat.com>
# Michael Moon <Michael dot Moon at oracle.com>
# Ryan McCabe <rmccabe at redhat.com>
#
# NOTES:
#
# (1) You can comment out the LOCKFILE declaration below. This will prevent
# the need for this script to access anything outside of the ORACLE_HOME
# path.
#
# (2) You MUST customize ORACLE_USER, ORACLE_HOME, ORACLE_SID, and
# ORACLE_HOSTNAME to match your installation if not running from within
# rgmanager.
#
# (3) Do NOT place this script in shared storage; place it in ORACLE_USER's
# home directory in non-clustered environments and /usr/share/cluster
# in rgmanager/Red Hat cluster environments.
#
# Oracle is a registered trademark of Oracle Corporation.
# Oracle9i is a trademark of Oracle Corporation.
# Oracle10g is a trademark of Oracle Corporation.
# Oracle11g is a trademark of Oracle Corporation.
# All other trademarks are property of their respective owners.
#
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
. /etc/init.d/functions
declare SCRIPT="`basename $0`"
declare SCRIPTDIR="`dirname $0`"
[ -n "$OCF_RESKEY_user" ] && ORACLE_USER=$OCF_RESKEY_user
[ -n "$OCF_RESKEY_home" ] && ORACLE_HOME=$OCF_RESKEY_home
[ -n "$OCF_RESKEY_name" ] && ORACLE_SID=$OCF_RESKEY_name
[ -n "$OCF_RESKEY_listener_name" ] && ORACLE_LISTENER=$OCF_RESKEY_listener_name
[ -n "$OCF_RESKEY_lockfile" ] && LOCKFILE=$OCF_RESKEY_lockfile
[ -n "$OCF_RESKEY_type" ] && ORACLE_TYPE=$OCF_RESKEY_type
[ -n "$OCF_RESKEY_vhost" ] && ORACLE_HOSTNAME=$OCF_RESKEY_vhost
[ -n "$OCF_RESKEY_tns_admin" ] && export TNS_ADMIN=$OCF_RESKEY_tns_admin
######################################################
# Customize these to match your Oracle installation. #
######################################################
#
# 1. Oracle user. Must be the same across all cluster members. In the event
# that this script is run by the super-user, it will automatically switch
# to the Oracle user and restart. Oracle needs to run as the Oracle
# user, not as root.
#
#[ -n "$ORACLE_USER" ] || ORACLE_USER=oracle
#
# 2. Oracle home. This is set up during the installation phase of Oracle.
# From the perspective of the cluster, this is generally the mount point
# you intend to use as the mount point for your Oracle Infrastructure
# service.
#
#[ -n "$ORACLE_HOME" ] || ORACLE_HOME=/mnt/oracle/home
#
# 3. This is your SID. This is set up during oracle installation as well.
#
#[ -n "$ORACLE_SID" ] || ORACLE_SID=orcl
#
# 4. The oracle user probably doesn't have the permission to write to
# /var/lock/subsys, so use the user's home directory.
#
#[ -n "$LOCKFILE" ] || LOCKFILE="/home/$ORACLE_USER/.oracle-ias.lock"
[ -n "$LOCKFILE" ] || LOCKFILE="$ORACLE_HOME/.oracle-ias.lock"
#[ -n "$LOCKFILE" ] || LOCKFILE="/var/lock/subsys/oracle-ias" # Watch privileges
#
# 5. Type of Oracle Database. Currently supported: 10g 10g-iAS(untested!)
#
[ -n "$ORACLE_TYPE" ] || ORACLE_TYPE="base-em"
#
# 6. Oracle virtual hostname. This is the hostname you gave Oracle during
# installation.
#
#[ -n "$ORACLE_HOSTNAME" ] || ORACLE_HOSTNAME=svc0.foo.test.com
###########################################################################
ORACLE_TYPE=`echo $ORACLE_TYPE | tr A-Z a-z`
export ORACLE_USER ORACLE_HOME ORACLE_SID LOCKFILE ORACLE_TYPE
export ORACLE_HOSTNAME
##########################
# Set up paths we'll use. Not all are used by all the different types of
# Oracle installations
#
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$ORACLE_HOME/opmn/lib
export PATH=$ORACLE_HOME/bin:$ORACLE_HOME/opmn/bin:$ORACLE_HOME/dcm/bin:$PATH
declare -i RESTART_RETRIES=0
declare -r DB_PROCNAMES="pmon"
#declare -r DB_PROCNAMES="pmonXX" # testing
#declare -r DB_PROCNAMES="pmon smon dbw0 lgwr"
declare -r LSNR_PROCNAME="tnslsnr"
#declare -r LSNR_PROCNAME="tnslsnrXX" # testing
# clulog will not log messages when run by the oracle user.
# This is a hack to work around that.
if [ "`id -u`" = "`id -u $ORACLE_USER`" ]; then
ocf_log() {
prio=$1
shift
logger -i -p daemon."$prio" -- "$*"
}
fi
##########################################################
# (Hopefully) No user-serviceable parts below this line. #
##########################################################
meta_data()
{
cat <<EOT
<?xml version="1.0" ?>
<resource-agent name="oracledb" version="rgmanager 2.0">
<version>1.0</version>
<longdesc lang="en">
Oracle 10g/11g Failover Instance
</longdesc>
<shortdesc lang="en">
Oracle 10g/11g Failover Instance
</shortdesc>
<parameters>
<parameter name="name" primary="1">
<longdesc lang="en">
Instance name (SID) of oracle instance
</longdesc>
<shortdesc lang="en">
Oracle SID
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="listener_name" unique="1">
<longdesc lang="en">
Oracle Listener Instance Name. If you have multiple
instances of Oracle running, it may be necessary to
have multiple listeners on the same machine with
different names.
</longdesc>
<shortdesc lang="en">
Oracle Listener Instance Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="user" required="1">
<longdesc lang="en">
Oracle user name. This is the user name of the Oracle
user which the Oracle AS instance runs as.
</longdesc>
<shortdesc lang="en">
Oracle User Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="home" required="1">
<longdesc lang="en">
This is the Oracle (application, not user) home directory.
This is configured when you install Oracle.
</longdesc>
<shortdesc lang="en">
Oracle Home Directory
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="type" required="0">
<longdesc lang="en">
This is the Oracle installation type:
base - Database Instance and Listener only
base-11g - Oracle11g Database Instance and Listener Only
base-em (or 10g) - Database, Listener, Enterprise Manager,
and iSQL*Plus
base-em-11g - Database, Listener, Enterprise Manager dbconsole
ias (or 10g-ias) - Internet Application Server (Infrastructure)
</longdesc>
<shortdesc lang="en">
Oracle Installation Type
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="vhost" required="0" unique="1">
<longdesc lang="en">
Virtual Hostname matching the installation hostname of
Oracle 10g. Note that during the start/stop of an oracledb
resource, your hostname will temporarily be changed to
this hostname. As such, it is recommended that oracledb
resources be instanced as part of an exclusive service only.
</longdesc>
<shortdesc lang="en">
Virtual Hostname
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="tns_admin" required="0" unique="1">
<longdesc lang="en">
Full path to the directory that contains the Oracle
listener tnsnames.ora configuration file. The shell
variable TNS_ADMIN is set to the value provided.
</longdesc>
<shortdesc lang="en">
Full path to the directory containing tnsnames.ora
</shortdesc>
<content type="string"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="900"/>
<action name="stop" timeout="90"/>
<action name="recover" timeout="990"/>
<!-- Checks to see if it's mounted in the right place -->
<action name="status" timeout="10"/>
<action name="monitor" timeout="10"/>
<action name="status" depth="10" timeout="30" interval="30"/>
<action name="monitor" depth="10" timeout="30" interval="30"/>
<action name="meta-data" timeout="5"/>
<action name="validate-all" timeout="5"/>
</actions>
<special tag="rgmanager">
<attributes maxinstances="1"/>
</special>
</resource-agent>
EOT
}
#
# Start Oracle9i/10g/11g (database portion)
#
start_db()
{
declare -i rv
declare startup_cmd
declare startup_stdout
ocf_log info "Starting Oracle DB $ORACLE_SID"
# Set up our sqlplus script. Basically, we're trying to
# capture output in the hopes that it's useful in the case
# that something doesn't work properly.
startup_cmd="set heading off;\nstartup;\nquit;\n"
startup_stdout=$(echo -e "$startup_cmd" | sqlplus -S "/ as sysdba")
rv=$?
# Dump output to syslog for debugging
ocf_log debug "[$ORACLE_SID] [$rv] sent $startup_cmd"
ocf_log debug "[$ORACLE_SID] [$rv] got $startup_stdout"
if [ $rv -ne 0 ]; then
ocf_log error "Starting Oracle DB $ORACLE_SID failed, sqlplus returned $rv"
return 1
fi
# If we see:
# ORA-.....: failure, we failed
# Troubleshooting:
# ORA-00845 - Try rm -f /dev/shm/ora_*
# ORA-01081 - Try echo -e 'shutdown abort;\nquit;'|sqlplus "/ as sysdba"
if [[ "$startup_stdout" =~ "ORA-" ]] || [[ "$startup_stdout" =~ "failure" ]]; then
ocf_log error "Starting Oracle DB $ORACLE_SID failed, found errors in stdout"
return 1
fi
ocf_log info "Started Oracle DB $ORACLE_SID successfully"
return 0
}
#
# Stop Oracle (database portion)
#
stop_db()
{
declare stop_cmd
declare stop_stdout
declare -i rv
declare how_shutdown="$1"
if [ -z "$1" ]; then
how_shutdown="immediate"
fi
ocf_log info "Stopping Oracle DB $ORACLE_SID $how_shutdown"
# Setup for Stop ...
stop_cmd="set heading off;\nshutdown $how_shutdown;\nquit;\n"
stop_stdout=$(echo -e "$stop_cmd" | sqlplus -S "/ as sysdba")
rv=$?
# Log stdout of the stop command
ocf_log debug "[$ORACLE_SID] sent stop command $stop_cmd"
ocf_log debug "[$ORACLE_SID] got $stop_stdout"
# sqlplus returned failure. We'll return failed to rhcs
if [ $rv -ne 0 ]; then
ocf_log error "Stopping Oracle DB $ORACLE_SID failed, sqlplus returned $rv"
return 1
fi
# If we see 'ORA-' or 'failure' in stdout, we're done.
if [[ "$startup_stdout" =~ "ORA-" ]] || [[ "$startup_stdout" =~ "failure" ]]; then
ocf_log error "Stopping Oracle DB $ORACLE_SID failed, errors in stdout"
return 1
fi
ocf_log info "Stopped Oracle DB $ORACLE_SID successfully"
return 0
}
#
# Destroy any remaining processes with refs to $ORACLE_HOME
#
force_cleanup()
{
declare pids
declare pid
# Patch from Shane Bradley to fix 471266
pids=`ps ax | grep "ora_.*_${ORACLE_SID}" | grep -v grep | awk '{print $1}'`
ocf_log error "Not all Oracle processes for $ORACLE_SID exited cleanly, killing"
for pid in $pids; do
kill -9 $pid
rv=$?
if [ $rv -eq 0 ]; then
ocf_log info "Cleanup $ORACLE_SID Killed PID $pid"
else
ocf_log error "Cleanup $ORACLE_SID Kill PID $pid failed: $rv"
fi
done
return 0
}
#
# Wait for oracle processes to exit. Time out after 60 seconds
#
exit_idle()
{
declare -i n=0
ocf_log debug "Waiting for Oracle processes for $ORACLE_SID to terminate..."
# grep -q "." keeps this loop going if the previous commands produce any stdout
while ps ax | grep "ora_.*_${ORACLE_SID}" | grep -v grep | awk '{print $1}' | grep -q "."; do
if [ $n -ge 90 ]; then
ocf_log debug "Timed out while waiting for Oracle processes for $ORACLE_SID to terminate"
force_cleanup
return 0
fi
sleep 1
((n++))
done
ocf_log debug "All Oracle processes for $ORACLE_SID have terminated"
return 0
}
#
# Get database background process status. Restart it if it failed and
# we have seen the lock file.
#
get_db_status()
{
declare -i subsys_lock=$1
declare -i i=0
declare -i rv=0
declare ora_procname
for procname in $DB_PROCNAMES ; do
ora_procname="ora_${procname}_${ORACLE_SID}"
status $ora_procname
if [ $? -eq 0 ] ; then
# This one's okay; go to the next one.
continue
fi
#
# We're not supposed to be running, and we are,
# in fact, not running...
# XXX only works when monitoring one db process; consider
# extending in future.
#
if [ $subsys_lock -ne 0 ]; then
return 3
fi
for (( i=$RESTART_RETRIES ; i; i-- )) ; do
# this db process is down - stop and
# (re)start all ora_XXXX_$ORACLE_SID processes
ocf_log info "Restarting Oracle Database $ORACLE_SID"
stop_db immediate
if [ $? -ne 0 ] ; then
# stop failed - return 1
ocf_log error "Error stopping Oracle Database $ORACLE_SID"
return 1
fi
start_db
if [ $? -eq 0 ] ; then
# ora_XXXX_$ORACLE_SID processes started
# successfully, so break out of the
# stop/start # 'for' loop
ocf_log info "Restarted Oracle Database $ORACLE_SID successfully"
break
fi
done
if [ $i -eq 0 ]; then
# stop/start's failed - return 1 (failure)
ocf_log error "Failed to restart Oracle Database $ORACLE_SID after $RESTART_RETRIES tries"
return 1
fi
done
return 0
}
#
# Get the status of the Oracle listener process
#
get_lsnr_status()
{
declare -i subsys_lock=$1
declare -i rv
ocf_log debug "Checking status for listener $ORACLE_LISTENER"
lsnrctl status $ORACLE_LISTENER >& /dev/null
rv=$?
if [ $rv -eq 0 ] ; then
ocf_log debug "Listener $ORACLE_LISTENER is up"
return 0 # Listener is running fine
fi
# We're not supposed to be running, and we are,
# in fact, not running. Return 3
if [ $subsys_lock -ne 0 ]; then
ocf_log debug "Listener $ORACLE_LISTENER is stopped as expected"
return 3
fi
# Listener is NOT running (but should be) - try to restart
for (( i=$RESTART_RETRIES ; i; i-- )) ; do
ocf_log info "Listener $ORACLE_LISTENER is down, attempting to restart"
lsnrctl start $ORACLE_LISTENER >& /dev/null
lsnrctl status $ORACLE_LISTENER >& /dev/null
if [ $? -eq 0 ] ; then
ocf_log info "Listener $ORACLE_LISTENER was restarted successfully"
break # Listener was (re)started and is running fine
fi
done
if [ $i -eq 0 ]; then
# stop/start's failed - return 1 (failure)
ocf_log error "Failed to restart listener $ORACLE_LISTENER after $RESTART_RETRIES tries"
return 1
fi
lsnrctl_stdout=$(lsnrctl status $ORACLE_LISTENER)
rv=$?
if [ $rv -ne 0 ] ; then
ocf_log error "Starting listener $ORACLE_LISTENER failed: $rv output $lsnrctl_stdout"
return 1 # Problem restarting the Listener
fi
ocf_log info "Listener $ORACLE_LISTENER started successfully"
return 0 # Success restarting the Listener
}
#
# usage: get_opmn_proc_status <ias-component> [process-type]
#
# Get the status of a specific OPMN-managed process. If process-type
# is not specified, assume the process-type is the same as the ias-component.
# If the lock-file exists (or no lock file is specified), try to restart
# the given process-type if it is not running.
#
get_opmn_proc_status()
{
declare comp=$1
declare opmntype=$2
declare type_pretty
declare _pid _status
[ -n "$comp" ] || return 1
if [ -z "$opmntype" ]; then
opmntype=$comp
else
type_pretty=" [$opmntype]"
fi
for (( i=$RESTART_RETRIES ; i; i-- )) ; do
_status=`opmnctl status | grep "^$comp " | grep " $opmntype " | cut -d '|' -f3,4 | sed -e 's/ //g' -e 's/|/ /g'`
_pid=`echo $_status | cut -f1 -d' '`
_status=`echo $_status | cut -f2 -d' '`
if [ "${_status}" == "Alive" ] || [ "${_status}" == "Init" ]; then
if [ $i -lt $RESTART_RETRIES ] ; then
ocf_log info "$comp$type_pretty restarted"
fi
ocf_log info "$comp$type_pretty (pid $_pid) is running..."
break
else
ocf_log info "$comp$type_pretty is stopped"
#
# Try to restart it, but don't worry if we fail. OPMN
# is supposed to handle restarting these anyway.
#
# If it's running and you tell OPMN to "start" it,
# you will get an error.
#
# If it's NOT running and you tell OPMN to "restart"
# it, you will also get an error.
#
opmnctl startproc process-type=$opmntype &> /dev/null
fi
done
if [ $i -eq 0 ]; then
# restarts failed - return 1 (failure)
ocf_log error "Failed to restart OPMN process $comp"
return 1
fi
return 0
}
#
# Get the status of the OPMN-managed processes.
#
get_opmn_status()
{
declare -i subsys_lock=$1
declare -i ct_errors=0
opmnctl status &> /dev/null
if [ $? -eq 2 ]; then
#
# OPMN not running??
#
ocf_log info "OPMN is stopped"
if [ $subsys_lock -eq 0 ]; then
#
# Don't handle full opmn-restart. XXX
#
return 1
fi
# That's okay, it's not supposed to be!
return 3
fi
#
# Print out the PIDs for everyone.
#
ocf_log info "OPMN is running..."
ocf_log info "opmn components:"
#
# Check the OPMN-managed processes
#
get_opmn_proc_status OID || ((ct_errors++))
get_opmn_proc_status HTTP_Server || ((ct_errors++))
get_opmn_proc_status OC4J OC4J_SECURITY || ((ct_errors++))
#
# One or more OPMN-managed processes failed and could not be
# restarted.
#
if [ $ct_errors -ne 0 ]; then
ocf_log error "$ct_errors errors occurred while restarting OPMN-managed processes"
return 1
fi
return 0
}
#
# Helps us keep a running status so we know what our ultimate return
# code will be. Returns 1 if the $1 and $2 are not equivalent, otherwise
# returns $1. The return code is meant to be the next $1 when this is
# called, so, for example:
#
# update_status 0 <-- returns 0
# update_status $? 0 <-- returns 0
# update_status $? 3 <-- returns 1 (values different - error condition)
# update_status $? 1 <-- returns 1 (same, but happen to be error state!)
#
# update_status 3
# update_status $? 3 <-- returns 3
#
# (and so forth...)
#
update_status()
{
declare -i old_status=$1
declare -i new_status=$2
if [ -z "$2" ]; then
return $old_status
fi
if [ $old_status -ne $new_status ]; then
return 1
fi
return $old_status
}
#
# Print an error message to the user and exit.
#
oops()
{
ocf_log error "$ORACLE_SID: Fatal: $1 failed validation checks"
exit 1
}
#
# Do some validation on the user-configurable stuff at the beginning of the
# script.
#
validation_checks()
{
ocf_log debug "Validating configuration for $ORACLE_SID"
#
# If the oracle user doesn't exist, we're done.
#
[ -n "$ORACLE_USER" ] || oops "ORACLE_USER"
id -u $ORACLE_USER > /dev/null || oops "ORACLE_USER"
id -g $ORACLE_USER > /dev/null || oops "ORACLE_USER"
#
# If the oracle home isn't a directory, we're done
#
[ -n "$ORACLE_HOME" ] || oops ORACLE_HOME
#[ -d "$ORACLE_HOME" ] || oops ORACLE_HOME
#
# If the oracle SID is NULL, we're done
#
[ -n "$ORACLE_SID" ] || oops ORACLE_SID
#
# If we don't know the type, we're done
#
if [ "$ORACLE_TYPE" = "base" ]; then
# Other names for base
ORACLE_TYPE="base"
elif [ "$ORACLE_TYPE" = "10g" ] || [ "$ORACLE_TYPE" = "base-em" ]; then
ORACLE_TYPE="base-em"
elif [ "$ORACLE_TYPE" = "10g-ias" ] || [ "$ORACLE_TYPE" = "ias" ]; then
ORACLE_TYPE="ias"
elif [ "$ORACLE_TYPE" = "11g" ] || [ "$ORACLE_TYPE" = "base-em-11g" ]; then
ORACLE_TYPE="base-em-11g"
elif [ "$ORACLE_TYPE" = "base-11g" ]; then
ORACLE_TYPE="base-11g"
else
oops "ORACLE_TYPE $ORACLE_TYPE"
fi
#
# If the hostname is zero-length, fix it
#
[ -n "$ORACLE_HOSTNAME" ] || ORACLE_HOSTNAME=`hostname`
#
# Super user? Automatically change UID and exec as oracle user.
# Oracle needs to be run as the Oracle user, not root!
#
if [ "`id -u`" = "0" ]; then
#echo "Restarting $0 as $ORACLE_USER."
#
# Breaks on RHEL5
# exec sudo -u $ORACLE_USER $0 $*
#
su $ORACLE_USER -c "$0 $*"
exit $?
fi
#
# If we're not root and not the Oracle user, we're done.
#
[ "`id -u`" = "`id -u $ORACLE_USER`" ] || oops "not ORACLE_USER after su"
[ "`id -g`" = "`id -g $ORACLE_USER`" ] || oops "not ORACLE_GROUP after su"
#
# Go home.
#
cd "$ORACLE_HOME"
ocf_log debug "Validation checks for $ORACLE_SID succeeded"
return 0
}
#
# Start Oracle 9i/10g/11g Application Server Infrastructure
#
start_oracle()
{
ocf_log info "Starting service $ORACLE_SID"
start_db
rv=$?
if [ $rv -ne 0 ]; then
ocf_log error "Starting service $ORACLE_SID failed"
return 1
fi
ocf_log info "Starting listener $ORACLE_LISTENER"
lsnrctl_stdout=$(lsnrctl start $ORACLE_LISTENER)
rv=$?
if [ $rv -ne 0 ]; then
ocf_log debug "[$ORACLE_SID] Listener $ORACLE_LISTENER start returned $rv output $lsnrctl_stdout"
ocf_log error "Starting service $ORACLE_SID failed"
return 1
fi
if [ "$ORACLE_TYPE" = "base-em" ]; then
ocf_log info "Starting iSQL*Plus for $ORACLE_SID"
isqlplusctl start
if [ $? -ne 0 ]; then
ocf_log error "iSQL*Plus startup for $ORACLE_SID failed"
ocf_log error "Starting service $ORACLE_SID failed"
return 1
else
ocf_log info "iSQL*Plus startup for $ORACLE_SID succeeded"
fi
ocf_log info "Starting Oracle EM DB Console for $ORACLE_SID"
emctl start dbconsole
if [ $? -ne 0 ]; then
ocf_log error "Oracle EM DB Console startup for $ORACLE_SID failed"
ocf_log error "Starting service $ORACLE_SID failed"
return 1
else
ocf_log info "Oracle EM DB Console startup for $ORACLE_SID succeeded"
fi
elif [ "$ORACLE_TYPE" = "ias" ]; then
ocf_log info "Starting Oracle EM for $ORACLE_SID"
emctl start em
if [ $? -ne 0 ]; then
ocf_log error "Oracle EM startup for $ORACLE_SID failed"
ocf_log error "Starting service $ORACLE_SID failed"
return 1
else
ocf_log info "Oracle EM startup for $ORACLE_SID succeeded"
fi
ocf_log info "Starting iAS Infrastructure for $ORACLE_SID"
opmnctl startall
if [ $? -ne 0 ]; then
ocf_log error "iAS Infrastructure startup for $ORACLE_SID failed"
ocf_log error "Starting service $ORACLE_SID failed"
return 1
else
ocf_log info "iAS Infrastructure startup for $ORACLE_SID succeeded"
fi
elif [ "$ORACLE_TYPE" = "base-em-11g" ]; then
ocf_log info "Starting Oracle EM DB Console for $ORACLE_SID"
emctl start dbconsole
if [ $? -ne 0 ]; then
ocf_log error "Oracle EM DB Console startup for $ORACLE_SID failed"
ocf_log error "Starting service $ORACLE_SID failed"
return 1
else
ocf_log info "Oracle EM DB Console startup for $ORACLE_SID succeeded"
fi
fi
if [ -n "$LOCKFILE" ]; then
touch "$LOCKFILE"
fi
ocf_log info "Starting service $ORACLE_SID completed successfully"
return 0
}
#
# Stop Oracle 9i/10g/11g Application Server Infrastructure
#
stop_oracle()
{
ocf_log info "Stopping service $ORACLE_SID"
if ! [ -e "$ORACLE_HOME/bin/lsnrctl" ]; then
ocf_log error "Oracle Listener Control is not available ($ORACLE_HOME not mounted?)"
return 0
fi
if [ "$ORACLE_TYPE" = "base-em" ]; then
ocf_log info "Stopping Oracle EM DB Console for $ORACLE_SID"
emctl stop dbconsole
if [ $? -ne 0 ]; then
ocf_log error "Stopping Oracle EM DB Console for $ORACLE_SID failed"
ocf_log error "Stopping service $ORACLE_SID failed"
return 1
else
ocf_log info "Stopping Oracle EM DB Console for $ORACLE_SID succeeded"
fi
ocf_log info "Stopping iSQL*Plus for $ORACLE_SID"
isqlplusctl stop
if [ $? -ne 0 ]; then
ocf_log error "Stopping iSQL*Plus for $ORACLE_SID failed"
ocf_log error "Stopping service $ORACLE_SID failed"
return 1
else
ocf_log info "Stopping iSQL*Plus for $ORACLE_SID succeeded"
fi
elif [ "$ORACLE_TYPE" = "ias" ]; then
ocf_log info "Stopping iAS Infrastructure for $ORACLE_SID"
opmnctl stopall
if [ $? -ne 0 ]; then
ocf_log error "Stopping iAS Infrastructure for $ORACLE_SID failed"
ocf_log error "Stopping service $ORACLE_SID failed"
return 1
else
ocf_log info "Stopping iAS Infrastructure for $ORACLE_SID succeeded"
fi
ocf_log info "Stopping Oracle EM for $ORACLE_SID"
emctl stop em
if [ $? -ne 0 ]; then
ocf_log error "Stopping Oracle EM for $ORACLE_SID failed"
ocf_log error "Stopping service $ORACLE_SID failed"
return 1
else
ocf_log info "Stopping Oracle EM for $ORACLE_SID succeeded"
fi
elif [ "$ORACLE_TYPE" = "base-em-11g" ]; then
ocf_log info "Stopping Oracle EM DB Console for $ORACLE_SID"
emctl stop dbconsole
if [ $? -ne 0 ]; then
ocf_log error "Stopping Oracle EM DB Console for $ORACLE_SID failed"
ocf_log error "Stopping service $ORACLE_SID failed"
return 1
else
ocf_log info "Stopping Oracle EM DB Console for $ORACLE_SID succeeded"
fi
fi
stop_db immediate || stop_db abort
if [ $? -ne 0 ]; then
ocf_log error "Stopping service $ORACLE_SID failed"
return 1
fi
ocf_log info "Stopping listener $ORACLE_LISTENER for $ORACLE_SID"
lsnrctl_stdout=$(lsnrctl stop $ORACLE_LISTENER)
rv=$?
if [ $? -ne 0 ]; then
ocf_log error "Listener $ORACLE_LISTENER stop failed for $ORACLE_SID: $rv output $lsnrctl_stdout"
# XXX - failure?
fi
exit_idle
if [ $? -ne 0 ]; then
ocf_log warning "WARNING: Not all Oracle processes exited cleanly for $ORACLE_SID"
fi
if [ -n "$LOCKFILE" ]; then
rm -f "$LOCKFILE"
fi
ocf_log info "Stopping service $ORACLE_SID succeeded"
return 0
}
#
# Find and display the status of iAS infrastructure.
#
# This has three parts:
# (1) Oracle database itself
# (2) Oracle listener process
# (3) OPMN and OPMN-managed processes
#
# - If all are (cleanly) down, we return 3. In order for this to happen,
# $LOCKFILE must not exist. In this case, we try and restart certain parts
# of the service - as this may be running in a clustered environment.
#
# - If some but not all are running (and, if $LOCKFILE exists, we could not
# restart the failed portions), we return 1 (ERROR)
#
# - If all are running, return 0. In the "all-running" case, we recreate
# $LOCKFILE if it does not exist.
#
status_oracle()
{
declare -i subsys_lock=1
declare -i last
ocf_log debug "Checking status for $ORACLE_SID depth $depth"
#
# Check for lock file. Crude and rudimentary, but it works
#
if [ -z "$LOCKFILE" ] || [ -f "$LOCKFILE" ]; then
subsys_lock=0
fi
# Check database status
get_db_status $subsys_lock
update_status $? # Start
last=$?
# Check & report listener status
get_lsnr_status $subsys_lock
update_status $? $last
last=$?
if [ "$ORACLE_TYPE" = "base-em" ] || [ "$ORACLE_TYPE" = "base-em-11g" ]; then
# XXX Add isqlplus status check?!
emctl status dbconsole >&/dev/null
update_status $? $last
last=$?
elif [ "$ORACLE_TYPE" = "ias" ]; then
# Check & report opmn / opmn-managed process status
get_opmn_status $subsys_lock
update_status $? $last
last=$?
fi
#
# No lock file, but everything's running. Put the lock
# file back. XXX - this kosher?
#
if [ $last -eq 0 ] && [ $subsys_lock -ne 0 ]; then
touch "$LOCKFILE"
fi
ocf_log debug "Status returning $last for $ORACLE_SID"
return $last
}
########################
# Do some real work... #
########################
if [ "$1" = "meta-data" ]; then
meta_data
exit 0
fi
validation_checks $*
case $1 in
start)
start_oracle
exit $?
;;
stop)
stop_oracle
exit $?
;;
status|monitor)
status_oracle
exit $?
;;
restart)
$0 stop || exit $?
$0 start || exit $?
exit 0
;;
*)
echo "usage: $SCRIPT {start|stop|status|restart|meta-data}"
exit 1
;;
esac
exit 0
diff --git a/rgmanager/src/resources/oradg.sh b/rgmanager/src/resources/oradg.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/oradg.sh
rename to rgmanager/src/resources/oradg.sh.in
index 778712692..4674fe1b2
--- a/rgmanager/src/resources/oradg.sh
+++ b/rgmanager/src/resources/oradg.sh.in
@@ -1,660 +1,660 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright 2003-2004, 2006-2013 Red Hat, Inc.
#
# Author(s):
# Hardy Merrill <hmerrill at redhat.com>
# Lon Hohberger <lhh at redhat.com>
# Michael Moon <Michael dot Moon at oracle.com>
# Ryan McCabe <rmccabe at redhat.com>
#
# This program is Open Source software. You may modify and/or redistribute
# it persuant to the terms of the Open Software License version 2.1, which
# is available from the following URL and is included herein by reference:
#
# http://opensource.org/licenses/osl-2.1.php
#
# NOTES:
#
# (1) You can comment out the LOCKFILE declaration below. This will prevent
# the need for this script to access anything outside of the ORACLE_HOME
# path.
#
# (2) You MUST customize ORACLE_USER, ORACLE_HOME, ORACLE_SID, and
# ORACLE_HOSTNAME to match your installation if not running from within
# rgmanager.
#
# (3) Do NOT place this script in shared storage; place it in ORACLE_USER's
# home directory in non-clustered environments and /usr/share/cluster
# in rgmanager/Red Hat cluster environments.
#
# Oracle is a registered trademark of Oracle Corporation.
# Oracle9i is a trademark of Oracle Corporation.
# Oracle10g is a trademark of Oracle Corporation.
# Oracle11g is a trademark of Oracle Corporation.
# All other trademarks are property of their respective owners.
#
#
# $Id: oradg.sh 127 2009-08-21 09:17:52Z hevirtan $
#
# Original version is distributed with RHCS. The modifications include
# the following minor changes:
# - Meta-data moved to a dedicated file
# - Support for multiple listeners
# - Disabled EM
# - SysV init support removed. Only usable with rgmanager
#
# Grab the global RHCS helper functions
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
. /etc/init.d/functions
declare SCRIPT="`basename $0`"
declare SCRIPTDIR="`dirname $0`"
# Required parameters from rgmanager
ORACLE_USER=$OCF_RESKEY_user
ORACLE_HOME=$OCF_RESKEY_home
ORACLE_SID=$OCF_RESKEY_name
[ -n "$OCF_RESKEY_tns_admin" ] && export TNS_ADMIN=$OCF_RESKEY_tns_admin
# Optional parameters with default values
LISTENERS=$OCF_RESKEY_listeners
LOCKFILE="$ORACLE_HOME/.orainstance-${ORACLE_SID}.lock"
[ -n "$OCF_RESKEY_vhost" ] && ORACLE_HOSTNAME=$OCF_RESKEY_vhost
[ -n "$OCF_RESKEY_lockfile" ] && LOCKFILE=$OCF_RESKEY_lockfile
export LISTENERS ORACLE_USER ORACLE_HOME ORACLE_SID LOCKFILE ORACLE_HOSTNAME
export LD_LIBRARY_PATH=$ORACLE_HOME/lib
export PATH=$ORACLE_HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin
#declare -i RESTART_RETRIES=3
declare -i RESTART_RETRIES=0
declare -r DB_PROCNAMES="pmon"
declare -r LSNR_PROCNAME="tnslsnr"
# clulog will not log messages when run by the oracle user.
# This is a hack to work around that.
if [ "`id -u`" = "`id -u $ORACLE_USER`" ]; then
ocf_log() {
prio=$1
shift
logger -i -p daemon."$prio" -- "$*"
}
fi
#
# Start Oracle (database portion)
#
start_db() {
declare -i rv
declare startup_cmd
declare startup_stdout
ocf_log info "Starting Oracle DB $ORACLE_SID"
# Set up our sqlplus script. Basically, we're trying to
# capture output in the hopes that it's useful in the case
# that something doesn't work properly.
startup_stdout=$(sqlplus "/ as sysdba" << EOF
set serveroutput on
startup mount;
declare
rol varchar(20);
begin
select database_role into rol from v\$database;
dbms_output.put_line('Database role is ' || rol);
if (rol = 'PHYSICAL STANDBY') then
return;
end if;
execute immediate 'alter database open';
end;
/
select database_role, open_mode from v\$database;
set heading off;
set serveroutput off;
spool /tmp/dgstatus.${ORACLE_SID};
select open_mode from v\$database;
spool off;
EOF
)
rv=$?
# Data Guard Modification 2 - Remove deprecated parameter error from startup_stdout
startup_stdout=$(echo $startup_stdout | sed 's/ORA-32004//g')
# Dump output to syslog for debugging
ocf_log debug "[$ORACLE_SID] [$rv] sent $startup_cmd"
ocf_log debug "[$ORACLE_SID] [$rv] got $startup_stdout"
if [ $rv -ne 0 ]; then
ocf_log error "Starting Oracle DB $ORACLE_SID failed, sqlplus returned $rv"
return 1
fi
# If we see:
# ORA-.....: failure, we failed
# Troubleshooting:
# ORA-00845 - Try rm -f /dev/shm/ora_*
# ORA-01081 - Try echo -e 'shutdown abort;\nquit;'|sqlplus "/ as sysdba"
if [[ "$startup_stdout" =~ "ORA-" ]] || [[ "$startup_stdout" =~ "failure" ]]; then
ocf_log error "Starting Oracle DB $ORACLE_SID failed, found errors in stdout"
return 1
fi
ocf_log info "Started Oracle DB $ORACLE_SID successfully"
return 0
}
#
# Stop Oracle (database portion)
#
stop_db() {
declare stop_cmd
declare stop_stdout
declare -i rv
declare how_shutdown="$1"
if [ -z "$1" ]; then
how_shutdown="immediate"
fi
ocf_log info "Stopping Oracle DB $ORACLE_SID $how_shutdown"
ora_procname="ora_${DB_PROCNAMES}_${ORACLE_SID}"
status $ora_procname
if [ $? -ne 0 ]; then
ocf_log debug "no pmon process -- DB $ORACLE_SID already stopped"
# No pmon process found, db already down
return 0
fi
# Setup for Stop ...
stop_cmd="set heading off;\nshutdown $how_shutdown;\nquit;\n"
stop_stdout=$(echo -e "$stop_cmd" | sqlplus -S "/ as sysdba")
rv=$?
# Log stdout of the stop command
ocf_log debug "[$ORACLE_SID] sent stop command $stop_cmd"
ocf_log debug "[$ORACLE_SID] got $stop_stdout"
# sqlplus returned failure. We'll return failed to rhcs
if [ $rv -ne 0 ]; then
ocf_log error "Stopping Oracle DB $ORACLE_SID failed, sqlplus returned $rv"
return 1
fi
# If we see 'ORA-' or 'failure' in stdout, we're done.
if [[ "$startup_stdout" =~ "ORA-" ]] || [[ "$startup_stdout" =~ "failure" ]]; then
ocf_log error "Stopping Oracle DB $ORACLE_SID failed, errors in stdout"
return 1
fi
ocf_log info "Stopped Oracle DB $ORACLE_SID successfully"
return 0
}
#
# Destroy any remaining processes with refs to $ORACLE_SID
#
force_cleanup() {
declare pids
declare pid
ocf_log error "Not all Oracle processes for $ORACLE_SID exited cleanly, killing"
pids=`ps ax | grep "ora_.*_${ORACLE_SID}$" | grep -v grep | awk '{print $1}'`
for pid in $pids; do
kill -9 $pid
rv=$?
if [ $rv -eq 0 ]; then
ocf_log info "Cleanup $ORACLE_SID Killed PID $pid"
else
ocf_log error "Cleanup $ORACLE_SID Kill PID $pid failed: $rv"
fi
done
return 0
}
#
# Wait for oracle processes to exit. Time out after 60 seconds
#
exit_idle() {
declare -i n=0
ocf_log debug "Waiting for Oracle processes for $ORACLE_SID to terminate..."
while ps ax | grep "ora_.*_${ORACLE_SID}$" | grep -v grep | grep -q -v $LSNR_PROCNAME; do
if [ $n -ge 90 ]; then
ocf_log debug "Timed out while waiting for Oracle processes for $ORACLE_SID to terminate"
force_cleanup
return 0
fi
sleep 1
((n++))
done
ocf_log debug "All Oracle processes for $ORACLE_SID have terminated"
return 0
}
#
# Get database background process status. Restart it if it failed and
# we have seen the lock file.
#
get_db_status() {
declare -i subsys_lock=$1
declare -i i=0
declare -i rv=0
declare ora_procname
ocf_log debug "Checking status of DB $ORACLE_SID"
for procname in $DB_PROCNAMES ; do
ora_procname="ora_${procname}_${ORACLE_SID}"
status $ora_procname
if [ $? -eq 0 ] ; then
# This one's okay; go to the next one.
continue
fi
# We're not supposed to be running, and we are,
# in fact, not running...
if [ $subsys_lock -ne 0 ]; then
ocf_log debug "DB $ORACLE_SID is already stopped"
return 3
fi
for (( i=$RESTART_RETRIES ; i; i-- )) ; do
# this db process is down - stop and
# (re)start all ora_XXXX_$ORACLE_SID processes
ocf_log info "Restarting Oracle Database $ORACLE_SID"
stop_db
start_db
if [ $? -eq 0 ] ; then
# ora_XXXX_$ORACLE_SID processes started
# successfully, so break out of the
# stop/start # 'for' loop
ocf_log info "Restarted Oracle DB $ORACLE_SID successfully"
break
fi
done
if [ $i -eq 0 ]; then
# stop/start's failed - return 1 (failure)
ocf_log error "Failed to restart Oracle DB $ORACLE_SID after $RESTART_RETRIES tries"
return 1
fi
done
ocf_log debug "Checking status of DB $ORACLE_SID success"
return 0
}
#
# Get the status of the Oracle listener process
#
get_lsnr_status() {
declare -i subsys_lock=$1
declare -i rv
declare -r LISTENER=$3
ocf_log debug "Checking status for listener $LISTENER"
lsnrctl status "$LISTENER" >& /dev/null
rv=$?
if [ $rv -eq 0 ] ; then
ocf_log debug "Listener $LISTENER is up"
return 0 # Listener is running fine
fi
# We're not supposed to be running, and we are,
# in fact, not running. Return 3
if [ $subsys_lock -ne 0 ]; then
ocf_log debug "Listener $LISTENER is stopped as expected"
return 3
fi
# Listener is NOT running (but should be) - try to restart
for (( i=$RESTART_RETRIES ; i; i-- )) ; do
ocf_log info "Listener $LISTENER is down, attempting to restart"
lsnrctl start "$LISTENER" >& /dev/null
lsnrctl status "$LISTENER" >& /dev/null
if [ $? -eq 0 ]; then
ocf_log info "Listener $LISTENER was restarted successfully"
break # Listener was (re)started and is running fine
fi
done
if [ $i -eq 0 ]; then
# stop/start's failed - return 1 (failure)
ocf_log error "Failed to restart listener $LISTENER after $RESTART_RETRIES tries"
return 1
fi
lsnrctl_stdout=$(lsnrctl status "$LISTENER")
rv=$?
if [ $rv -ne 0 ] ; then
ocf_log error "Starting listener $LISTENER failed: $rv output $lsnrctl_stdout"
return 1 # Problem restarting the Listener
fi
ocf_log info "Listener $LISTENER started successfully"
return 0 # Success restarting the Listener
}
#
# Helps us keep a running status so we know what our ultimate return
# code will be. Returns 1 if the $1 and $2 are not equivalent, otherwise
# returns $1. The return code is meant to be the next $1 when this is
# called, so, for example:
#
# update_status 0 <-- returns 0
# update_status $? 0 <-- returns 0
# update_status $? 3 <-- returns 1 (values different - error condition)
# update_status $? 1 <-- returns 1 (same, but happen to be error state!)
#
# update_status 3
# update_status $? 3 <-- returns 3
#
# (and so forth...)
#
update_status() {
declare -i old_status=$1
declare -i new_status=$2
if [ -z "$2" ]; then
return $old_status
fi
if [ $old_status -ne $new_status ]; then
ocf_log error "Error: $old_status vs $new_status for $ORACLE_SID - returning 1"
return 1
fi
return $old_status
}
#
# Print an error message to the user and exit.
#
oops() {
ocf_log error "$ORACLE_SID: Fatal: $1 failed validation checks"
exit 1
}
#
# Do some validation on the user-configurable stuff at the beginning of the
# script.
#
validation_checks() {
ocf_log debug "Validating configuration for $ORACLE_SID"
# If the oracle user doesn't exist, we're done.
[ -n "$ORACLE_USER" ] || oops "ORACLE_USER"
id -u $ORACLE_USER > /dev/null || oops "ORACLE_USER"
id -g $ORACLE_USER > /dev/null || oops "ORACLE_GROUP"
# If the oracle home isn't a directory, we're done
[ -n "$ORACLE_HOME" ] || oops "ORACLE_HOME"
# If the oracle SID is NULL, we're done
[ -n "$ORACLE_SID" ] || oops "ORACLE_SID"
# Super user? Automatically change UID and exec as oracle user.
# Oracle needs to be run as the Oracle user, not root!
if [ "`id -u`" = "0" ]; then
su $ORACLE_USER -c "$0 $*"
exit $?
fi
# If we're not root and not the Oracle user, we're done.
[ "`id -u`" = "`id -u $ORACLE_USER`" ] || oops "not ORACLE_USER after su"
[ "`id -g`" = "`id -g $ORACLE_USER`" ] || oops "not ORACLE_GROUP after su"
# Go home.
cd "$ORACLE_HOME"
ocf_log debug "Validation checks for $ORACLE_SID succeeded"
return 0
}
#
# Start Oracle
#
start_oracle() {
ocf_log info "Starting service $ORACLE_SID"
start_db
rv=$?
if [ $rv -ne 0 ]; then
ocf_log error "Starting service $ORACLE_SID failed"
return 1
fi
for LISTENER in ${LISTENERS}; do
ocf_log info "Starting listener $LISTENER"
lsnrctl_stdout=$(lsnrctl start "$LISTENER")
rv=$?
if [ $rv -ne 0 ]; then
ocf_log debug "[$ORACLE_SID] Listener $LISTENER start returned $rv output $lsnrctl_stdout"
ocf_log error "Starting service $ORACLE_SID failed"
return 1
fi
done
if [ -n "$ORACLE_HOSTNAME" -a -s /tmp/dgstatus.${ORACLE_SID} ]; then
# Start DB Console if vhost defined and database_role is READ WRITE
if cat /tmp/dgstatus.${ORACLE_SID} 2>/dev/null | grep "READ WRITE"; then
ocf_log info "Starting Oracle EM DB Console for $ORACLE_SID"
emctl start dbconsole
if [ $? -ne 0 ]; then
ocf_log error "Oracle EM DB Console startup for $ORACLE_SID failed"
ocf_log error "Starting service $ORACLE_SID failed"
# Force good return status
#return 1
return 0
else
ocf_log info "Oracle EM DB Console startup for $ORACLE_SID succeeded"
fi
fi
rm -f /tmp/dgstatus.${ORACLE_SID}
fi
if [ -n "$LOCKFILE" ]; then
touch "$LOCKFILE"
fi
ocf_log info "Starting service $ORACLE_SID completed successfully"
return 0
}
#
# Stop Oracle
#
stop_oracle() {
ocf_log info "Stopping service $ORACLE_SID"
if ! [ -e "$ORACLE_HOME/bin/lsnrctl" ]; then
ocf_log error "Oracle Listener Control is not available ($ORACLE_HOME not mounted?)"
# XXX should this return 1?
return 0
fi
stop_db || stop_db abort
if [ $? -ne 0 ]; then
ocf_log error "Unable to stop DB for $ORACLE_SID"
return 1
fi
for LISTENER in ${LISTENERS}; do
ocf_log info "Stopping listener $LISTENER for $ORACLE_SID"
lsnrctl_stdout=$(lsnrctl stop "$LISTENER")
rv=$?
if [ $rv -ne 0 ]; then
ocf_log error "Listener $LISTENER stop failed for $ORACLE_SID: $rv output $lsnrctl_stdout"
pid=`ps ax | grep "tnslsnr $LISTENER " | grep -v grep | awk '{print $1}'`
kill -9 $pid
rv=$?
if [ $rv -eq 0 ]; then
ocf_log info "Cleanup $LISTENER Killed PID $pid"
else
ocf_log error "Cleanup $LISTENER Kill PID $pid failed: $rv"
fi
fi
done
if [ -n "$ORACLE_HOSTNAME" ]; then
# Stop DB Console if vhost defined
ocf_log info "Stopping Oracle EM DB Console for $ORACLE_SID"
emctl stop dbconsole
if [ $? -ne 0 ]; then
ocf_log error "Stopping Oracle EM DB Console for $ORACLE_SID failed"
ocf_log error "Stopping service $ORACLE_SID failed"
# Force good return status
#return 1
return 0
else
ocf_log info "Stopping Oracle EM DB Console for $ORACLE_SID succeeded"
fi
fi
exit_idle
if [ $? -ne 0 ]; then
ocf_log error "WARNING: Not all Oracle processes exited cleanly for $ORACLE_SID"
# XXX - failure?
fi
if [ -n "$LOCKFILE" ]; then
rm -f "$LOCKFILE"
fi
ocf_log info "Stopping service $ORACLE_SID succeeded"
return 0
}
#
# Find and display the status of iAS infrastructure.
#
# This has three parts:
# (1) Oracle database itself
# (2) Oracle listener process
# (3) OPMN and OPMN-managed processes
#
# - If all are (cleanly) down, we return 3. In order for this to happen,
# $LOCKFILE must not exist. In this case, we try and restart certain parts
# of the service - as this may be running in a clustered environment.
#
# - If some but not all are running (and, if $LOCKFILE exists, we could not
# restart the failed portions), we return 1 (ERROR)
#
# - If all are running, return 0. In the "all-running" case, we recreate
# $LOCKFILE if it does not exist.
#
status_oracle() {
declare -i subsys_lock=1
declare -i last
declare -i depth=$1
ocf_log debug "Checking status for $ORACLE_SID depth $depth"
# Check for lock file. Crude and rudimentary, but it works
if [ -z "$LOCKFILE" ] || [ -f "$LOCKFILE" ]; then
subsys_lock=0
fi
# Check database status
get_db_status $subsys_lock $depth
update_status $? # Start
last=$?
# Check & report listener status
for LISTENER in ${LISTENERS}; do
get_lsnr_status $subsys_lock $depth "$LISTENER"
update_status $? $last
last=$?
done
# No status for DB Console (ORACLE_HOSTNAME)
# No lock file, but everything's running. Put the lock
# file back. XXX - this kosher?
if [ $last -eq 0 ] && [ $subsys_lock -ne 0 ]; then
touch "$LOCKFILE"
fi
ocf_log debug "Status returning $last for $ORACLE_SID"
return $last
}
########################
# Do some real work... #
########################
# Data Guard Modification 1 - Debug Logging
case $1 in
stop | start | status | restart | recover | monitor )
[ $(id -u) = 0 ] && exec > "/tmp/oradg_${ORACLE_SID}_$1.log" 2>&1
set -x
date
echo $@
printenv
esac
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
exit 0
;;
start)
validation_checks $*
start_oracle
exit $?
;;
stop)
validation_checks $*
stop_oracle
exit $?
;;
status|monitor)
validation_checks $*
status_oracle $OCF_CHECK_LEVEL
exit $?
;;
restart)
$0 stop || exit $?
$0 start || exit $?
exit 0
;;
*)
echo "usage: $SCRIPT {start|stop|restart|status|monitor|meta-data}"
exit 1
;;
esac
exit 0
diff --git a/rgmanager/src/resources/orainstance.sh b/rgmanager/src/resources/orainstance.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/orainstance.sh
rename to rgmanager/src/resources/orainstance.sh.in
index 3504a5329..58733739e
--- a/rgmanager/src/resources/orainstance.sh
+++ b/rgmanager/src/resources/orainstance.sh.in
@@ -1,594 +1,594 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright 2003-2004, 2006-2013 Red Hat, Inc.
#
# Author(s):
# Hardy Merrill <hmerrill at redhat.com>
# Lon Hohberger <lhh at redhat.com>
# Michael Moon <Michael dot Moon at oracle.com>
# Ryan McCabe <rmccabe at redhat.com>
#
# This program is Open Source software. You may modify and/or redistribute
# it persuant to the terms of the Open Software License version 2.1, which
# is available from the following URL and is included herein by reference:
#
# http://opensource.org/licenses/osl-2.1.php
#
# NOTES:
#
# (1) You can comment out the LOCKFILE declaration below. This will prevent
# the need for this script to access anything outside of the ORACLE_HOME
# path.
#
# (2) You MUST customize ORACLE_USER, ORACLE_HOME, ORACLE_SID, and
# ORACLE_HOSTNAME to match your installation if not running from within
# rgmanager.
#
# (3) Do NOT place this script in shared storage; place it in ORACLE_USER's
# home directory in non-clustered environments and /usr/share/cluster
# in rgmanager/Red Hat cluster environments.
#
# Oracle is a registered trademark of Oracle Corporation.
# Oracle9i is a trademark of Oracle Corporation.
# Oracle10g is a trademark of Oracle Corporation.
# Oracle11g is a trademark of Oracle Corporation.
# All other trademarks are property of their respective owners.
#
#
# $Id: orainstance.sh 127 2009-08-21 09:17:52Z hevirtan $
#
# Original version is distributed with RHCS. The modifications include
# the following minor changes:
# - Meta-data moved to a dedicated file
# - Support for multiple listeners
# - Disabled EM
# - SysV init support removed. Only usable with rgmanager
#
# Grab the global RHCS helper functions
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
. /etc/init.d/functions
declare SCRIPT="`basename $0`"
declare SCRIPTDIR="`dirname $0`"
# Required parameters from rgmanager
ORACLE_USER=$OCF_RESKEY_user
ORACLE_HOME=$OCF_RESKEY_home
ORACLE_SID=$OCF_RESKEY_name
[ -n "$OCF_RESKEY_tns_admin" ] && export TNS_ADMIN=$OCF_RESKEY_tns_admin
# Optional parameters with default values
LISTENERS=$OCF_RESKEY_listeners
LOCKFILE="$ORACLE_HOME/.orainstance-${ORACLE_SID}.lock"
[ -n "$OCF_RESKEY_lockfile" ] && LOCKFILE=$OCF_RESKEY_lockfile
export LISTENERS ORACLE_USER ORACLE_HOME ORACLE_SID LOCKFILE
export LD_LIBRARY_PATH=$ORACLE_HOME/lib
export PATH=$ORACLE_HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin
declare -i RESTART_RETRIES=3
declare -r DB_PROCNAMES="pmon"
declare -r LSNR_PROCNAME="tnslsnr"
# clulog will not log messages when run by the oracle user.
# This is a hack to work around that.
if [ "`id -u`" = "`id -u $ORACLE_USER`" ]; then
ocf_log() {
prio=$1
shift
logger -i -p daemon."$prio" -- "$*"
}
fi
#
# Start Oracle (database portion)
#
start_db() {
declare -i rv
declare startup_cmd
declare startup_stdout
ocf_log info "Starting Oracle DB $ORACLE_SID"
# Set up our sqlplus script. Basically, we're trying to
# capture output in the hopes that it's useful in the case
# that something doesn't work properly.
startup_cmd="set heading off;\nstartup;\nquit;\n"
startup_stdout=$(echo -e "$startup_cmd" | sqlplus -S "/ as sysdba")
rv=$?
# Dump output to syslog for debugging
ocf_log debug "[$ORACLE_SID] [$rv] sent $startup_cmd"
ocf_log debug "[$ORACLE_SID] [$rv] got $startup_stdout"
if [ $rv -ne 0 ]; then
ocf_log error "Starting Oracle DB $ORACLE_SID failed, sqlplus returned $rv"
return 1
fi
# If we see:
# ORA-.....: failure, we failed
# Troubleshooting:
# ORA-00845 - Try rm -f /dev/shm/ora_*
# ORA-01081 - Try echo -e 'shutdown abort;\nquit;'|sqlplus "/ as sysdba"
# We need to ignore some non-fatl errors
ignore_error=(ORA-32004)
for error in ${ignore_error[*]}
do
startup_stdout=$(echo "$startup_stdout" | sed "s/${error}//g")
done
if [[ "$startup_stdout" =~ "ORA-" ]] || [[ "$startup_stdout" =~ "failure" ]]; then
ocf_log error "Starting Oracle DB $ORACLE_SID failed, found errors in stdout"
return 1
fi
ocf_log info "Started Oracle DB $ORACLE_SID successfully"
return 0
}
#
# Stop Oracle (database portion)
#
stop_db() {
declare stop_cmd
declare stop_stdout
declare -i rv
declare how_shutdown="$1"
if [ -z "$1" ]; then
how_shutdown="immediate"
fi
ocf_log info "Stopping Oracle DB $ORACLE_SID $how_shutdown"
ora_procname="ora_${DB_PROCNAMES}_${ORACLE_SID}"
status $ora_procname
if [ $? -ne 0 ]; then
ocf_log debug "no pmon process -- DB $ORACLE_SID already stopped"
# No pmon process found, db already down
return 0
fi
# Setup for Stop ...
stop_cmd="set heading off;\nshutdown $how_shutdown;\nquit;\n"
stop_stdout=$(echo -e "$stop_cmd" | sqlplus -S "/ as sysdba")
rv=$?
# Log stdout of the stop command
ocf_log debug "[$ORACLE_SID] sent stop command $stop_cmd"
ocf_log debug "[$ORACLE_SID] got $stop_stdout"
# sqlplus returned failure. We'll return failed to rhcs
if [ $rv -ne 0 ]; then
ocf_log error "Stopping Oracle DB $ORACLE_SID failed, sqlplus returned $rv"
return 1
fi
# If we see 'ORA-' or 'failure' in stdout, we're done.
if [[ "$startup_stdout" =~ "ORA-" ]] || [[ "$startup_stdout" =~ "failure" ]]; then
ocf_log error "Stopping Oracle DB $ORACLE_SID failed, errors in stdout"
return 1
fi
ocf_log info "Stopped Oracle DB $ORACLE_SID successfully"
return 0
}
#
# Destroy any remaining processes with refs to $ORACLE_SID
#
force_cleanup() {
declare pids
declare pid
ocf_log error "Not all Oracle processes for $ORACLE_SID exited cleanly, killing"
pids=`ps ax | grep "ora_.*_${ORACLE_SID}$" | grep -v grep | awk '{print $1}'`
for pid in $pids; do
kill -9 $pid
rv=$?
if [ $rv -eq 0 ]; then
ocf_log info "Cleanup $ORACLE_SID Killed PID $pid"
else
ocf_log error "Cleanup $ORACLE_SID Kill PID $pid failed: $rv"
fi
done
return 0
}
#
# Wait for oracle processes to exit. Time out after 60 seconds
#
exit_idle() {
declare -i n=0
ocf_log debug "Waiting for Oracle processes for $ORACLE_SID to terminate..."
while ps ax | grep "ora_.*_${ORACLE_SID}$" | grep -v grep | grep -q -v $LSNR_PROCNAME; do
if [ $n -ge 90 ]; then
ocf_log debug "Timed out while waiting for Oracle processes for $ORACLE_SID to terminate"
force_cleanup
return 0
fi
sleep 1
((n++))
done
ocf_log debug "All Oracle processes for $ORACLE_SID have terminated"
return 0
}
#
# Get database background process status. Restart it if it failed and
# we have seen the lock file.
#
get_db_status() {
declare -i subsys_lock=$1
declare -i i=0
declare -i rv=0
declare ora_procname
ocf_log debug "Checking status of DB $ORACLE_SID"
for procname in $DB_PROCNAMES ; do
ora_procname="ora_${procname}_${ORACLE_SID}"
status $ora_procname
if [ $? -eq 0 ] ; then
# This one's okay; go to the next one.
continue
fi
# We're not supposed to be running, and we are,
# in fact, not running...
if [ $subsys_lock -ne 0 ]; then
ocf_log debug "DB $ORACLE_SID is already stopped"
return 3
fi
for (( i=$RESTART_RETRIES ; i; i-- )) ; do
# this db process is down - stop and
# (re)start all ora_XXXX_$ORACLE_SID processes
ocf_log info "Restarting Oracle Database $ORACLE_SID"
stop_db
start_db
if [ $? -eq 0 ] ; then
# ora_XXXX_$ORACLE_SID processes started
# successfully, so break out of the
# stop/start # 'for' loop
ocf_log info "Restarted Oracle DB $ORACLE_SID successfully"
break
fi
done
if [ $i -eq 0 ]; then
# stop/start's failed - return 1 (failure)
ocf_log error "Failed to restart Oracle DB $ORACLE_SID after $RESTART_RETRIES tries"
return 1
fi
done
ocf_log debug "Checking status of DB $ORACLE_SID success"
return 0
}
#
# Get the status of the Oracle listener process
#
get_lsnr_status() {
declare -i subsys_lock=$1
declare -i rv
declare -r LISTENER=$3
ocf_log debug "Checking status for listener $LISTENER"
lsnrctl status "$LISTENER" >& /dev/null
rv=$?
if [ $rv -eq 0 ] ; then
ocf_log debug "Listener $LISTENER is up"
return 0 # Listener is running fine
fi
# We're not supposed to be running, and we are,
# in fact, not running. Return 3
if [ $subsys_lock -ne 0 ]; then
ocf_log debug "Listener $LISTENER is stopped as expected"
return 3
fi
# Listener is NOT running (but should be) - try to restart
for (( i=$RESTART_RETRIES ; i; i-- )) ; do
ocf_log info "Listener $LISTENER is down, attempting to restart"
lsnrctl start "$LISTENER" >& /dev/null
lsnrctl status "$LISTENER" >& /dev/null
if [ $? -eq 0 ]; then
ocf_log info "Listener $LISTENER was restarted successfully"
break # Listener was (re)started and is running fine
fi
done
if [ $i -eq 0 ]; then
# stop/start's failed - return 1 (failure)
ocf_log error "Failed to restart listener $LISTENER after $RESTART_RETRIES tries"
return 1
fi
lsnrctl_stdout=$(lsnrctl status "$LISTENER")
rv=$?
if [ $rv -ne 0 ] ; then
ocf_log error "Starting listener $LISTENER failed: $rv output $lsnrctl_stdout"
return 1 # Problem restarting the Listener
fi
ocf_log info "Listener $LISTENER started successfully"
return 0 # Success restarting the Listener
}
#
# Helps us keep a running status so we know what our ultimate return
# code will be. Returns 1 if the $1 and $2 are not equivalent, otherwise
# returns $1. The return code is meant to be the next $1 when this is
# called, so, for example:
#
# update_status 0 <-- returns 0
# update_status $? 0 <-- returns 0
# update_status $? 3 <-- returns 1 (values different - error condition)
# update_status $? 1 <-- returns 1 (same, but happen to be error state!)
#
# update_status 3
# update_status $? 3 <-- returns 3
#
# (and so forth...)
#
update_status() {
declare -i old_status=$1
declare -i new_status=$2
if [ -z "$2" ]; then
return $old_status
fi
if [ $old_status -ne $new_status ]; then
ocf_log error "Error: $old_status vs $new_status for $ORACLE_SID - returning 1"
return 1
fi
return $old_status
}
#
# Print an error message to the user and exit.
#
oops() {
ocf_log error "$ORACLE_SID: Fatal: $1 failed validation checks"
exit 1
}
#
# Do some validation on the user-configurable stuff at the beginning of the
# script.
#
validation_checks() {
ocf_log debug "Validating configuration for $ORACLE_SID"
# If the oracle user doesn't exist, we're done.
[ -n "$ORACLE_USER" ] || oops "ORACLE_USER"
id -u $ORACLE_USER > /dev/null || oops "ORACLE_USER"
id -g $ORACLE_USER > /dev/null || oops "ORACLE_GROUP"
# If the oracle home isn't a directory, we're done
[ -n "$ORACLE_HOME" ] || oops "ORACLE_HOME"
# If the oracle SID is NULL, we're done
[ -n "$ORACLE_SID" ] || oops "ORACLE_SID"
# Super user? Automatically change UID and exec as oracle user.
# Oracle needs to be run as the Oracle user, not root!
if [ "`id -u`" = "0" ]; then
su $ORACLE_USER -c "$0 $*"
exit $?
fi
# If we're not root and not the Oracle user, we're done.
[ "`id -u`" = "`id -u $ORACLE_USER`" ] || oops "not ORACLE_USER after su"
[ "`id -g`" = "`id -g $ORACLE_USER`" ] || oops "not ORACLE_GROUP after su"
# Go home.
cd "$ORACLE_HOME"
ocf_log debug "Validation checks for $ORACLE_SID succeeded"
return 0
}
#
# Start Oracle
#
start_oracle() {
ocf_log info "Starting service $ORACLE_SID"
start_db
rv=$?
if [ $rv -ne 0 ]; then
ocf_log error "Starting service $ORACLE_SID failed"
return 1
fi
for LISTENER in ${LISTENERS}; do
ocf_log info "Starting listener $LISTENER"
lsnrctl_stdout=$(lsnrctl start "$LISTENER")
rv=$?
if [ $rv -ne 0 ]; then
ocf_log debug "[$ORACLE_SID] Listener $LISTENER start returned $rv output $lsnrctl_stdout"
ocf_log error "Starting service $ORACLE_SID failed"
return 1
fi
done
if [ -n "$LOCKFILE" ]; then
touch "$LOCKFILE"
fi
ocf_log info "Starting service $ORACLE_SID completed successfully"
return 0
}
#
# Stop Oracle
#
stop_oracle() {
ocf_log info "Stopping service $ORACLE_SID"
if ! [ -e "$ORACLE_HOME/bin/lsnrctl" ]; then
ocf_log error "Oracle Listener Control is not available ($ORACLE_HOME not mounted?)"
# XXX should this return 1?
return 0
fi
stop_db || stop_db abort
if [ $? -ne 0 ]; then
ocf_log error "Unable to stop DB for $ORACLE_SID"
return 1
fi
for LISTENER in ${LISTENERS}; do
ocf_log info "Stopping listener $LISTENER for $ORACLE_SID"
lsnrctl_stdout=$(lsnrctl stop "$LISTENER")
rv=$?
if [ $rv -ne 0 ]; then
ocf_log error "Listener $LISTENER stop failed for $ORACLE_SID: $rv output $lsnrctl_stdout"
pid=`ps ax | grep "tnslsnr $LISTENER " | grep -v grep | awk '{print $1}'`
kill -9 $pid
rv=$?
if [ $rv -eq 0 ]; then
ocf_log info "Cleanup $LISTENER Killed PID $pid"
else
ocf_log error "Cleanup $LISTENER Kill PID $pid failed: $rv"
fi
fi
done
exit_idle
if [ $? -ne 0 ]; then
ocf_log error "WARNING: Not all Oracle processes exited cleanly for $ORACLE_SID"
# XXX - failure?
fi
if [ -n "$LOCKFILE" ]; then
rm -f "$LOCKFILE"
fi
ocf_log info "Stopping service $ORACLE_SID succeeded"
return 0
}
#
# Find and display the status of iAS infrastructure.
#
# This has three parts:
# (1) Oracle database itself
# (2) Oracle listener process
# (3) OPMN and OPMN-managed processes
#
# - If all are (cleanly) down, we return 3. In order for this to happen,
# $LOCKFILE must not exist. In this case, we try and restart certain parts
# of the service - as this may be running in a clustered environment.
#
# - If some but not all are running (and, if $LOCKFILE exists, we could not
# restart the failed portions), we return 1 (ERROR)
#
# - If all are running, return 0. In the "all-running" case, we recreate
# $LOCKFILE if it does not exist.
#
status_oracle() {
declare -i subsys_lock=1
declare -i last
declare -i depth=$1
ocf_log debug "Checking status for $ORACLE_SID depth $depth"
# Check for lock file. Crude and rudimentary, but it works
if [ -z "$LOCKFILE" ] || [ -f "$LOCKFILE" ]; then
subsys_lock=0
fi
# Check database status
get_db_status $subsys_lock $depth
update_status $? # Start
last=$?
# Check & report listener status
for LISTENER in ${LISTENERS}; do
get_lsnr_status $subsys_lock $depth "$LISTENER"
update_status $? $last
last=$?
done
# No lock file, but everything's running. Put the lock
# file back. XXX - this kosher?
if [ $last -eq 0 ] && [ $subsys_lock -ne 0 ]; then
touch "$LOCKFILE"
fi
ocf_log debug "Status returning $last for $ORACLE_SID"
return $last
}
########################
# Do some real work... #
########################
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
exit 0
;;
start)
validation_checks $*
start_oracle
exit $?
;;
stop)
validation_checks $*
stop_oracle
exit $?
;;
status|monitor)
validation_checks $*
status_oracle $OCF_CHECK_LEVEL
exit $?
;;
restart)
$0 stop || exit $?
$0 start || exit $?
exit 0
;;
*)
echo "usage: $SCRIPT {start|stop|restart|status|monitor|meta-data}"
exit 1
;;
esac
exit 0
diff --git a/rgmanager/src/resources/oralistener.sh b/rgmanager/src/resources/oralistener.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/oralistener.sh
rename to rgmanager/src/resources/oralistener.sh.in
index 94698a90a..215fd0f6e
--- a/rgmanager/src/resources/oralistener.sh
+++ b/rgmanager/src/resources/oralistener.sh.in
@@ -1,197 +1,197 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Red Hat Cluster Suite resource agent for controlling Oracle 10g
# listener instances. This script will start, stop and monitor running
# listeners.
#
# start: Will start given listener instance
#
# stop: Will stop given listener instance
#
# monitor: Will check that the listener is OK by calling lsnrctl status
#
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Grab the global RHCS helper functions
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
declare -i RESTART_RETRIES=3
ORACLE_USER=$OCF_RESKEY_user
ORACLE_HOME=$OCF_RESKEY_home
LISTENER=$OCF_RESKEY_name
[ -n "$OCF_RESKEY_tns_admin" ] && export TNS_ADMIN=$OCF_RESKEY_tns_admin
LC_ALL=C
LANG=C
PATH=$ORACLE_HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin
export LC_ALL LANG PATH ORACLE_USER ORACLE_HOME
# clulog will not log messages when run by the oracle user.
# This is a hack to work around that.
if [ "`id -u`" = "`id -u $ORACLE_USER`" ]; then
ocf_log() {
prio=$1
shift
logger -i -p daemon."$prio" -- "$*"
}
fi
verify_all() {
ocf_log debug "Validating configuration for $LISTENER"
if [ -z "$OCF_RESKEY_name" ]; then
ocf_log error "Validation for $LISTENER failed: Invalid name of service (listener name)"
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_home" ]; then
ocf_log error "Validation for $LISTENER failed: No Oracle home specified."
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_user" ]; then
ocf_log error "Validation for $LISTENER failed: No Oracle username specified."
return $OCF_ERR_ARGS
fi
# Super user? Automatically change UID and exec as oracle user.
# Oracle needs to be run as the Oracle user, not root!
if [ "`id -u`" = "0" ]; then
su $OCF_RESKEY_user -c "$0 $*"
exit $?
fi
# Make sure the lsnrctl binary is in our $PATH
if [ ! -x $(which lsnrctl) ]; then
ocf_log error "Validation for $LISTENER failed: Unable to locate lsnrctl command from path! ($PATH)"
return $OCF_ERR_GENERIC
fi
ocf_log debug "Validation checks for $LISTENER succeeded"
return 0
}
start() {
ocf_log info "Starting listener $LISTENER"
lsnrctl_stdout=$(lsnrctl start "$LISTENER")
if [ $? -ne 0 ]; then
ocf_log error "start listener $LISTENER failed $lsnrctl_stdout"
return $OCF_ERR_GENERIC
fi
ocf_log info "Listener $LISTENER started successfully"
return 0
}
stop() {
ocf_log info "Stopping listener $LISTENER"
monitor $OCF_CHECK_LEVEL
if [ $? -ne 0 ]; then
ocf_log info "Listener $LISTENER already stopped"
return 0
fi
lsnrctl_stdout=$(lsnrctl stop "$LISTENER")
if [ $? -ne 0 ]; then
ocf_log debug "stop listener $LISTENER failed $lsnrctl_stdout"
return $OCF_ERR_GENERIC
fi
ocf_log info "Listener $LISTENER stopped successfully"
return 0
}
monitor() {
declare -i depth=$1
ocf_log debug "Checking status for listener $LISTENER depth $depth"
lsnrctl status "$LISTENER" >& /dev/null
if [ $? -ne 0 ]; then
ocf_log error "Listener $LISTENER not running"
return $OCF_ERR_GENERIC
fi
ocf_log debug "Listener $LISTENER is up"
return 0 # Listener is running fine
}
recover() {
ocf_log debug "Recovering listener $LISTENER"
for (( i=$RESTART_RETRIES ; i; i-- )); do
start
if [ $? -eq 0 ] ; then
ocf_log debug "Restarted listener $LISTENER successfully"
break
fi
done
if [ $i -eq 0 ]; then
# stop/start's failed - return 1 (failure)
ocf_log debug "Failed to restart listener $LISTENER after $RESTART_RETRIES tries"
return 1
fi
status
if [ $? -ne 0 ] ; then
ocf_log debug "Failed to restart listener $LISTENER"
return 1 # Problem restarting the Listener
fi
ocf_log debug "Restarted listener $LISTENER successfully"
return 0 # Success restarting the Listener
}
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
exit 0
;;
verify-all)
verify_all $*
exit $?
;;
start)
verify_all $* && start
exit $?
;;
stop)
verify_all $* && stop
exit $?
;;
recover)
verify_all $* && recover
exit $?
;;
status|monitor)
verify_all $*
monitor $OCF_CHECK_LEVEL
exit $?
;;
*)
echo "Usage: $0 {start|stop|recover|monitor|status|meta-data|verify-all}"
exit $OCF_ERR_GENERIC
;;
esac
diff --git a/rgmanager/src/resources/postgres-8.sh b/rgmanager/src/resources/postgres-8.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/postgres-8.sh
rename to rgmanager/src/resources/postgres-8.sh.in
index 76c22ddfd..6f597d332
--- a/rgmanager/src/resources/postgres-8.sh
+++ b/rgmanager/src/resources/postgres-8.sh.in
@@ -1,241 +1,241 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
export LC_ALL=C
export LANG=C
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
declare PSQL_POSTMASTER="/usr/bin/postmaster"
declare PSQL_CTL="/usr/bin/pg_ctl"
declare PSQL_pid_file="`generate_name_for_pid_file`"
declare PSQL_conf_dir="`generate_name_for_conf_dir`"
declare PSQL_gen_config_file="$PSQL_conf_dir/postgresql.conf"
declare PSQL_kill_timeout="5"
declare PSQL_stop_timeout="15"
if [ -z "$OCF_RESKEY_startup_wait" ]; then
OCF_RESKEY_startup_wait=10
fi
verify_all()
{
clog_service_verify $CLOG_INIT
if [ -z "$OCF_RESKEY_name" ]; then
clog_service_verify $CLOG_FAILED "Invalid Name Of Service"
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_service_name" ]; then
clog_service_verify $CLOG_FAILED_NOT_CHILD
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_INVALID "$OCF_RESKEY_config_file"
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
if [ ! -r "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_NOT_READABLE $OCF_RESKEY_config_file
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_postmaster_user" ]; then
clog_servicer_verify $CLOG_FAILED "Invalid User"
return $OCF_ERR_ARGS
fi
clog_service_verify $CLOG_SUCCEED
return 0
}
generate_config_file()
{
declare original_file="$1"
declare generated_file="$2"
declare ip_addressess="$3"
declare ip_comma="";
if [ -f "$generated_file" ]; then
sha1_verify "$generated_file"
if [ $? -ne 0 ]; then
clog_check_sha1 $CLOG_FAILED
return 0
fi
fi
clog_generate_config $CLOG_INIT "$original_file" "$generated_file"
declare x=1
for i in $ip_addressess; do
i=`echo $i | sed -e 's/\/.*$//'`
if [ $x -eq 1 ]; then
x=0
ip_comma=$i
else
ip_comma=$ip_comma,$i
fi
done
generate_configTemplate "$generated_file" "$1"
echo "external_pid_file = '$PSQL_pid_file'" >> "$generated_file"
echo "listen_addresses = '$ip_comma'" >> "$generated_file"
echo >> "$generated_file"
sed 's/^[[:space:]]*external_pid_file/### external_pid_file/i;s/^[[:space:]]*listen_addresses/### listen_addresses/i' < "$original_file" >> "$generated_file"
sha1_addToFile "$generated_file"
clog_generate_config $CLOG_SUCCEED "$original_file" "$generated_file"
return 0;
}
start()
{
declare pguser_group
declare count=0
clog_service_start $CLOG_INIT
create_pid_directory
create_conf_directory "$PSQL_conf_dir"
check_pid_file "$PSQL_pid_file"
if [ $? -ne 0 ]; then
clog_check_pid $CLOG_FAILED "$PSQL_pid_file"
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
#
# Create an empty PID file for the postgres user and
# change it to be owned by the postgres user so that
# postmaster doesn't complain.
#
pguser_group=`groups $OCF_RESKEY_postmaster_user | cut -f3 -d ' '`
touch $PSQL_pid_file
chown $OCF_RESKEY_postmaster_user.$pguser_group $PSQL_pid_file
clog_looking_for $CLOG_INIT "IP Addresses"
get_service_ip_keys "$OCF_RESKEY_service_name"
ip_addresses=`build_ip_list`
if [ -z "$ip_addresses" ]; then
clog_looking_for $CLOG_FAILED_NOT_FOUND "IP Addresses"
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_SUCCEED "IP Addresses"
generate_config_file "$OCF_RESKEY_config_file" "$PSQL_gen_config_file" "$ip_addresses"
su - "$OCF_RESKEY_postmaster_user" -c "$PSQL_POSTMASTER -c config_file=\"$PSQL_gen_config_file\" \
$OCF_RESKEY_postmaster_options" &> /dev/null &
# We need to sleep briefly to allow pg_ctl to detect that we've started.
# We need to fetch "-D /path/to/pgsql/data" from $OCF_RESKEY_postmaster_options
until [ "$count" -gt "$OCF_RESKEY_startup_wait" ] ||
[ `su - "$OCF_RESKEY_postmaster_user" -c \
"$PSQL_CTL status $OCF_RESKEY_postmaster_options" &> /dev/null; echo $?` = '0' ]
do
sleep 1
let count=$count+1
done
if [ "$count" -gt "$OCF_RESKEY_startup_wait" ]; then
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_service_start $CLOG_SUCCEED
return 0;
}
stop()
{
clog_service_stop $CLOG_INIT
## Send -INT to close connections and stop. -QUIT is used if -INT signal does not stop process.
stop_generic_sigkill "$PSQL_pid_file" "$PSQL_stop_timeout" "$PSQL_kill_timeout" "-INT"
if [ $? -ne 0 ]; then
clog_service_stop $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_service_stop $CLOG_SUCCEED
return 0;
}
status()
{
clog_service_status $CLOG_INIT
status_check_pid "$PSQL_pid_file"
if [ $? -ne 0 ]; then
clog_service_status $CLOG_FAILED "$PSQL_pid_file"
return $OCF_ERR_GENERIC
fi
clog_service_status $CLOG_SUCCEED
return 0
}
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
exit 0
;;
validate-all)
verify_all
exit $?
;;
start)
verify_all && start
exit $?
;;
stop)
verify_all && stop
exit $?
;;
status|monitor)
verify_all
status
exit $?
;;
restart)
verify_all
stop
start
exit $?
;;
*)
echo "Usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/samba.sh b/rgmanager/src/resources/samba.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/samba.sh
rename to rgmanager/src/resources/samba.sh.in
index d4d073669..9b7216dd4
--- a/rgmanager/src/resources/samba.sh
+++ b/rgmanager/src/resources/samba.sh.in
@@ -1,241 +1,241 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
export LC_ALL=C
export LANG=C
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
declare SAMBA_SMBD=/usr/sbin/smbd
declare SAMBA_NMBD=/usr/sbin/nmbd
declare SAMBA_pid_dir="`generate_name_for_pid_dir`"
declare SAMBA_conf_dir="`generate_name_for_conf_dir`"
declare SAMBA_smbd_pid_file="$SAMBA_pid_dir/smbd-smb.conf.pid"
declare SAMBA_nmbd_pid_file="$SAMBA_pid_dir/nmbd-smb.conf.pid"
declare SAMBA_gen_config_file="$SAMBA_conf_dir/smb.conf"
verify_all()
{
clog_service_verify $CLOG_INIT
if [ -z "$OCF_RESKEY_name" ]; then
clog_service_verify $CLOG_FAILED "Invalid Name Of Service"
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_service_name" ]; then
clog_service_verify $CLOG_FAILED_NOT_CHILD
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_INVALID "$OCF_RESKEY_config_file"
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
if [ ! -r "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_NOT_READABLE $OCF_RESKEY_config_file
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
clog_service_verify $CLOG_SUCCEED
return 0
}
generate_config_file()
{
declare original_file="$1"
declare generated_file="$2"
declare ip_addresses="$3"
if [ -f "$generated_file" ]; then
sha1_verify "$generated_file"
if [ $? -ne 0 ]; then
clog_check_sha1 $CLOG_FAILED
return 0
fi
fi
clog_generate_config $CLOG_INIT "$original_file" "$generated_file"
generate_configTemplate "$generated_file" "$1"
echo "pid directory = \"$SAMBA_pid_dir\"" >> "$generated_file"
echo "interfaces = $ip_addresses" >> "$generated_file"
echo "bind interfaces only = Yes" >> "$generated_file"
echo "netbios name = ${OCF_RESKEY_name/ /_}" >> "$generated_file"
echo >> "$generated_file"
sed 's/^[[:space:]]*pid directory/### pid directory/i;s/^[[:space:]]*interfaces/### interfaces/i;s/^[[:space:]]*bind interfaces only/### bind interfaces only/i;s/^[[:space:]]*netbios name/### netbios name/i' \
< "$original_file" >> "$generated_file"
sha1_addToFile "$generated_file"
clog_generate_config $CLOG_SUCCEED "$original_file" "$generated_file"
return 0;
}
start()
{
clog_service_start $CLOG_INIT
create_pid_directory
mkdir -p "$SAMBA_pid_dir"
create_conf_directory "$SAMBA_conf_dir"
check_pid_file "$SAMBA_smbd_pid_file"
if [ $? -ne 0 ]; then
clog_check_pid $CLOG_FAILED "$SAMBA_smbd_pid_file"
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
check_pid_file "$SAMBA_nmbd_pid_file"
if [ $? -ne 0 ]; then
clog_check_pid $CLOG_FAILED "$SAMBA_nmbd_pid_file"
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_INIT "IP Addresses"
get_service_ip_keys "$OCF_RESKEY_service_name"
ip_addresses=`build_ip_list`
if [ -z "$ip_addresses" ]; then
clog_looking_for $CLOG_FAILED_NOT_FOUND "IP Addresses"
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_SUCCEED "IP Addresses"
generate_config_file "$OCF_RESKEY_config_file" "$SAMBA_gen_config_file" "$ip_addresses"
$SAMBA_SMBD -D -s "$SAMBA_gen_config_file" $OCF_RESKEY_smbd_options
if [ $? -ne 0 ]; then
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
$SAMBA_NMBD -D -s "$SAMBA_gen_config_file" $OCF_RESKEY_nmbd_options
if [ $? -ne 0 ]; then
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_service_start $CLOG_SUCCEED
return 0;
}
stop()
{
clog_service_stop $CLOG_INIT
stop_generic "$SAMBA_smbd_pid_file" "$OCF_RESKEY_shutdown_wait"
if [ $? -ne 0 ]; then
clog_service_stop $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
stop_generic "$SAMBA_nmbd_pid_file"
if [ $? -ne 0 ]; then
clog_service_stop $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
if [ -e "$SAMBA_smbd_pid_file" ]; then
rm -f "$SAMBA_smbd_pid_file"
fi
if [ -e "$SAMBA_nmbd_pid_file" ]; then
rm -f "$SAMBA_nmbd_pid_file"
fi
clog_service_stop $CLOG_SUCCEED
return 0;
}
status()
{
clog_service_status $CLOG_INIT
status_check_pid "$SAMBA_smbd_pid_file"
if [ $? -ne 0 ]; then
clog_service_status $CLOG_FAILED "$SAMBA_smbd_pid_file"
return $OCF_ERR_GENERIC
fi
status_check_pid "$SAMBA_nmbd_pid_file"
if [ $? -ne 0 ]; then
clog_service_status $CLOG_FAILED "$SAMBA_nmbd_pid_file"
return $OCF_ERR_GENERIC
fi
clog_service_status $CLOG_SUCCEED
return 0
}
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
exit 0
;;
validate-all)
verify_all
exit $?
;;
start)
verify_all && start
exit $?
;;
stop)
verify_all && stop
exit $?
;;
status|monitor)
verify_all
status
exit $?
;;
restart)
verify_all
stop
start
exit $?
;;
*)
echo "Usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/script.sh b/rgmanager/src/resources/script.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/script.sh
rename to rgmanager/src/resources/script.sh.in
index fa3b4124c..88e831521
--- a/rgmanager/src/resources/script.sh
+++ b/rgmanager/src/resources/script.sh.in
@@ -1,171 +1,171 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Script to handle a non-OCF script (e.g. a normal init-script)
#
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
LC_ALL=C
LANG=C
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LC_ALL LANG PATH
. $(dirname $0)/ocf-shellfuncs
meta_data()
{
cat <<EOT
<?xml version="1.0"?>
<resource-agent version="rgmanager 2.0" name="script">
<version>1.0</version>
<longdesc lang="en">
The script resource allows a standard LSB-compliant init script
to be used to start a clustered service.
</longdesc>
<shortdesc lang="en">
LSB-compliant init script as a clustered resource.
</shortdesc>
<parameters>
<parameter name="name" unique="1" primary="1">
<longdesc lang="en">
Name
</longdesc>
<shortdesc lang="en">
Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="file" unique="1" required="1">
<longdesc lang="en">
Path to script
</longdesc>
<shortdesc lang="en">
Path to script
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="service_name" inherit="service%name">
<longdesc lang="en">
Inherit the service name, in case the
script wants to know this information.
</longdesc>
<shortdesc lang="en">
Inherit the service name.
</shortdesc>
<content type="string"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="0"/>
<action name="stop" timeout="0"/>
<!-- This is just a wrapper for LSB init scripts, so monitor
and status can't have a timeout, nor do they do any extra
work regardless of the depth -->
<action name="status" interval="30s" timeout="0"/>
<action name="monitor" interval="30s" timeout="0"/>
<action name="meta-data" timeout="0"/>
<action name="validate-all" timeout="0"/>
</actions>
</resource-agent>
EOT
}
validate_all()
{
if [ -z "${OCF_RESKEY_file}" ]; then
ocf_log err "No file provided"
return $OCF_ERR_ARGS # Invalid Argument
fi
if ! [ -e "${OCF_RESKEY_file}" ]; then
ocf_log err "${OCF_RESKEY_file} does not exist"
return $OCF_ERR_INSTALLED # Program not installed
fi
if [ -b "${OCF_RESKEY_file}" ]; then
ocf_log err "${OCF_RESKEY_file} is a block device"
return $OCF_ERR_ARGS # Invalid Argument
fi
if [ -d "${OCF_RESKEY_file}" ]; then
ocf_log err "${OCF_RESKEY_file} is a directory"
return $OCF_ERR_ARGS # Invalid Argument
fi
if [ -c "${OCF_RESKEY_file}" ]; then
ocf_log err "${OCF_RESKEY_file} is a character device"
return $OCF_ERR_ARGS # Invalid Argument
fi
if [ -p "${OCF_RESKEY_file}" ]; then
ocf_log err "${OCF_RESKEY_file} is a named pipe"
return $OCF_ERR_ARGS # Invalid Argument
fi
if [ -S "${OCF_RESKEY_file}" ]; then
ocf_log err "${OCF_RESKEY_file} is a socket"
return $OCF_ERR_ARGS # Invalid Argument
fi
if ! [ -s "${OCF_RESKEY_file}" ]; then
ocf_log err "${OCF_RESKEY_file} is empty"
return $OCF_ERR_GENERIC # ???
fi
if ! [ -x "${OCF_RESKEY_file}" ]; then
ocf_log err "${OCF_RESKEY_file} is not executable"
return $OCF_ERR_PERM
fi
return 0
}
case $1 in
meta-data)
meta_data
exit 0
;;
validate-all)
validate_all
exit $?
;;
*)
;;
esac
validate_all || exit $?
# Execute the script
ocf_log info "Executing ${OCF_RESKEY_file} $1"
${OCF_RESKEY_file} $1
declare -i rv=$?
if [ $rv -ne 0 ]; then
ocf_log err "script:$OCF_RESKEY_name: $1 of $OCF_RESKEY_file failed (returned $rv)"
exit $OCF_ERR_GENERIC
fi
diff --git a/rgmanager/src/resources/service.sh b/rgmanager/src/resources/service.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/service.sh
rename to rgmanager/src/resources/service.sh.in
index 9b6ccc927..5fd9b5b4f
--- a/rgmanager/src/resources/service.sh
+++ b/rgmanager/src/resources/service.sh.in
@@ -1,300 +1,300 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Dummy OCF script for resource group
#
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Grab nfs lock tricks if available
export NFS_TRICKS=1
if [ -f "$(dirname $0)/svclib_nfslock" ]; then
. $(dirname $0)/svclib_nfslock
NFS_TRICKS=0
fi
meta_data()
{
cat <<EOT
<?xml version="1.0"?>
<resource-agent version="rgmanager 2.0" name="service">
<version>1.0</version>
<longdesc lang="en">
This defines a collection of resources, known as a resource
group or cluster service.
</longdesc>
<shortdesc lang="en">
Defines a service (resource group).
</shortdesc>
<parameters>
<parameter name="name" unique="1" required="1" primary="1">
<longdesc lang="en">
This is the name of the resource group.
</longdesc>
<shortdesc lang="en">
Name.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="domain" reconfig="1">
<longdesc lang="en">
Failover domains define lists of cluster members
to try in the event that a resource group fails.
</longdesc>
<shortdesc lang="en">
Failover domain.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="autostart" reconfig="1">
<longdesc lang="en">
If set to yes, this resource group will automatically be started
after the cluster forms a quorum. If set to no, this resource
group will start in the 'disabled' state after the cluster forms
a quorum.
</longdesc>
<shortdesc lang="en">
Automatic start after quorum formation
</shortdesc>
<content type="boolean" default="1"/>
</parameter>
<parameter name="exclusive" reconfig="1">
<longdesc lang="en">
If set, this resource group will only relocate to
nodes which have no other resource groups running in the
event of a failure. If no empty nodes are available,
this resource group will not be restarted after a failure.
Additionally, resource groups will not automatically
relocate to the node running this resource group. This
option can be overridden by manual start and/or relocate
operations.
</longdesc>
<shortdesc lang="en">
Exclusive service.
</shortdesc>
<content type="boolean" default="0"/>
</parameter>
<parameter name="nfslock">
<longdesc lang="en">
Enable NFS lock workarounds. When used with a compatible
HA-callout program like clunfslock, this could be used
to provide NFS lock failover, but at significant cost to
other services on the machine. This requires a compatible
version of nfs-utils and manual configuration of rpc.statd;
see 'man rpc.statd' to see if your version supports
the -H parameter.
</longdesc>
<shortdesc lang="en">
Enable NFS lock workarounds.
</shortdesc>
<content type="boolean" default="0"/>
</parameter>
<parameter name="nfs_client_cache">
<longdesc lang="en">
On systems with large numbers of exports, a performance
problem in the exportfs command can cause inordinately long
status check times for services with lots of mounted
NFS clients. This occurs because exportfs does DNS queries
on all clients in the export list.
Setting this option to '1' will enable caching of the export
list returned from the exportfs command on a per-service
basis. The cache will last for 30 seconds before expiring
instead of being generated each time an nfsclient resource
is called.
</longdesc>
<shortdesc lang="en">
Enable exportfs list caching (performance).
</shortdesc>
<content type="integer" default="0"/>
</parameter>
<parameter name="recovery" reconfig="1">
<longdesc lang="en">
This currently has three possible options: "restart" tries
to restart failed parts of this resource group locally before
attempting to relocate (default); "relocate" does not bother
trying to restart the service locally; "disable" disables
the resource group if any component fails. Note that
any resource with a valid "recover" operation which can be
recovered without a restart will be.
</longdesc>
<shortdesc lang="en">
Failure recovery policy (restart, relocate, or disable).
</shortdesc>
<content type="string" default="restart"/>
</parameter>
<parameter name="depend">
<longdesc lang="en">
Service dependency; will not start without the specified
service running.
</longdesc>
<shortdesc lang="en">
Top-level service this depends on, in service:name format.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="depend_mode">
<longdesc lang="en">
Service dependency mode.
hard - This service is stopped/started if its dependency
is stopped/started
soft - This service only depends on the other service for
initial startip. If the other service stops, this
service is not stopped.
</longdesc>
<shortdesc lang="en">
Service dependency mode (soft or hard).
</shortdesc>
<content type="string" default="hard"/>
</parameter>
<parameter name="max_restarts">
<longdesc lang="en">
Maximum restarts for this service.
</longdesc>
<shortdesc lang="en">
Maximum restarts for this service.
</shortdesc>
<content type="string" default="0"/>
</parameter>
<parameter name="restart_expire_time">
<longdesc lang="en">
Restart expiration time. A restart is forgotten
after this time. When combined with the max_restarts
option, this lets administrators specify a threshold
for when to fail over services. If max_restarts
is exceeded in this given expiration time, the service
is relocated instead of restarted again.
</longdesc>
<shortdesc lang="en">
Restart expiration time; amount of time before a restart
is forgotten.
</shortdesc>
<content type="string" default="0"/>
</parameter>
<parameter name="priority">
<longdesc lang="en">
Priority for the service. In a failover scenario, this
indicates the ordering of the service (1 is processed
first, 2 is processed second, etc.). This overrides the
order presented in cluster.conf. This option only has
an effect if central processing within rgmanager is turned
on.
</longdesc>
<shortdesc lang="en">
Service priority.
</shortdesc>
<content type="integer" default="0"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="5"/>
<action name="stop" timeout="5"/>
<!-- No-ops. Groups are abstract resource types.
<action name="status" timeout="5" interval="1h"/>
<action name="monitor" timeout="5" interval="1h"/>
-->
<action name="reconfig" timeout="5"/>
<action name="recover" timeout="5"/>
<action name="reload" timeout="5"/>
<action name="meta-data" timeout="5"/>
<action name="validate-all" timeout="5"/>
</actions>
<special tag="rgmanager">
<attributes maxinstances="1"/>
<child type="lvm" start="1" stop="9"/>
<child type="fs" start="2" stop="8"/>
<child type="clusterfs" start="3" stop="7"/>
<child type="netfs" start="4" stop="6"/>
<child type="nfsexport" start="5" stop="5"/>
<child type="nfsclient" start="6" stop="4"/>
<child type="ip" start="7" stop="2"/>
<child type="smb" start="8" stop="3"/>
<child type="script" start="9" stop="1"/>
</special>
</resource-agent>
EOT
}
#
# A Resource group is abstract, but the OCF RA API doesn't allow for abstract
# resources, so here it is.
#
case $1 in
start)
#
# XXX If this is set, we kill lockd. If there is no
# child IP address, then clients will NOT get the reclaim
# notification.
#
if [ $NFS_TRICKS -eq 0 ]; then
if [ "$OCF_RESKEY_nfslock" = "yes" ] || \
[ "$OCF_RESKEY_nfslock" = "1" ]; then
pkill -KILL -x lockd
fi
fi
exit 0
;;
stop)
exit 0
;;
recover|restart)
exit 0
;;
status|monitor)
exit 0
;;
reload)
exit 0
;;
meta-data)
meta_data
exit 0
;;
validate-all)
exit 0
;;
reconfig)
exit 0
;;
*)
exit 0
;;
esac
diff --git a/rgmanager/src/resources/smb.sh b/rgmanager/src/resources/smb.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/smb.sh
rename to rgmanager/src/resources/smb.sh.in
index edb99cef5..f2d566fbd
--- a/rgmanager/src/resources/smb.sh
+++ b/rgmanager/src/resources/smb.sh.in
@@ -1,698 +1,698 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Script to manage a Samba file-sharing service component.
# Unline NFS, this should be placed at the top level of a service
# because it will try to gather information necessary to run the
# smbd/nmbd daemons at run-time from the service structure.
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Author(s):
# Lon Hohberger (lhh at redhat.com)
# Tim Burke (tburke at redhat.com)
#
LC_ALL=C
LANG=C
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LC_ALL LANG PATH
#
# Definitions!
#
declare SAMBA_CONFIG_DIR=/etc/samba
declare SMBD_COMMAND=/usr/sbin/smbd
declare NMBD_COMMAND=/usr/sbin/nmbd
declare KILLALL_COMMAND=/usr/bin/killall
declare SAMBA_PID_DIR=/var/run/samba
declare SAMBA_LOCK_DIR=/var/cache/samba
#
# gross globals
#
declare -a ipkeys
declare -a fskeys
# Don't change please :)
_FAIL=255
. $(dirname $0)/ocf-shellfuncs
meta_data()
{
cat <<EOT
<?xml version="1.0"?>
<resource-agent version="rgmanager 2.0" name="smb">
<version>1.0</version>
<longdesc lang="en">
Dynamic smbd/nmbd resource agent
</longdesc>
<shortdesc lang="en">
Dynamic smbd/nmbd resource agent
</shortdesc>
<parameters>
<parameter name="name" unique="1" primary="1">
<longdesc lang="en">
Samba Symbolic Name. This name will
correspond to /etc/samba/smb.conf.NAME
</longdesc>
<shortdesc lang="en">
Samba Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="workgroup">
<longdesc lang="en">
Workgroup name
</longdesc>
<shortdesc lang="en">
Workgroup name
</shortdesc>
<content type="string" default="LINUXCLUSTER"/>
</parameter>
<parameter name="service_name" inherit="service%name">
<longdesc lang="en">
Inherit the service name. We need to know
the service name in order to determine file
systems and IPs for this smb service.
</longdesc>
<shortdesc lang="en">
Inherit the service name.
</shortdesc>
<content type="string"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="0"/>
<action name="stop" timeout="0"/>
<!-- This is just a wrapper for LSB init scripts, so monitor
and status can't have a timeout, nor do they do any extra
work regardless of the depth -->
<action name="status" interval="30s" timeout="0"/>
<action name="monitor" interval="30s" timeout="0"/>
<action name="meta-data" timeout="0"/>
<action name="validate-all" timeout="0"/>
</actions>
</resource-agent>
EOT
}
#
# Usage: ccs_get key
#
ccs_get()
{
declare outp
declare key
[ -n "$1" ] || return $_FAIL
key="$*"
outp=$(ccs_tool query "$key" 2>&1)
if [ $? -ne 0 ]; then
if [ "$outp" = "${outp/No data available/}" ] || [ "$outp" = "${outp/Operation not permitted/}" ]; then
ocf_log err "$outp ($key)"
return $_FAIL
fi
# no real error, just no data available
return 0
fi
echo $outp
return 0
}
#
# Build a list of service IP keys; traverse refs if necessary
#
get_service_ip_keys()
{
declare svc=$1
declare -i x y=0
declare outp
declare key
#
# Find service-local IP keys
#
x=1
while : ; do
key="/cluster/rm/service[@name=\"$svc\"]/ip[$x]"
#
# Try direct method
#
outp=$(ccs_get "$key/@address")
if [ $? -ne 0 ]; then
return 1
fi
#
# Try by reference
#
if [ -z "$outp" ]; then
outp=$(ccs_get "$key/@ref")
if [ $? -ne 0 ]; then
return 1
fi
key="/cluster/rm/resources/ip[@address=\"$outp\"]"
fi
if [ -z "$outp" ]; then
break
fi
#ocf_log debug "IP $outp found @ $key"
ipkeys[$y]="$key"
((y++))
((x++))
done
ocf_log debug "$y IP addresses found for $svc/$OCF_RESKEY_name"
return 0
}
#
# Build a list of service fs keys, traverse refs if necessary
#
get_service_fs_keys()
{
declare svc=$1
declare -i x y=0
declare outp
declare key
#
# Find service-local IP keys
#
x=1
while : ; do
key="/cluster/rm/service[@name=\"$svc\"]/fs[$x]"
#
# Try direct method
#
outp=$(ccs_get "$key/@name")
if [ $? -ne 0 ]; then
return 1
fi
#
# Try by reference
#
if [ -z "$outp" ]; then
outp=$(ccs_get "$key/@ref")
if [ $? -ne 0 ]; then
return 1
fi
key="/cluster/rm/resources/fs[@name=\"$outp\"]"
fi
if [ -z "$outp" ]; then
break
fi
#ocf_log debug "filesystem $outp found @ $key"
fskeys[$y]="$key"
((y++))
((x++))
done
ocf_log debug "$y filesystems found for $svc/$OCF_RESKEY_name"
return 0
}
build_ip_list()
{
declare ipaddrs ipaddr
declare -i x=0
while [ -n "${ipkeys[$x]}" ]; do
ipaddr=$(ccs_get "${ipkeys[$x]}/@address")
if [ -z "$ipaddr" ]; then
break
fi
ipaddrs="$ipaddrs $ipaddr"
((x++))
done
echo $ipaddrs
}
add_sha1()
{
declare sha1line="# rgmanager-sha1 $(sha1sum "$1")"
echo $sha1line >> "$1"
}
verify_sha1()
{
declare tmpfile="$(mktemp /tmp/smb-$OCF_RESKEY_name.tmp.XXXXXX)"
declare current exp
exp=$(grep "^# rgmanager-sha1.*$1" "$1" | head -1)
if [ -z "$exp" ]; then
# No sha1 line. We're done.
ocf_log debug "No SHA1 info in $1"
return 1
fi
#
# Find expected sha1 and expected file name
#
exp=${exp/*sha1 /}
exp=${exp/ */}
grep -v "^# rgmanager-sha1" "$1" > "$tmpfile"
current=$(sha1sum "$tmpfile")
current=${current/ */}
rm -f "$tmpfile"
if [ "$current" = "$exp" ]; then
ocf_log debug "SHA1 sum matches for $1"
return 0
fi
ocf_log debug "SHA1 sum does not match for $1"
return 1
}
add_fs_entries()
{
declare conf="$1"
declare sharename
declare sharepath key
declare -i x=0
while [ -n "${fskeys[$x]}" ]; do
key="${fskeys[$x]}/@name"
sharename=$(ccs_get "$key")
if [ -z "$sharename" ]; then
break
fi
key="${fskeys[$x]}/@mountpoint"
sharepath=$(ccs_get "$key")
if [ -z "$sharepath" ]; then
break
fi
cat >> "$conf" <<EODEV
[$sharename]
comment = Auto-generated $sharename share
# Hide the secret cluster files
veto files = /.clumanager/.rgmanager/
browsable = yes
writable = no
public = yes
path = $sharepath
EODEV
((x++))
done
}
#
# Generate the samba configuration if neede for this service.
#
gen_smb_conf()
{
declare conf="$1"
declare lvl="debug"
if [ -f "$conf" ]; then
verify_sha1 "$conf"
if [ $? -ne 0 ]; then
ocf_log debug "Config file changed; skipping"
return 0
fi
else
lvl="info"
fi
ocf_log $lvl "Creating $conf"
get_service_ip_keys "$OCF_RESKEY_service_name"
get_service_fs_keys "$OCF_RESKEY_service_name"
cat > "$conf" <<EOT
#
# "$conf"
#
# This template configuration wass automatically generated, and will
# be automatically regenerated if removed. Please modify this file to
# speficy subdirectories and/or client access permissions.
#
# Once this file has been altered, automatic re-generation will stop.
# Remember to copy this file to all other cluster members after making
# changes, or your SMB service will not operate correctly.
#
# From a cluster perspective, the key fields are:
# lock directory - must be unique per samba service.
# bind interfaces only - must be present set to yes.
# interfaces - must be set to service floating IP address.
# path - must be the service mountpoint or subdirectory thereof.
#
[global]
workgroup = $OCF_RESKEY_workgroup
pid directory = /var/run/samba/$OCF_RESKEY_name
lock directory = /var/cache/samba/$OCF_RESKEY_name
log file = /var/log/samba/%m.log
#private dir = /var/
encrypt passwords = yes
bind interfaces only = yes
netbios name = ${OCF_RESKEY_name/ /_}
#
# Interfaces are based on ip resources at the top level of
# "$OCF_RESKEY_service_name"; IPv6 addresses may or may not
# work correctly.
#
interfaces = $(build_ip_list)
#
# Shares based on fs resources at the top level of "$OCF_RESKEY_service_name"
#
EOT
add_fs_entries "$conf"
add_sha1 "$conf"
return 0
}
#
# Kill off the specified PID
# (from clumanager 1.0.x/1.2.x)
#
# Killing off the samba daemons was miserable to implement, merely
# because killall doesn't distinguish by program commandline.
# Consequently I had to implement these routines to selectively pick 'em off.
#
# Kills of either the {smbd|nmbd} which is running and was started with
# the specified argument. Can't use `killall` to do this because it
# doesn't allow you to distinguish which process to kill based on any
# of the program arguments.
#
# This routine is also called on "status" checks. In this case it doesn't
# actually kill anything.
#
# Parameters:
# daemonName - daemon name, can be either smbd or nmbd
# command - [stop|start|status]
# arg - argument passed to daemon. In this case its not the
# full set of program args, rather its really just the
# samba config file.
#
# Returns: 0 - success (or the daemon isn't currently running)
# 1 - failure
#
kill_daemon_by_arg()
{
declare daemonName=$1
declare action=$2
declare arg=$3
# Create a unique temporary file to stash off intermediate results
declare tmpfile_str=/tmp/sambapids.XXXXXX
declare tmpfile
declare ret
tmpfile=$(mktemp $tmpfile_str); ret_val=$?
if [ -z "$tmpfile" ]; then
ocf_log err "kill_daemon_by_arg: Can't create tmp file"
return $_FAIL
fi
# Mumble, need to strip off the /etc/samba portion, otherwise the
# grep pattern matching will fail.
declare confFile="$(basename $arg)"
# First generate a list of candidate pids.
pidof $daemonName > $tmpfile
if [ $? -ne 0 ]; then
ocf_log debug "kill_daemon_by_arg: no pids for $daemonName"
rm -f $tmpfile
case "$action" in
'stop')
return 0
;;
'status')
return $_FAIL
;;
esac
return 0
fi
# If you don't find any matching daemons for a "stop" operation, thats
# considered success; whereas for "status" inquiries its a failure.
case "$action" in
'stop')
ret=0
;;
'status')
ret=$_FAIL
;;
esac
#
# At this point tmpfile contains a set of pids for the corresponding
# {smbd|nmbd}. Now look though this candidate set of pids and compare
# the program arguments (samba config file name). This distinguishes
# which ones should be killed off.
#
declare daemonPid=""
for daemonPid in $(cat $tmpfile); do
declare commandLine=$(cat /proc/$daemonPid/cmdline)
declare confBase="$(basename $commandLine)"
if [ "$confBase" = "$confFile" ]; then
case "$action" in
'status')
rm -f $tmpfile
return 0
;;
esac
kill_daemon_pid $daemonPid
if [ $? -ne 0 ]; then
ret=$_FAIL
ocf_log err \
"kill_daemon_by_arg: kill_daemon_pid $daemonPid failed"
else
ocf_log debug \
"kill_daemon_by_arg: kill_daemon_pid $daemonPid success"
fi
fi
done
rm -f $tmpfile
return $ret
}
#
# Kill off the specified PID
# (from clumanager 1.0.x/1.2.x)
#
kill_daemon_pid()
{
declare pid=$1
declare retval=0
kill -TERM $pid
if [ $? -eq 0 ]; then
ocf_log debug "Samba: successfully killed $pid"
else
ocf_log debug "Samba: failed to kill $pid"
retval=$_FAIL
fi
return $retval
}
share_start_stop()
{
declare command=$1
declare conf="$SAMBA_CONFIG_DIR/smb.conf.$OCF_RESKEY_name"
declare smbd_command
declare nmbd_command
declare netbios_name
#
# Specify daemon options
# -D = spawn off as separate daemon
# -s = the following arg specifies the config file
#
declare smbd_options="-D -s"
declare nmbd_options="-D -s"
if [ "$command" = "start" ]; then
gen_smb_conf "$conf"
else
if ! [ -f "$conf" ]; then
ocf_log warn "\"$conf\" missing during $command"
fi
fi
#
# On clusters with multiple samba shares, we need to ensure (as much
# as possible) that each service is advertised as a separate netbios
# name.
#
# Generally, the admin sets this in smb.conf.NAME - but since
# it is not required, we need another option. Consequently, we use
# smb instance name (which must be unique)
#
if [ -f "$conf" ]; then
grep -qe "^\([[:space:]]\+n\|n\)etbios[[:space:]]\+name[[:space:]]*=[[:space:]]*[[:alnum:]]\+" "$conf"
if [ $? -ne 0 ]; then
netbios_name=$OCF_RESKEY_name
ocf_log notice "Using $netbios_name as NetBIOS name (service $OCF_RESKEY_service_name)"
nmbd_options=" -n $netbios_name $nmbd_options"
fi
fi
case $command in
start)
ocf_log info "Starting Samba instance \"$OCF_RESKEY_name\""
mkdir -p "$SAMBA_PID_DIR/$OCF_RESKEY_name"
mkdir -p "$SAMBA_LOCK_DIR/$OCF_RESKEY_name"
[ -f "$SMBD_COMMAND" ] || exit $OCF_ERR_INSTALLED
[ -f "$NMBD_COMMAND" ] || exit $OCF_ERR_INSTALLED
# Kick off the per-service smbd
$SMBD_COMMAND $smbd_options "$conf"
ret_val=$?
if [ $ret_val -ne 0 ]; then
ocf_log err "Samba service failed: $SMBD_COMMAND $smbd_options \"$conf\""
return $_FAIL
fi
ocf_log debug "Samba service succeeded: $SMBD_COMMAND $smbd_options \"$conf\""
# Kick off the per-service nmbd
$NMBD_COMMAND $nmbd_options "$conf"
ret_val=$?
if [ $ret_val -ne 0 ]; then
ocf_log err "Samba service failed: $NMBD_COMMAND $nmbd_options \"$conf\""
return $_FAIL
fi
ocf_log debug "Samba service succeeded: $NMBD_COMMAND $nmbd_options \"$conf\""
;;
stop)
ocf_log info "Stopping Samba instance \"$OCF_RESKEY_name\""
kill_daemon_by_arg "nmbd" $command "$conf"
kill_daemon_by_arg "smbd" $command "$conf"
if [ "$SAMBA_PID_DIR/$OCF_RESKEY_name" != "/" ]; then
pushd "$SAMBA_PID_DIR" &> /dev/null
rm -rf "$OCF_RESKEY_name"
popd &> /dev/null
fi
if [ "$SAMBA_LOCK_DIR/$OCF_RESKEY_name" != "/" ]; then
pushd "$SAMBA_LOCK_DIR" &> /dev/null
rm -rf "$OCF_RESKEY_name"
popd &> /dev/null
fi
;;
status)
ocf_log debug "Checking Samba instance \"$OCF_RESKEY_name\""
kill_daemon_by_arg "nmbd" $command "$conf"
if [ $? -ne 0 ]; then
ocf_log err \
"share_start_stop: nmbd for service $svc_name died!"
return $_FAIL
fi
kill_daemon_by_arg "smbd" $command "$conf"
if [ $? -ne 0 ]; then
ocf_log err \
"share_start_stop: nmbd for service $svc_name died!"
return $_FAIL
fi
;;
esac
}
verify_all()
{
[ -z "$OCF_RESKEY_workgroup" ] && export OCF_RESKEY_workgroup="LINUXCLUSTER"
[ -n "${OCF_RESKEY_name}" ] || exit $OCF_ERR_ARGS # Invalid Argument
if [ -z "${OCF_RESKEY_service_name}" ]; then
ocf_log ERR "Samba service ${OCF_RESKEY_name} is not the child of a service"
exit $OCF_ERR_ARGS
fi
}
case $1 in
meta-data)
meta_data
exit 0
;;
start|stop)
verify_all
share_start_stop $1
exit $?
;;
status|monitor)
verify_all
share_start_stop status
exit $?
;;
validate-all)
verify_all
echo "Yer radio's workin', driver!"
exit 0
;;
*)
echo "usage: $0 {start|stop|status|monitor|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/svclib_nfslock b/rgmanager/src/resources/svclib_nfslock.in
similarity index 99%
rename from rgmanager/src/resources/svclib_nfslock
rename to rgmanager/src/resources/svclib_nfslock.in
index bc06269d5..86efd07bb 100644
--- a/rgmanager/src/resources/svclib_nfslock
+++ b/rgmanager/src/resources/svclib_nfslock.in
@@ -1,281 +1,281 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Do reclaim-broadcasts when we kill lockd during shutdown/startup
# of a cluster service.
#
# Exported functions:
#
# notify_list_store
# notify_list_merge
# notify_list_broadcast
#
#
# Usage:
# statd_notify <directory> <hostname|ip>
#
# Copy out a list from <directory>, merge them with the system nfs lock
# list, and send them out as <hostname|ip> after generating a random
# state (needed so clients will reclaim their locks)
#
nfslock_statd_notify()
{
declare tmpdir
declare nl_dir=$1
declare nl_ip=$2
declare command # Work around bugs in rpc.statd
declare pid_xxx # Work around bugs in rpc.statd
declare owner
[ -z "$lockd_pid" ] && return 0
if ! [ -d $nl_dir ]; then
return 0
fi
if [ -z "`ls $nl_dir/sm/* 2> /dev/null`" ]; then
ocf_log debug "No hosts to notify"
return 0
fi
tmpdir=$(mktemp -d /tmp/statd-$2.XXXXXX)
# Ok, copy the HA directory to something we can use.
mkdir -p $tmpdir/sm
# Copy in our specified entries
cp -f $nl_dir/sm/* $tmpdir/sm
# Copy in our global entries
# XXX This might be what we just copied.
if [ -d "/var/lib/nfs/statd/sm" ]; then
owner=$(ls -dl /var/lib/nfs/statd/sm | awk '{print $3"."$4}')
cp -f /var/lib/nfs/statd/sm/* $tmpdir/sm
elif [ -d "/var/lib/nfs/sm" ]; then
owner=$(ls -dl /var/lib/nfs/statd/sm | awk '{print $3"."$4}')
cp -f /var/lib/nfs/sm/* $tmpdir/sm
fi
#
# Generate a random state file. If this ends up being what a client
# already has in its list, that's bad, but the chances of this
# are small - and relocations should be rare.
#
dd if=/dev/urandom of=$tmpdir/state bs=1 count=4 &> /dev/null
#
# Make sure we set permissions, or statd will not like it.
#
chown -R $owner $tmpdir
#
# Tell rpc.statd to notify clients. Don't go into background,
# because statd is buggy and won't exit like it's supposed to after
# sending the notifications out.
#
ocf_log info "Sending reclaim notifications via $nl_ip"
command="rpc.statd -NFP $tmpdir -n $nl_ip"
eval $command 2>&1 &
sleep 3 # XXX - the instance of rpc.statd we just spawned is supposed
# to exit after it finishes notifying clients.
# rpc.statd spawned which is still running handles the actual
# new SM_MON requests... we hope 3 seconds is enough time
# to get all the SM_NOTIFY messages out. rpc.statd = bugged
#
# clean up
#
pid_xxx=`ps auwwx | grep "$command" | grep -v grep | awk '{print $2}'`
kill $pid_xxx
rm -rf $tmpdir
return 0
}
#
# Copy of isSlave from svclib_ip and/or ip.sh
#
nfslock_isSlave()
{
declare intf=$1
declare line
if [ -z "$intf" ]; then
ocf_log err "usage: isSlave <I/F>"
return 1
fi
line=$(/sbin/ip link list dev $intf)
if [ $? -ne 0 ]; then
ocf_log err "$intf not found"
return 1
fi
if [ "$line" = "${line/<*SLAVE*>/}" ]; then
return 2
fi
# Yes, it is a slave device. Ignore.
return 0
}
#
# Get all the IPs on the system except loopback IPs
#
nfslock_ip_address_list()
{
declare idx dev family ifaddr
while read idx dev family ifaddr; do
if [ "$family" != "inet" ] && [ "$family" != "inet6" ]; then
continue
fi
if [ "$dev" = "lo" ]; then
# Ignore loopback
continue
fi
nfslock_isSlave $dev
if [ $? -ne 2 ]; then
continue
fi
idx=${idx/:/}
echo $dev $family ${ifaddr/\/*/} ${ifaddr/*\//}
done < <(/sbin/ip -o addr list | awk '{print $1,$2,$3,$4}')
return 0
}
#
# Usage: broadcast_notify <state_directory>
#
# Send the contents of <state_directory> out via all IPs on the system.
#
notify_list_broadcast()
{
declare dev family addr maskbits ip_name
declare lockd_pid=$(pidof lockd)
declare nl_dir=$1
# First of all, send lockd a SIGKILL. We hope nfsd is running.
# If it is, this will cause lockd to reset the grace period for
# lock reclaiming.
if [ -n "$lockd_pid" ]; then
ocf_log info "Asking lockd to drop locks (pid $lockd_pid)"
kill -9 $lockd_pid
else
ocf_log warning "lockd not running; cannot notify clients"
return 1
fi
while read dev family addr maskbits; do
if [ "$family" != "inet" ]; then
continue
fi
ip_name=$(clufindhostname -i $addr)
if [ -z "$ip_name" ]; then
nfslock_statd_notify $nl_dir $addr
else
nfslock_statd_notify $nl_dir $ip_name
fi
done < <(nfslock_ip_address_list)
}
#
# Store the lock monitor list from rpc.statd - do this during a teardown
# after the IP addresses of a service have been taken offline. Note that
# this should be done by HA-callout programs, but this feature is not in
# RHEL3.
#
notify_list_store()
{
declare nl_dir=$1
declare owner
mkdir -p $nl_dir/sm
if [ -d "/var/lib/nfs/statd/sm" ]; then
if [ -z "`ls /var/lib/nfs/statd/sm/* 2> /dev/null`" ]; then
return 1
# nothing to do!
fi
owner=$(ls -dl /var/lib/nfs/statd/sm | awk '{print $3"."$4}')
cp -Rdpf /var/lib/nfs/statd/sm/* $nl_dir/sm
chown -R $owner $nl_dir
return 0
elif [ -d "/var/lib/nfs/sm" ]; then
if [ -z "`ls /var/lib/nfs/sm/* 2> /dev/null`" ]; then
return 1
# nothing to do!
fi
owner=$(ls -dl /var/lib/nfs/sm | awk '{print $3"."$4}')
cp -Rdpf /var/lib/nfs/sm/* $nl_dir/sm
chown -R $owner $nl_dir
return 0
fi
return 1
}
#
# Merge the contents of <nl_dir>/sm with the system-wide list
# Make sure ownership is right, or statd will hiccup. This should not
# actually ever be needed because statd will, upon getting a SM_MON
# request, create all the entries in this list. It's mostly for
# housekeeping for next time we relocate the service.
#
notify_list_merge()
{
declare nl_dir=$1
declare owner
if [ -z "`ls $nl_dir/* 2> /dev/null`" ]; then
return 1
fi
if [ -d "/var/lib/nfs/statd/sm" ]; then
owner=$(ls -dl /var/lib/nfs/statd/sm | awk '{print $3"."$4}')
cp -Rdpf $nl_dir/sm/* /var/lib/nfs/statd/sm
chown -R $owner $nl_dir
return 0
elif [ -d "/var/lib/nfs/sm" ]; then
owner=$(ls -dl /var/lib/nfs/sm | awk '{print $3"."$4}')
cp -Rdpf $nl_dir/sm/* /var/lib/nfs/sm
chown -R $owner $nl_dir
return 0
fi
return 1
}
diff --git a/rgmanager/src/resources/tomcat-5.sh b/rgmanager/src/resources/tomcat-5.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/tomcat-5.sh
rename to rgmanager/src/resources/tomcat-5.sh.in
index 814da0ff5..c414343b0
--- a/rgmanager/src/resources/tomcat-5.sh
+++ b/rgmanager/src/resources/tomcat-5.sh.in
@@ -1,274 +1,274 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
export LC_ALL=C
export LANG=C
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
declare TOMCAT_TOMCAT=/usr/bin/dtomcat5
declare TOMCAT_RELINK=/usr/share/tomcat5/bin/relink
declare TOMCAT_pid_file="`generate_name_for_pid_file`"
declare TOMCAT_conf_dir="`generate_name_for_conf_dir`/conf"
declare TOMCAT_gen_config_file="$TOMCAT_conf_dir/server.xml"
declare TOMCAT_gen_catalina_base="`generate_name_for_conf_dir`"
declare JAVA_HOME
declare CATALINA_HOME
declare CATALINA_BASE
declare CATALINA_TMPDIR
declare CLASSPATH
declare TOMCAT_USER
##
verify_all()
{
clog_service_verify $CLOG_INIT
if [ -z "$OCF_RESKEY_name" ]; then
clog_service_verify $CLOG_FAILED "Invalid Name Of Service"
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_service_name" ]; then
clog_service_verify $CLOG_FAILED_NOT_CHILD
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_INVALID "$OCF_RESKEY_config_file"
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
if [ ! -r "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_NOT_READABLE $OCF_RESKEY_config_file
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
. "$OCF_RESKEY_config_file"
if [ $? -ne 0 ]; then
clog_service_verify $CLOG_FAILED "Error In The File \"$OCF_RESKEY_config_file\""
return $OCF_ERR_ARGS
fi
if [ -z "$JAVA_HOME" ]; then
clog_service_verify $CLOG_FAILED "JAVA_HOME Not Specified In ${OCF_RESKEY_config_file}"
return $OCF_ERR_ARGS;
fi
if [ ! -d "$JAVA_HOME" ]; then
clog_service_verify $CLOG_FAILED "JAVA_HOME Does Not Exist"
return $OCF_ERR_ARGS;
fi
if [ -z "$JAVA_ENDORSED_DIRS" ]; then
clog_service_verify $CLOG_FAILED "JAVA_ENDORSED_DIRS Not Specified In ${OCF_RESKEY_config_file}"
return $OCF_ERR_ARGS;
fi
if [ ! -d "$JAVA_ENDORSED_DIRS" ]; then
clog_service_verify $CLOG_FAILED "JAVA_ENDORSED_DIRS Does Not Exist"
return $OCF_ERR_ARGS;
fi
if [ -z "$CATALINA_HOME" ]; then
clog_service_verify $CLOG_FAILED "CATALINA_HOME Not Specified In ${OCF_RESKEY_config_file}"
return $OCF_ERR_ARGS;
fi
if [ ! -d "$CATALINA_HOME" ]; then
clog_service_verify $CLOG_FAILED "CATALINA_HOME Does Not Exist"
return $OCF_ERR_ARGS;
fi
if [ -z "$CATALINA_TMPDIR" ]; then
clog_service_verify $CLOG_FAILED "CATALINA_TMPDIR Not Specified In ${OCF_RESKEY_config_file}"
return $OCF_ERR_ARGS;
fi
if [ ! -d "$CATALINA_TMPDIR" ]; then
clog_service_verify $CLOG_FAILED "CATALINA_TMPDIR Does Not Exist"
return $OCF_ERR_ARGS;
fi
if [ -z "$TOMCAT_USER" ]; then
clog_service_verify $CLOG_FAILED "TOMCAT_USER Does Not Exist"
return $OCF_ERR_ARGS;
fi
clog_service_verify $CLOG_SUCCEED
return 0
}
generate_config_file()
{
declare original_file="$1"
declare generated_file="$2"
declare ip_addresses="$3"
if [ -f "$generated_file" ]; then
sha1_verify "$generated_file"
if [ $? -ne 0 ]; then
clog_check_sha1 $CLOG_FAILED
return 0
fi
fi
clog_generate_config $CLOG_INIT "$original_file" "$generated_file"
generate_configTemplateXML "$generated_file" "$original_file"
$(dirname $0)/utils/tomcat-parse-config.pl $ip_addresses < "$original_file" >> "$generated_file"
sha1_addToFileXML "$generated_file"
clog_generate_config $CLOG_SUCCEED "$original_file" "$generated_file"
return 0;
}
start()
{
clog_service_start $CLOG_INIT
create_pid_directory
create_conf_directory "$TOMCAT_conf_dir"
check_pid_file "$TOMCAT_pid_file"
if [ $? -ne 0 ]; then
clog_check_pid $CLOG_FAILED "$TOMCAT_pid_file"
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_INIT "IP Addresses"
get_service_ip_keys "$OCF_RESKEY_service_name"
ip_addresses=`build_ip_list`
if [ -z "$ip_addresses" ]; then
clog_looking_for $CLOG_FAILED_NOT_FOUND "IP Addresses"
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_SUCCEED "IP Addresses"
generate_config_file "$OCF_RESKEY_catalina_base/conf/server.xml" "$TOMCAT_gen_config_file" "$ip_addresses"
ln -s "$OCF_RESKEY_catalina_base"/* "$TOMCAT_gen_catalina_base" &> /dev/null
ln -s "$OCF_RESKEY_catalina_base"/conf/* "$TOMCAT_gen_catalina_base"/conf &> /dev/null
CLASSPATH="$JAVA_HOME"/lib/tools.jar:"$CATALINA_HOME"/bin/bootstrap.jar:"$CATALINA_HOME"/bin/commons-logging-api.jar:`/usr/bin/build-classpath mx4j/mx4j-impl`:`/usr/bin/build-classpath mx4j/mx4j-jmx`
su "$TOMCAT_USER" -c " \"$JAVA_HOME/bin/java\" $JAVA_OPTS $OCF_RESKEY_catalina_options \
-Djava.endorsed.dirs=\"$JAVA_ENDORSED_DIRS\" -classpath \"$CLASSPATH\" \
-Dcatalina.base=\"$TOMCAT_gen_catalina_base\" \
-Dcatalina.home=\"$CATALINA_HOME\" \
-Djava.io.tmpdir=\"$CATALINA_TMPDIR\" \
org.apache.catalina.startup.Bootstrap \"$@\" start " \
>> "$TOMCAT_gen_catalina_base"/logs/catalina.out 2>&1 &
if [ $? -ne 0 ]; then
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
if [ -z "$!" ]; then
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
echo $! > "$TOMCAT_pid_file"
clog_service_start $CLOG_SUCCEED
return 0;
}
stop()
{
clog_service_stop $CLOG_INIT
stop_generic "$TOMCAT_pid_file" "$OCF_RESKEY_shutdown_wait"
if [ $? -ne 0 ]; then
clog_service_stop $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
if [ -e "$TOMCAT_pid_file" ]; then
rm -f "$TOMCAT_pid_file"
fi
clog_service_stop $CLOG_SUCCEED
return 0;
}
status()
{
clog_service_status $CLOG_INIT
status_check_pid "$TOMCAT_pid_file"
if [ $? -ne 0 ]; then
clog_service_status $CLOG_FAILED "$TOMCAT_pid_file"
return $OCF_ERR_GENERIC
fi
clog_service_status $CLOG_SUCCEED
return 0
}
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
exit 0
;;
validate-all)
verify_all
exit $?
;;
start)
verify_all && start
exit $?
;;
stop)
verify_all && stop
exit $?
;;
status|monitor)
verify_all
status
exit $?
;;
restart)
verify_all
stop
start
exit $?
;;
*)
echo "Usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/tomcat-6.sh b/rgmanager/src/resources/tomcat-6.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/tomcat-6.sh
rename to rgmanager/src/resources/tomcat-6.sh.in
index 879e1ecda..749a86d8d
--- a/rgmanager/src/resources/tomcat-6.sh
+++ b/rgmanager/src/resources/tomcat-6.sh.in
@@ -1,250 +1,250 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
export LC_ALL=C
export LANG=C
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
. $(dirname $0)/ocf-shellfuncs
. $(dirname $0)/utils/config-utils.sh
. $(dirname $0)/utils/messages.sh
. $(dirname $0)/utils/ra-skelet.sh
declare TOMCAT_pid_file="`generate_name_for_pid_file`"
declare TOMCAT_conf_dir="`generate_name_for_conf_dir`/conf"
declare TOMCAT_gen_config_file="$TOMCAT_conf_dir/server.xml"
declare TOMCAT_gen_catalina_base="`generate_name_for_conf_dir`"
declare CATALINA_HOME
declare CATALINA_BASE
declare CATALINA_TMPDIR
declare CLASSPATH
declare TOMCAT_USER
##
verify_all()
{
clog_service_verify $CLOG_INIT
if [ -z "$OCF_RESKEY_name" ]; then
clog_service_verify $CLOG_FAILED "Invalid Name Of Service"
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_service_name" ]; then
clog_service_verify $CLOG_FAILED_NOT_CHILD
return $OCF_ERR_ARGS
fi
if [ -z "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_INVALID "$OCF_RESKEY_config_file"
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
if [ ! -r "$OCF_RESKEY_config_file" ]; then
clog_check_file_exist $CLOG_FAILED_NOT_READABLE $OCF_RESKEY_config_file
clog_service_verify $CLOG_FAILED
return $OCF_ERR_ARGS
fi
. "$OCF_RESKEY_config_file"
if [ $? -ne 0 ]; then
clog_service_verify $CLOG_FAILED "Error In The File \"$OCF_RESKEY_config_file\""
return $OCF_ERR_ARGS
fi
if [ -z "$CATALINA_HOME" ]; then
clog_service_verify $CLOG_FAILED "CATALINA_HOME Not Specified In ${OCF_RESKEY_config_file}"
return $OCF_ERR_ARGS;
fi
if [ ! -d "$CATALINA_HOME" ]; then
clog_service_verify $CLOG_FAILED "CATALINA_HOME Does Not Exist"
return $OCF_ERR_ARGS;
fi
if [ -z "$CATALINA_TMPDIR" ]; then
clog_service_verify $CLOG_FAILED "CATALINA_TMPDIR Not Specified In ${OCF_RESKEY_config_file}"
return $OCF_ERR_ARGS;
fi
if [ ! -d "$CATALINA_TMPDIR" ]; then
clog_service_verify $CLOG_FAILED "CATALINA_TMPDIR Does Not Exist"
return $OCF_ERR_ARGS;
fi
if [ -z "$TOMCAT_USER" ]; then
clog_service_verify $CLOG_FAILED "TOMCAT_USER Does Not Exist"
return $OCF_ERR_ARGS;
fi
clog_service_verify $CLOG_SUCCEED
return 0
}
generate_config_file()
{
declare original_file="$1"
declare generated_file="$2"
declare ip_addresses="$3"
if [ -f "$generated_file" ]; then
sha1_verify "$generated_file"
if [ $? -ne 0 ]; then
clog_check_sha1 $CLOG_FAILED
return 0
fi
fi
clog_generate_config $CLOG_INIT "$original_file" "$generated_file"
$(dirname $0)/utils/tomcat-parse-config.pl $ip_addresses < "$original_file" > "$generated_file"
sha1_addToFileXML "$generated_file"
clog_generate_config $CLOG_SUCCEED "$original_file" "$generated_file"
return 0;
}
start()
{
clog_service_start $CLOG_INIT
create_conf_directory "$TOMCAT_conf_dir"
check_pid_file "$TOMCAT_pid_file"
if [ $? -ne 0 ]; then
clog_check_pid $CLOG_FAILED "$TOMCAT_pid_file"
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_INIT "IP Addresses"
get_service_ip_keys "$OCF_RESKEY_service_name"
ip_addresses=`build_ip_list`
if [ -z "$ip_addresses" ]; then
clog_looking_for $CLOG_FAILED_NOT_FOUND "IP Addresses"
return $OCF_ERR_GENERIC
fi
clog_looking_for $CLOG_SUCCEED "IP Addresses"
. "$OCF_RESKEY_config_file"
create_pid_directory "$TOMCAT_USER"
generate_config_file "$CATALINA_BASE/conf/server.xml" "$TOMCAT_gen_config_file" "$ip_addresses"
rm -f "$TOMCAT_gen_catalina_base/conf/tomcat6.conf"
( cat $OCF_RESKEY_config_file | grep -v 'CATALINA_PID=' | grep -v 'CATALINA_BASE='; echo CATALINA_BASE="$TOMCAT_gen_catalina_base"; echo CATALINA_PID="$TOMCAT_pid_file") > "$TOMCAT_gen_catalina_base/conf/tomcat6.conf"
ln -s "$CATALINA_BASE"/* "$TOMCAT_gen_catalina_base" &> /dev/null
ln -s "$CATALINA_BASE"/conf/* "$TOMCAT_gen_catalina_base"/conf &> /dev/null
export TOMCAT_CFG="$TOMCAT_gen_catalina_base/conf/tomcat6.conf"
tomcat6_options="$tomcat6_options $(
awk '!/^#/ && !/^$/ { ORS=" "; print "export ", $0, ";" }' \
$TOMCAT_CFG
)"
eval "$tomcat6_options"
/bin/su -s /bin/sh $TOMCAT_USER -c "/usr/sbin/tomcat6 start"
if [ $? -ne 0 ]; then
clog_service_start $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
clog_service_start $CLOG_SUCCEED
return 0;
}
stop()
{
clog_service_stop $CLOG_INIT
stop_generic "$TOMCAT_pid_file" "$OCF_RESKEY_shutdown_wait"
if [ $? -ne 0 ]; then
clog_service_stop $CLOG_FAILED
return $OCF_ERR_GENERIC
fi
if [ -e "$TOMCAT_pid_file" ]; then
rm -f "$TOMCAT_pid_file"
fi
clog_service_stop $CLOG_SUCCEED
return 0;
}
status()
{
clog_service_status $CLOG_INIT
status_check_pid "$TOMCAT_pid_file"
if [ $? -ne 0 ]; then
clog_service_status $CLOG_FAILED "$TOMCAT_pid_file"
return $OCF_ERR_GENERIC
fi
clog_service_status $CLOG_SUCCEED
return 0
}
case $1 in
meta-data)
cat `echo $0 | sed 's/^\(.*\)\.sh$/\1.metadata/'`
exit 0
;;
validate-all)
verify_all
exit $?
;;
start)
verify_all && start
exit $?
;;
stop)
verify_all
stop
exit $?
;;
status|monitor)
verify_all
status
exit $?
;;
restart)
verify_all
stop
start
exit $?
;;
*)
echo "Usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
diff --git a/rgmanager/src/resources/utils/config-utils.sh b/rgmanager/src/resources/utils/config-utils.sh.in
similarity index 99%
rename from rgmanager/src/resources/utils/config-utils.sh
rename to rgmanager/src/resources/utils/config-utils.sh.in
index 95265d5f7..b59bcc724 100644
--- a/rgmanager/src/resources/utils/config-utils.sh
+++ b/rgmanager/src/resources/utils/config-utils.sh.in
@@ -1,309 +1,309 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
declare RA_COMMON_pid_dir=/var/run/cluster
declare RA_COMMON_conf_dir=/etc/cluster
declare -i FAIL=255
declare -a ip_keys
generate_configTemplate()
{
cat > "$1" << EOT
#
# "$1" was created from the "$2"
#
# This template configuration was automatically generated, and will be
# automatically regenerated if removed. Once this file has been altered,
# automatic re-generation will stop. Remember to copy this file to all
# other cluster members after making changes, or your service will not
# operate correctly.
#
EOT
}
generate_configTemplateXML()
{
cat > "$1" << EOT
<!--
"$1" was created from the "$2"
This template configuration was automatically generated, and will be
automatically regenerated if removed. Once this file has been altered,
automatic re-generation will stop. Remember to copy this file to all
other cluster members after making changes, or your service will not
operate correctly.
-->
EOT
}
sha1_addToFile()
{
declare sha1line="# rgmanager-sha1 $(sha1sum "$1")"
echo $sha1line >> "$1"
}
sha1_addToFileXML()
{
declare sha1line="<!--# rgmanager-sha1 $(sha1sum "$1")-->"
echo $sha1line >> "$1"
}
sha1_verify()
{
declare sha1_new sha1_old
declare oldFile=$1
ocf_log debug "Checking: SHA1 checksum of config file $oldFile"
sha1_new=`cat "$oldFile" | grep -v "# rgmanager-sha1" | sha1sum | sed 's/^\([a-z0-9]\+\) .*$/\1/'`
sha1_old=`tail -n 1 "$oldFile" | sed 's/^\(<!--\)\?# rgmanager-sha1 \(.*\)$/\2/' | sed 's/^\([a-z0-9]\+\) .*$/\1/'`
if [ "$sha1_new" = "$sha1_old" ]; then
ocf_log debug "Checking: SHA1 checksum > succeed"
return 0;
else
ocf_log debug "Checking: SHA1 checksum > failed - file changed"
return 1;
fi
}
#
# Usage: ccs_get key
#
ccs_get()
{
declare outp
declare key
[ -n "$1" ] || return $FAIL
key="$*"
outp=$(ccs_tool query "$key" 2>&1)
if [ $? -ne 0 ]; then
if [[ "$outp" =~ "Query failed: Invalid argument" ]]; then
# This usually means that element does not exist
# e.g. when checking for IP address
return 0;
fi
if [ "$outp" = "${outp/No data available/}" ] || [ "$outp" = "${outp/Operation not permitted/}" ]; then
ocf_log err "$outp ($key)"
return $FAIL
fi
# no real error, just no data available
return 0
fi
echo $outp
return 0
}
#
# Build a list of service IP keys; traverse refs if necessary
# Usage: get_service_ip_keys desc serviceName
#
get_service_ip_keys()
{
declare svc=$1
declare -i x y=0
declare outp
declare key
#
# Find service-local IP keys
#
x=1
while : ; do
key="/cluster/rm/service[@name=\"$svc\"]/ip[$x]"
#
# Try direct method
#
outp=$(ccs_get "$key/@address")
if [ $? -ne 0 ]; then
return 1
fi
#
# Try by reference
#
if [ -z "$outp" ]; then
outp=$(ccs_get "$key/@ref")
if [ $? -ne 0 ]; then
return 1
fi
key="/cluster/rm/resources/ip[@address=\"$outp\"]"
fi
if [ -z "$outp" ]; then
break
fi
#ocf_log debug "IP $outp found @ $key"
ip_keys[$y]="$key"
((y++))
((x++))
done
ocf_log debug "$y IP addresses found for $svc/$OCF_RESKEY_name"
return 0
}
build_ip_list()
{
declare ipaddrs ipaddr
declare -i x=0
while [ -n "${ip_keys[$x]}" ]; do
ipaddr=$(ccs_get "${ip_keys[$x]}/@address")
if [ -z "$ipaddr" ]; then
break
fi
# remove netmask
iponly=`echo $ipaddr | sed 's/\/.*//'`
ipaddrs="$ipaddrs $iponly"
((x++))
done
echo $ipaddrs
}
generate_name_for_pid_file()
{
declare filename=$(basename $0)
echo "$RA_COMMON_pid_dir/$(basename $0 | sed 's/^\(.*\)\..*/\1/')/$OCF_RESOURCE_INSTANCE.pid"
return 0;
}
generate_name_for_pid_dir()
{
declare filename=$(basename $0)
echo "$RA_COMMON_pid_dir/$(basename $0 | sed 's/^\(.*\)\..*/\1/')/$OCF_RESOURCE_INSTANCE"
return 0;
}
generate_name_for_conf_dir()
{
declare filename=$(basename $0)
echo "$RA_COMMON_conf_dir/$(basename $0 | sed 's/^\(.*\)\..*/\1/')/$OCF_RESOURCE_INSTANCE"
return 0;
}
set_pid_directory_permissions()
{
declare program_name="$1"
declare dirname="$2"
declare username="$3"
if [ "$program_name" = "mysql" ]; then
if [ -n "$username" ]; then
chown "${username}.root" "$dirname"
else
chown mysql.root "$dirname"
fi
elif [ "$program_name" = "tomcat-5" -o "$program_name" = "tomcat-6" ]; then
if [ -n "$username" ]; then
chown "${username}.root" "$dirname"
else
chown tomcat.root "$dirname"
fi
elif [ "$program_name" = "named" ]; then
if [ -n "$username" ]; then
chown "${username}.root" "$dirname"
fi
fi
}
#
# Usage: create_pid_directory [username]
#
create_pid_directory()
{
declare program_name="$(basename $0 | sed 's/^\(.*\)\..*/\1/')"
declare dirname="$RA_COMMON_pid_dir/$program_name"
declare username="$1"
if [ -d "$dirname" ]; then
# make sure the permissions are correct even if directory exists
set_pid_directory_permissions "$program_name" "$dirname" "$username"
return 0;
fi
chmod 711 "$RA_COMMON_pid_dir"
mkdir -p "$dirname"
set_pid_directory_permissions "$program_name" "$dirname" "$username"
return 0;
}
create_conf_directory()
{
declare dirname="$1"
if [ -d "$dirname" ]; then
return 0;
fi
mkdir -p "$dirname"
return 0;
}
check_pid_file() {
declare pid_file="$1"
if [ -z "$pid_file" ]; then
return 1;
fi
if [ ! -e "$pid_file" ]; then
return 0;
fi
## if PID file is empty then it should be safe to remove it
read pid < "$pid_file"
if [ -z "$pid" ]; then
rm $pid_file
ocf_log debug "PID File \"$pid_file\" Was Removed - Zero length";
return 0;
fi
if [ ! -d /proc/`cat "$pid_file"` ]; then
rm "$pid_file"
ocf_log debug "PID File \"$pid_file\" Was Removed - PID Does Not Exist";
return 0;
fi
return 1;
}
diff --git a/rgmanager/src/resources/utils/fs-lib.sh b/rgmanager/src/resources/utils/fs-lib.sh.in
similarity index 99%
rename from rgmanager/src/resources/utils/fs-lib.sh
rename to rgmanager/src/resources/utils/fs-lib.sh.in
index 9d91c793f..8b0ef5ec7 100644
--- a/rgmanager/src/resources/utils/fs-lib.sh
+++ b/rgmanager/src/resources/utils/fs-lib.sh.in
@@ -1,1230 +1,1230 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
# File system common functions
#
LC_ALL=C
LANG=C
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LC_ALL LANG PATH
# Define this value to 0 by default, bind-mount.sh or any other agent
# that uses this value will alter it after sourcing fs-lib.sh
export IS_BIND_MOUNT=0
# Private return codes
FAIL=2
NO=1
YES=0
YES_STR="yes"
[ -z "$OCF_RESOURCE_INSTANCE" ] && export OCF_RESOURCE_INSTANCE="filesystem:$OCF_RESKEY_name"
#
# Using a global to contain the return value saves
# clone() operations. This is important to reduce
# resource consumption during status checks.
#
# There is no way to return a string from a function
# in bash without cloning the process, which is exactly
# what we are trying to avoid. So, we have to resort
# to using a dedicated global variables.
declare REAL_DEVICE
declare STRIP_SLASHES=""
declare FINDMNT_OUTPUT=""
#
# Stub ocf_log function for when we are using
# quick_status, since ocf_log generally forks (and
# sourcing ocf-shellfuncs forks -a lot-).
#
ocf_log()
{
echo $*
}
#
# Assume NFS_TRICKS are not available until we are
# proved otherwise.
#
export NFS_TRICKS=1
#
# Quick status doesn't fork() or clone() when using
# device files directly. (i.e. not symlinks, LABEL= or
# UUID=
#
if [ "$1" = "status" -o "$1" = "monitor" ] &&
[ "$OCF_RESKEY_quick_status" = "1" ]; then
echo Using Quick Status
# XXX maybe we can make ocf-shellfuncs have a 'quick' mode too?
export OCF_SUCCESS=0
export OCF_ERR_GENERIC=1
else
#
# Grab nfs lock tricks if available
#
if [ -f "$(dirname $0)/svclib_nfslock" ]; then
. $(dirname $0)/svclib_nfslock
NFS_TRICKS=0
fi
. $(dirname $0)/ocf-shellfuncs
fi
verify_name()
{
if [ -z "$OCF_RESKEY_name" ]; then
ocf_log err "No file system name specified."
return $OCF_ERR_ARGS
fi
return $OCF_SUCCESS
}
verify_mountpoint()
{
if [ -z "$OCF_RESKEY_mountpoint" ]; then
ocf_log err "No mount point specified."
return $OCF_ERR_ARGS
fi
if ! [ -e "$OCF_RESKEY_mountpoint" ]; then
ocf_log info "Mount point $OCF_RESKEY_mountpoint will be "\
"created at mount time."
return $OCF_SUCCESS
fi
[ -d "$OCF_RESKEY_mountpoint" ] && return $OCF_SUCCESS
ocf_log err "$OCF_RESKEY_mountpoint exists but is not a directory."
return $OCF_ERR_ARGS
}
#
# This used to be called using $(...), but doing this causes bash
# to set up a pipe and clone(). So, the output of this function is
# stored in the global variable REAL_DEVICE, declared previously.
#
real_device()
{
declare dev="$1"
declare realdev
if [ $IS_BIND_MOUNT -eq 1 ]; then
REAL_DEVICE="$dev"
return $OCF_SUCCESS
fi
REAL_DEVICE=""
[ -z "$dev" ] && return $OCF_ERR_ARGS
# Oops, we have a link. Sorry, this is going to fork.
if [ -h "$dev" ]; then
realdev=$(readlink -f $dev)
if [ $? -ne 0 ]; then
return $OCF_ERR_ARGS
fi
REAL_DEVICE="$realdev"
return $OCF_SUCCESS
fi
# If our provided blockdev is a device, we are done
if [ -b "$dev" ]; then
REAL_DEVICE="$dev"
return $OCF_SUCCESS
fi
# It's not a link, it's not a block device. If it also
# does not match UUID= or LABEL=, then findfs is not
# going to find anything useful, so we should quit now.
if [ "${dev/UUID=/}" = "$dev" ] &&
[ "${dev/LABEL=/}" = "$dev" ]; then
return $OCF_ERR_GENERIC
fi
# When using LABEL= or UUID=, we can't save a fork.
realdev=$(findfs "$dev" 2> /dev/null)
if [ -n "$realdev" ] && [ -b "$realdev" ]; then
REAL_DEVICE="$realdev"
return $OCF_SUCCESS
fi
return $OCF_ERR_GENERIC
}
verify_device()
{
declare realdev
if [ -z "$OCF_RESKEY_device" ]; then
ocf_log err "No device or label specified."
return $OCF_ERR_ARGS
fi
real_device "$OCF_RESKEY_device"
realdev="$REAL_DEVICE"
if [ -n "$realdev" ]; then
if [ "$realdev" != "$OCF_RESKEY_device" ]; then
ocf_log info "Specified $OCF_RESKEY_device maps to $realdev"
fi
return $OCF_SUCCESS
fi
ocf_log err "Device or label \"$OCF_RESKEY_device\" not valid"
return $OCF_ERR_ARGS
}
list_mounts()
{
if [ $IS_BIND_MOUNT -eq 1 ]; then
cat /etc/mtab
else
cat /proc/mounts
fi
}
##
# Tries to use findmnt util to return list
# of mountpoints for a device
#
# Global variables are used to reduce forking when capturing stdout.
#
# Return values
# 0 - device mount points found, mountpoint list returned to FINDMNT_OUTPUT global variable
# 1 - device mount not found
# 2 - findmnt tool isn't found or can not be used
#
##
try_findmnt()
{
FINDMNT_OUTPUT=""
case $OCF_RESKEY_use_findmnt in
0|false|no|off)
return 2 ;;
*)
: ;;
esac
which findmnt > /dev/null 2>&1
if [ $? -eq 0 ]; then
FINDMNT_OUTPUT="$(findmnt -o TARGET --noheadings $1)"
if [ $? -ne 0 ]; then
# workaround mount helpers inconsistency that still
# add / on the device entry in /proc/mounts
FINDMNT_OUTPUT="$(findmnt -o TARGET --noheadings $1/)"
if [ $? -ne 0 ]; then
return 1
else
return 0
fi
else
return 0
fi
fi
return 2
}
##
# Returns result in global variable to reduce forking
##
strip_trailing_slashes()
{
local tmp=$1
while [ "${tmp#${tmp%?}}" = "/" ]
do
tmp="${tmp%/}"
done
STRIP_SLASHES="$tmp"
}
#
# kill_procs_using_mount mount_point [signal]
#
# Kill any processes using the specified mountpoint, using the optional
# specified signal. This is used in place of fuser to avoid it becoming
# blocked while following symlinks to an unresponsive file system.
# Defaults to SIGKILL if no signal specified.
#
kill_procs_using_mount () {
declare mp
declare procs
declare mmap_procs
if [ $# -lt 1 -o -z "$1" ]; then
ocf_log err "Usage: kill_procs_using_mount mount_point [signal]"
return $FAIL
fi
strip_trailing_slashes "$1"
mp="$STRIP_SLASHES"
if [ -z "$mp" ]; then
ocf_log err "Usage: kill_procs_using_mount mount_point [signal]"
return $FAIL
fi
# anything held open in mount point after the slash
procs=$(find /proc/[0-9]*/ -type l -lname "${mp}/*" -or -lname "${mp}" 2>/dev/null | awk -F/ '{print $3}' | uniq)
# anything with memory mapping to something in the mountpoint
mmap_procs=$(grep " ${mp}" /proc/[0-9]*/maps | awk -F/ '{print $3}' | uniq)
procs=$(echo -e "${procs}\n${mmap_procs}" | sort | uniq)
for pid in $procs; do
if [ -n "$2" ]; then
kill -s $2 $pid
else
kill -s KILL $pid
fi
done
return $SUCCESS
}
#
# mount_in_use device mount_point
#
# Check to see if either the device or mount point are in use anywhere on
# the system. It is not required that the device be mounted on the named
# moint point, just if either are in use.
#
mount_in_use () {
declare mp tmp_mp
declare tmp_type
declare dev tmp_dev
declare junkb junkc junkd
declare res=$FAIL
declare findmnt_res=2
if [ $# -ne 2 ]; then
ocf_log err "Usage: mount_in_use device mount_point".
return $FAIL
fi
dev="$1"
mp="$2"
# First try and find out if the device has a mount point by
# attempting to use the findmnt tool. It is much faster than
# iterating through /proc/mounts
try_findmnt $dev
findmnt_res=$?
if [ $findmnt_res -eq 0 ]; then
case $OCF_RESKEY_fstype in
cifs|nfs|nfs4)
# -r means to include '/' character and not treat it as escape character
while read -r tmp_mp
do
if [ "$tmp_mp" = "$mp" ]; then
return $YES
fi
done < <(echo "$FINDMNT_OUTPUT")
;;
*)
return $YES
;;
esac
fi
while read -r tmp_dev tmp_mp tmp_type junkb junkc junkd; do
if [ "$tmp_type" = "autofs" ]; then
continue
fi
# Does the device match? We might have already tried findmnt
# which is why this could get skipped
if [ $findmnt_res -eq 2 ]; then
if [ "${tmp_dev:0:1}" != "-" ]; then
# XXX fork/clone warning XXX
tmp_dev="$(printf "$tmp_dev")"
fi
strip_trailing_slashes "$tmp_dev"
tmp_dev="$STRIP_SLASHES"
if [ -n "$tmp_dev" -a "$tmp_dev" = "$dev" ]; then
case $OCF_RESKEY_fstype in
cifs|nfs|nfs4)
;;
*)
return $YES
;;
esac
fi
fi
# Mountpoint from /proc/mounts containing spaces will
# have spaces represented in octal. printf takes care
# of this for us.
tmp_mp="$(printf "$tmp_mp")"
if [ -n "$tmp_mp" -a "$tmp_mp" = "$mp" ]; then
return $YES
fi
done < <(list_mounts)
return $NO
}
##
# Returns whether or not the device is mounted.
# If the mountpoint does not match the one provided, the
# mount point found is printed to stdout.
##
real_mountpoint()
{
declare dev=$1
declare mp=$2
declare ret=$NO
declare tmp_mp
declare tmp_dev
declare tmp_type
declare found=1
declare poss_mp=""
try_findmnt $dev
case $? in
0) #findmnt found mount points, loop through them to find a match
# -r means to include '/' character and not treat it as escape character
while read -r tmp_mp
do
ret=$YES
if [ "$tmp_mp" != "$mp" ]; then
poss_mp=$tmp_mp
else
found=0
break
fi
done < <(echo "$FINDMNT_OUTPUT")
;;
1)
# findmnt found no mount points for the device
return $NO
;;
2) # findmnt tool could not be used.
# Using slow method reading /proc/mounts dir.
while read -r tmp_dev tmp_mp tmp_type junk_b junk_c junk_d
do
if [ "$tmp_type" = "autofs" ]; then
continue
fi
if [ "${tmp_dev:0:1}" != "-" ]; then
# XXX fork/clone warning XXX
tmp_dev="$(printf "$tmp_dev")"
fi
# CIFS mounts can sometimes have trailing slashes
# in their first field in /proc/mounts, so strip them.
strip_trailing_slashes "$tmp_dev"
tmp_dev="$STRIP_SLASHES"
real_device "$tmp_dev"
tmp_dev="$REAL_DEVICE"
# XXX fork/clone warning XXX
# Mountpoint from /proc/mounts containing spaces will
# have spaces represented in octal. printf takes care
# of this for us.
tmp_mp="$(printf "$tmp_mp")"
if [ -n "$tmp_dev" -a "$tmp_dev" = "$dev" ]; then
ret=$YES
#
# Check to see if its mounted in the right
# place
#
if [ -n "$tmp_mp" ]; then
if [ "$tmp_mp" != "$mp" ]; then
poss_mp=$tmp_mp
else
found=0
break
fi
fi
fi
done < <(list_mounts)
esac
if [ $found -ne 0 ]; then
echo "$poss_mp"
fi
return $ret
}
#
# is_mounted device mount_point
#
# Check to see if the device is mounted. Print a warning if its not
# mounted on the directory we expect it to be mounted on.
#
is_mounted () {
declare mp
declare dev
declare ret=$FAIL
declare poss_mp
if [ $# -ne 2 ]; then
ocf_log err "Usage: is_mounted device mount_point"
return $FAIL
fi
real_device "$1"
dev="$REAL_DEVICE"
if [ -z "$dev" ]; then
ocf_log err "$OCF_RESOURCE_INSTANCE: is_mounted: Could not match $1 with a real device"
return $OCF_ERR_ARGS
fi
if [ -h "$2" ]; then
mp="$(readlink -f $2)"
else
mp="$2"
fi
# This bash glyph simply removes a trailing slash
# if one exists. /a/b/ -> /a/b; /a/b -> /a/b.
mp="${mp%/}"
poss_mp=$(real_mountpoint "$dev" "$mp")
ret=$?
if [ $ret -eq $YES ] && [ -n "$poss_mp" ]; then
# if we made it here, then the device is mounted, but not where
# we expected it to be
case $OCF_RESKEY_fstype in
cifs|nfs|nfs4)
ret=$NO
;;
*)
ocf_log warn "Device $dev is mounted on $poss_mp instead of $mp"
;;
esac
fi
return $ret
}
#
# is_alive mount_point
#
# Check to see if mount_point is alive (testing read/write)
#
is_alive()
{
declare errcode
declare mount_point="$1"
declare file
declare rw
if [ $# -ne 1 ]; then
ocf_log err "Usage: is_alive mount_point"
return $FAIL
fi
[ -z "$OCF_CHECK_LEVEL" ] && export OCF_CHECK_LEVEL=0
test -d "$mount_point"
if [ $? -ne 0 ]; then
ocf_log err "${OCF_RESOURCE_INSTANCE}: is_alive: $mount_point is not a directory"
return $FAIL
fi
[ $OCF_CHECK_LEVEL -lt 10 ] && return $YES
# depth 10 test (read test)
ls "$mount_point" > /dev/null 2> /dev/null
errcode=$?
if [ $errcode -ne 0 ]; then
ocf_log err "${OCF_RESOURCE_INSTANCE}: is_alive: failed read test on [$mount_point]. Return code: $errcode"
return $NO
fi
[ $OCF_CHECK_LEVEL -lt 20 ] && return $YES
# depth 20 check (write test)
rw=$YES
for o in `echo $OCF_RESKEY_options | sed -e s/,/\ /g`; do
if [ "$o" = "ro" ]; then
rw=$NO
fi
done
if [ $rw -eq $YES ]; then
file=$(mktemp "$mount_point/.check_writable.$(hostname).XXXXXX")
if [ ! -e "$file" ]; then
ocf_log err "${OCF_RESOURCE_INSTANCE}: is_alive: failed write test on [$mount_point]. Return code: $errcode"
return $NO
fi
rm -f $file > /dev/null 2> /dev/null
fi
return $YES
}
#
# Decide which quota options are enabled and return a string
# which we can pass to quotaon
#
quota_opts()
{
declare quotaopts=""
declare opts="$1"
declare mopt
for mopt in `echo $opts | sed -e s/,/\ /g`; do
case $mopt in
quota)
quotaopts="gu"
break
;;
usrquota)
quotaopts="u$quotaopts"
continue
;;
grpquota)
quotaopts="g$quotaopts"
continue
;;
noquota)
quotaopts=""
return 0
;;
esac
done
echo $quotaopts
return 0
}
#
# Enable quotas on the mount point if the user requested them
#
enable_fs_quotas()
{
declare -i need_check=0
declare -i rv
declare quotaopts=""
declare mopt
declare opts="$1"
declare mp="$2"
if ! type quotaon &> /dev/null; then
ocf_log err "quotaon not found in $PATH"
return $OCF_ERR_GENERIC
fi
quotaopts=$(quota_opts $opts)
[ -z "$quotaopts" ] && return 0
ocf_log debug "quotaopts = $quotaopts"
# Ok, create quota files if they don't exist
for f in quota.user aquota.user quota.group aquota.group; do
if ! [ -f "$mp/$f" ]; then
ocf_log info "$mp/$f was missing - creating"
touch "$mp/$f"
chmod 600 "$mp/$f"
need_check=1
fi
done
if [ $need_check -eq 1 ]; then
ocf_log info "Checking quota info in $mp"
quotacheck -$quotaopts "$mp"
fi
ocf_log info "Enabling Quotas on $mp"
ocf_log debug "quotaon -$quotaopts \"$mp\""
quotaon -$quotaopts "$mp"
rv=$?
if [ $rv -ne 0 ]; then
# Just a warning
ocf_log warn "Unable to turn on quotas for $mp; return = $rv"
fi
return $rv
}
# Agent-specific actions to take before mounting
# (if required). Typically things like fsck.
do_pre_mount() {
return 0
}
# Default mount handler - for block devices
#
do_mount() {
declare dev="$1"
declare mp="$2"
declare mount_options=""
declare fstype_option=""
declare fstype
#
# Get the filesystem type, if specified.
#
fstype_option=""
fstype=${OCF_RESKEY_fstype}
case "$fstype" in
""|"[ ]*")
fstype=""
;;
*) # found it
fstype_option="-t $fstype"
;;
esac
#
# Get the mount options, if they exist.
#
mount_options=""
opts=${OCF_RESKEY_options}
case "$opts" in
""|"[ ]*")
opts=""
;;
*) # found it
mount_options="-o $opts"
;;
esac
#
# Mount the device
#
ocf_log info "mounting $dev on $mp"
ocf_log err "mount $fstype_option $mount_options $dev $mp"
mount $fstype_option $mount_options "$dev" "$mp"
ret_val=$?
if [ $ret_val -ne 0 ]; then
ocf_log err "\
'mount $fstype_option $mount_options $dev $mp' failed, error=$ret_val"
return 1
fi
return 0
}
# Agent-specific actions to take after mounting
# (if required).
do_post_mount() {
return 0
}
# Agent-specific actions to take before unmounting
# (if required)
do_pre_unmount() {
return 0
}
# Agent-specific actions to take after umount succeeds
# (if required)
do_post_unmount() {
return 0
}
# Agent-specific force unmount logic, if required
# return = 0 if successful, or nonzero if unsuccessful
# (unsuccessful = try harder)
do_force_unmount() {
return 1
}
#
# start_filesystem
#
start_filesystem() {
declare -i ret_val=$OCF_SUCCESS
declare mp="${OCF_RESKEY_mountpoint}"
declare dev="" # device
declare fstype=""
declare opts=""
declare mount_options=""
#
# Check if fstype is supported
#
verify_fstype
case $? in
$OCF_ERR_ARGS)
ocf_log err "File system type $OCF_RESKEY_fstype not supported"
return $OCF_ERR_ARGS
;;
*)
;;
esac
#
# Check if mount point was specified. If not, no need to continue.
#
case "$mp" in
""|"[ ]*") # nothing to mount
return $OCF_SUCCESS
;;
/*) # found it
;;
*) # invalid format
ocf_log err \
"start_filesystem: Invalid mount point format (must begin with a '/'): \'$mp\'"
return $OCF_ERR_ARGS
;;
esac
#
# Get the device
#
real_device "$OCF_RESKEY_device"
dev="$REAL_DEVICE"
if [ -z "$dev" ]; then
ocf_log err "\
start_filesystem: Could not match $OCF_RESKEY_device with a real device"
return $OCF_ERR_ARGS
fi
#
# Ensure we've got a valid directory
#
if [ -e "$mp" ]; then
if ! [ -d "$mp" ]; then
ocf_log err"\
start_filesystem: Mount point $mp exists but is not a directory"
return $OCF_ERR_ARGS
fi
else
ocf_log err "\
start_filesystem: Creating mount point $mp for device $dev"
mkdir -p "$mp"
ret_val=$?
if [ $ret_val -ne 0 ]; then
ocf_log err "\
start_filesystem: Unable to create $mp. Error code: $ret_val"
return $OCF_ERR_GENERIC
fi
fi
#
# See if the device is already mounted.
#
is_mounted "$dev" "$mp"
case $? in
$YES) # already mounted
ocf_log debug "$dev already mounted"
return $OCF_SUCCESS
;;
$NO) # not mounted, continue
;;
*)
return $FAIL
;;
esac
#
# Make sure that neither the device nor the mount point are mounted
# (i.e. they may be mounted in a different location). The'mount_in_use'
# function checks to see if either the device or mount point are in
# use somewhere else on the system.
#
mount_in_use "$dev" "$mp"
case $? in
$YES) # uh oh, someone is using the device or mount point
ocf_log err "\
Cannot mount $dev on $mp, the device or mount point is already in use!"
return $FAIL
;;
$NO) # good, no one else is using it
;;
$FAIL)
return $FAIL
;;
*)
ocf_log err "Unknown return from mount_in_use"
return $FAIL
;;
esac
do_pre_mount
case $? in
0)
;;
1)
return $OCF_ERR_GENERIC
;;
2)
return $OCF_SUCCESS
;;
esac
do_mount "$dev" "$mp"
case $? in
0)
;;
1)
return $OCF_ERR_GENERIC
;;
2)
return $OCF_SUCCESS
;;
esac
do_post_mount
case $? in
0)
;;
1)
return $OCF_ERR_GENERIC
;;
2)
return $OCF_SUCCESS
;;
esac
enable_fs_quotas "$opts" "$mp"
return $OCF_SUCCESS
}
#
# stop_filesystem - unmount a file system; calls out to
#
stop_filesystem() {
declare -i ret_val=0
declare -i try
declare -i sleep_time=5 # time between each umount failure
declare umount_failed=""
declare force_umount=""
declare self_fence=""
declare quotaopts=""
#
# Get the mount point, if it exists. If not, no need to continue.
#
mp=${OCF_RESKEY_mountpoint}
case "$mp" in
""|"[ ]*") # nothing to mount
return $OCF_SUCCESS
;;
/*) # found it
;;
*) # invalid format
ocf_log err \
"stop_filesystem: Invalid mount point format (must begin with a '/'): \'$mp\'"
return $FAIL
;;
esac
#
# Get the device
#
real_device "$OCF_RESKEY_device"
dev="$REAL_DEVICE"
if [ -z "$dev" ]; then
ocf_log err "\
stop: Could not match $OCF_RESKEY_device with a real device"
return $OCF_ERR_INSTALLED
fi
#
# Get the force unmount setting if there is a mount point.
#
case ${OCF_RESKEY_force_unmount} in
$YES_STR) force_umount=$YES ;;
on) force_umount=$YES ;;
true) force_umount=$YES ;;
1) force_umount=$YES ;;
*) force_umount="" ;;
esac
#
# self_fence _MUST_ be initialized before calling do_pre_unmount
# The netfs agent depends on the self_fence variable.
#
case ${OCF_RESKEY_self_fence} in
$YES_STR) self_fence=$YES ;;
on) self_fence=$YES ;;
true) self_fence=$YES ;;
1) self_fence=$YES ;;
*) self_fence="" ;;
esac
do_pre_unmount
case $? in
0)
;;
1)
return $OCF_ERR_GENERIC
;;
2)
return $OCF_SUCCESS
;;
esac
#
# Preparations: sync, turn off quotas
#
sync
quotaopts=$(quota_opts $OCF_RESKEY_options)
if [ -n "$quotaopts" ]; then
ocf_log debug "Turning off quotas for $mp"
quotaoff -$quotaopts "$mp" &> /dev/null
fi
#
# Unmount the device.
#
for try in 1 2 3; do
if [ $try -ne 1 ]; then
sleep $sleep_time
fi
is_mounted "$dev" "$mp"
case $? in
$NO)
ocf_log info "$dev is not mounted"
umount_failed=
break
;;
$YES) # fallthrough
;;
*)
return $FAIL
;;
esac
case ${OCF_RESKEY_no_unmount} in
yes|YES|true|TRUE|YES|on|ON|1)
ocf_log debug "Skipping umount on stop because of 'no_unmount' option"
return $OCF_SUCCESS
;;
*) : ;;
esac
ocf_log info "unmounting $mp"
umount "$mp"
ret_val=$?
# some versions of umount will exit with status 16 iff
# the umount(2) succeeded but /etc/mtab could not be written.
if [ $ret_val -eq 0 -o $ret_val -eq 16 ]; then
umount_failed=
break
fi
ocf_log debug "umount failed: $ret_val"
umount_failed=yes
if [ -z "$force_umount" ]; then
continue
fi
# Force unmount: try #1: send SIGTERM
if [ $try -eq 1 ]; then
# Try fs-specific force unmount, if provided
do_force_unmount
if [ $? -eq 0 ]; then
# if this succeeds, we should be done
continue
fi
ocf_log warning "Sending SIGTERM to processes on $mp"
kill_procs_using_mount "$mp" "TERM"
continue
else
ocf_log warning "Sending SIGKILL to processes on $mp"
kill_procs_using_mount "$mp"
if [ $? -eq 0 ]; then
# someone is still accessing the mount, We've already sent
# SIGTERM, now we've sent SIGKILL and are trying umount again.
continue
fi
# mount has failed, and no one is accessing it. There's
# nothing left for us to try.
break
fi
done # for
do_post_unmount
case $? in
0)
;;
1)
return $OCF_ERR_GENERIC
;;
2)
return $OCF_SUCCESS
;;
esac
if [ -n "$umount_failed" ]; then
ocf_log err "'umount $mp' failed, error=$ret_val"
if [ "$self_fence" ]; then
ocf_log alert "umount failed - REBOOTING"
sync
reboot -fn
fi
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
do_start() {
declare tries=0
declare rv
while [ $tries -lt 3 ]; do
start_filesystem
rv=$?
if [ $rv -eq 0 ]; then
return 0
fi
((tries++))
sleep 3
done
return $rv
}
do_stop() {
stop_filesystem
return $?
}
do_monitor() {
ocf_log debug "Checking fs \"$OCF_RESKEY_name\", Level $OCF_CHECK_LEVEL"
#
# Get the device
#
real_device "$OCF_RESKEY_device"
dev="$REAL_DEVICE"
if [ -z "$dev" ]; then
ocf_log err "\
start_filesystem: Could not match $OCF_RESKEY_device with a real device"
return $OCF_NOT_RUNNING
fi
is_mounted "$dev" "${OCF_RESKEY_mountpoint}"
if [ $? -ne $YES ]; then
ocf_log err "${OCF_RESOURCE_INSTANCE}: ${OCF_RESKEY_device} is not mounted on ${OCF_RESKEY_mountpoint}"
return $OCF_NOT_RUNNING
fi
if [ "$OCF_RESKEY_quick_status" = "1" ]; then
return 0
fi
is_alive "${OCF_RESKEY_mountpoint}"
[ $? -eq $YES ] && return 0
ocf_log err "fs:${OCF_RESKEY_name}: Mount point is not accessible!"
return $OCF_ERR_GENERIC
}
do_restart() {
stop_filesystem
if [ $? -ne 0 ]; then
return $OCF_ERR_GENERIC
fi
start_filesystem
if [ $? -ne 0 ]; then
return $OCF_ERR_GENERIC
fi
return 0
}
# MUST BE OVERRIDDEN
do_metadata() {
return 1
}
do_validate() {
return 1
}
main() {
case $1 in
start)
do_start
exit $?
;;
stop)
do_stop
exit $?
;;
status|monitor)
do_monitor
exit $?
;;
restart)
do_restart
exit $?
;;
meta-data)
do_metadata
exit $?
;;
validate-all)
do_validate
;;
*)
echo "usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit 0
}
diff --git a/rgmanager/src/resources/utils/member_util.sh b/rgmanager/src/resources/utils/member_util.sh.in
similarity index 99%
rename from rgmanager/src/resources/utils/member_util.sh
rename to rgmanager/src/resources/utils/member_util.sh.in
index 51b1bcece..0dab7b798 100644
--- a/rgmanager/src/resources/utils/member_util.sh
+++ b/rgmanager/src/resources/utils/member_util.sh.in
@@ -1,116 +1,116 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
# Use corosync-quorumtool to figure out if the specified node is a member
# of the cluster. Returns 1 if not a member, and
# 0 if the node is happily running.
#
# Tested on RHEL6 and F17 Note that the old version of this function utilized
# clustat, which had introspection in to the configuration.
# If a node was not found, the old version would return '2', but the only
# consumer of this function never cared about that value.
#
is_node_member_clustat()
{
local node="$1"
local output_list
# Still having a tag while (a) online but (b) not running pacemaker
# (e.g. crm_node) or rgmanager not considered adequate for things like
# the LVM agent - so we use corosync-quorumtool instead. The function
# name really should be changed.
#
# corosync 1.4.1 output looks like:
#
# # corosync-quorumtool -l
# Nodeid Name
# 1 rhel6-1
# 2 rhel6-2
#
# corosync 2.0.1 output looks like:
# # corosync-quorumtool -l
#
# Membership information
# ----------------------
# Nodeid Votes Name
# 1 1 rhel7-1.priv.redhat.com
# 2 1 rhel7-2.priv.redhat.com
#
output_list=$(corosync-quorumtool -l | grep -v "^Nodeid")
# first try searching for the node in the output as both a FQDN or shortname
echo "$output_list" | grep -i -e " $node\$" -e " $node\..*\$" &> /dev/null && return 0
# if the node was not found in the quorum list, try any known aliases found in /etc/hosts
for alias in $(cat /etc/hosts | grep -e "\s$node\s" -e "\s$node\$" | tail -n 1 | sed 's/\t/ /g' | cut -f2- -d " ");
do
echo "$output_list" | grep -i -e " $alias\$" &> /dev/null && return 0
done
return 1
}
#
# Print the local node name to stdout
# Returns 0 if could be found, 1 if not
# Tested on RHEL6 (cman) and Fedora 17 (corosync/pacemaker)
#
local_node_name()
{
local node nid localid
if which magma_tool &> /dev/null; then
# Use magma_tool, if available.
line=$(magma_tool localname | grep "^Local")
if [ -n "$line" ]; then
echo ${line/* = /}
return 0
fi
fi
if which cman_tool &> /dev/null; then
# Use cman_tool
line=$(cman_tool status | grep -i "Node name: $1")
[ -n "$line" ] || return 1
echo ${line/*name: /}
return 0
fi
if ! which crm_node &> /dev/null; then
# no crm_node? :(
return 2
fi
localid=$(crm_node -i)
while read nid node; do
if [ "$nid" = "$localid" ]; then
echo $node
return 0
fi
done < <(crm_node -l)
return 1
}
diff --git a/rgmanager/src/resources/utils/messages.sh b/rgmanager/src/resources/utils/messages.sh.in
similarity index 99%
rename from rgmanager/src/resources/utils/messages.sh
rename to rgmanager/src/resources/utils/messages.sh.in
index 0f8d7ff97..1c4f13c22 100644
--- a/rgmanager/src/resources/utils/messages.sh
+++ b/rgmanager/src/resources/utils/messages.sh.in
@@ -1,269 +1,269 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
declare CLOG_INIT=100
declare CLOG_SUCCEED=200
declare CLOG_SUCCEED_KILL=201
declare CLOG_FAILED=400
declare CLOG_FAILED_TIMEOUT=401
declare CLOG_FAILED_NOT_FOUND=403
declare CLOG_FAILED_INVALID=404
declare CLOG_FAILED_NOT_READABLE=405
declare CLOG_FAILED_KILL=406
##
## Usage:
## clog_service_start %operation%
##
clog_service_start()
{
case $1 in
$CLOG_INIT)
ocf_log info "Starting Service $OCF_RESOURCE_INSTANCE"
;;
$CLOG_SUCCEED)
ocf_log debug "Starting Service $OCF_RESOURCE_INSTANCE > Succeed"
;;
$CLOG_FAILED)
ocf_log error "Starting Service $OCF_RESOURCE_INSTANCE > Failed"
;;
$CLOG_FAILED_TIMEOUT)
ocf_log error "Starting Service $OCF_RESOURCE_INSTANCE > Failed - Timeout Error"
;;
esac
return 0
}
##
## Usage:
## clog_service_stop %operation%
##
clog_service_stop()
{
case $1 in
$CLOG_INIT)
ocf_log info "Stopping Service $OCF_RESOURCE_INSTANCE"
;;
$CLOG_SUCCEED)
ocf_log info "Stopping Service $OCF_RESOURCE_INSTANCE > Succeed"
;;
$CLOG_SUCCEED_KILL)
ocf_log info "Killing Service $OCF_RESOURCE_INSTANCE > Succeed"
;;
$CLOG_FAILED)
ocf_log error "Stopping Service $OCF_RESOURCE_INSTANCE > Failed"
;;
$CLOG_FAILED_NOT_STOPPED)
ocf_log error "Stopping Service $OCF_RESOURCE_INSTANCE > Failed - Application Is Still Running"
;;
$CLOG_FAILED_KILL)
ocf_log error "Killing Service $OCF_RESOURCE_INSTANCE > Failed"
;;
esac
return 0
}
##
## Usage:
## clog_service_status %operation%
##
clog_service_status()
{
case $1 in
$CLOG_INIT)
ocf_log debug "Monitoring Service $OCF_RESOURCE_INSTANCE"
;;
$CLOG_SUCCEED)
ocf_log debug "Monitoring Service $OCF_RESOURCE_INSTANCE > Service Is Running"
;;
$CLOG_FAILED)
ocf_log error "Monitoring Service $OCF_RESOURCE_INSTANCE > Service Is Not Running"
;;
$CLOG_FAILED_NOT_FOUND)
ocf_log error "Monitoring Service $OCF_RESOURCE_INSTANCE > Service Is Not Running - PID File Not Found"
;;
esac
return 0
}
##
## Usage:
## clog_service_verify %operation%
## clog_service_verify $CLOG_FAILED %reason%
##
clog_service_verify()
{
case $1 in
$CLOG_INIT)
ocf_log debug "Verifying Configuration Of $OCF_RESOURCE_INSTANCE"
;;
$CLOG_SUCCEED)
ocf_log debug "Verifying Configuration Of $OCF_RESOURCE_INSTANCE > Succeed"
;;
$CLOG_FAILED_NOT_CHILD)
ocf_log error "Service $OCF_RESOURCE_INSTANCE Is Not A Child Of A Service"
;;
$CLOG_FAILED)
if [ "x$2" = "x" ]; then
ocf_log error "Verifying Configuration Of $OCF_RESOURCE_INSTANCE > Failed"
else
ocf_log error "Verifying Configuration Of $OCF_RESOURCE_INSTANCE > Failed - $2"
fi
;;
esac
return 0
}
##
## Usage:
## clog_check_sha1 %operation% %filename%
##
clog_check_sha1()
{
case $1 in
$CLOG_INIT)
ocf_log debug "Checking SHA1 Checksum Of File $1"
;;
$CLOG_SUCCEED)
ocf_log debug "Checking SHA1 Checksum Of File > Succeed"
;;
$CLOG_FAILED)
ocf_log debug "Checking SHA1 Checksum Of File > Failed - File Changed"
;;
esac
return 0;
}
##
## Usage:
## clog_check_file_exist %operation% %filename%
##
clog_check_file_exist()
{
case $1 in
$CLOG_INIT)
ocf_log debug "Checking Existence Of File $2"
;;
$CLOG_SUCCEED)
ocf_log debug "Checking Existence Of File $2 > Succeed"
;;
$CLOG_FAILED)
ocf_log error "Checking Existence Of File $2 [$OCF_RESOURCE_INSTANCE] > Failed"
;;
$CLOG_FAILED_INVALID)
ocf_log error "Checking Existence Of File $2 [$OCF_RESOURCE_INSTANCE] > Failed - Invalid Argument"
;;
$CLOG_FAILED_NOT_FOUND)
ocf_log error "Checking Existence Of File $2 [$OCF_RESOURCE_INSTANCE] > Failed - File Doesn't Exist"
;;
$CLOG_FAILED_NOT_READABLE)
ocf_log error "Checking Existence Of File $2 [$OCF_RESOURCE_INSTANCE] > Failed - File Is Not Readable"
;;
esac
return 0;
}
##
## Usage:
## clog_check_pid %operation% %filename%
##
clog_check_pid()
{
case $1 in
$CLOG_INIT)
ocf_log debug "Checking Non-Existence Of PID File $2"
return 0
;;
$CLOG_SUCCEED)
ocf_log debug "Checking Non-Existence of PID File $2 > Succeed"
;;
$CLOG_FAILED)
ocf_log error "Checking Non-Existence of PID File $2 [$OCF_RESOURCE_INSTANCE] > Failed - PID File Exists For $OCF_RESOURCE_INSTANCE"
;;
esac
return 0;
}
##
## Usage:
## clog_check_syntax %operation% %filename%
##
clog_check_syntax()
{
case $1 in
$CLOG_INIT)
ocf_log debug "Checking Syntax Of The File $2"
;;
$CLOG_SUCCEED)
ocf_log debug "Checking Syntax Of The File $2 > Succeed"
;;
$CLOG_FAILED)
ocf_log error "Checking Syntax Of The File $2 [$OCF_RESOURCE_INSTANCE] > Failed"
;;
esac
return 0;
}
##
## Usage:
## clog_generate_config %operation% %old filename% %new filename%
##
clog_generate_config()
{
case $1 in
$CLOG_INIT)
ocf_log debug "Generating New Config File $3 From $2"
;;
$CLOG_SUCCEED)
ocf_log debug "Generating New Config File $3 From $2 > Succeed"
;;
$CLOG_FAILED)
ocf_log error "Generating New Config File $3 From $2 [$OCF_RESOURCE_INSTANCE] > Failed"
;;
esac
return 0;
}
##
## Usage:
## clog_looking_for %operation% %resource%
## clog_looking_for %operation% "IP Addresses"
## clog_looking_for %operation% "Filesystems"
##
clog_looking_for()
{
case $1 in
$CLOG_INIT)
ocf_log debug "Looking For $2"
;;
$CLOG_SUCCEED)
ocf_log debug "Looking For $2 > Succeed - $3 $2 Found"
;;
$CLOG_FAILED)
ocf_log error "Looking For $2 [$OCF_RESOURCE_INSTANCE] > Failed"
;;
$CLOG_FAILED_NOT_FOUND)
ocf_log error "Looking For $2 [$OCF_RESOURCE_INSTANCE] > Failed - No $2 Found"
;;
esac
return 0;
}
diff --git a/rgmanager/src/resources/utils/ra-skelet.sh b/rgmanager/src/resources/utils/ra-skelet.sh.in
similarity index 99%
rename from rgmanager/src/resources/utils/ra-skelet.sh
rename to rgmanager/src/resources/utils/ra-skelet.sh.in
index cdee5c47c..ee943b2a8 100644
--- a/rgmanager/src/resources/utils/ra-skelet.sh
+++ b/rgmanager/src/resources/utils/ra-skelet.sh.in
@@ -1,156 +1,156 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
status_check_pid()
{
declare pid_file="$1"
if [ -z "$pid_file" ]; then
clog_check_file_exist $CLOG_FAILED_INVALID "$pid_file"
return $OCF_ERR_GENERIC
fi
if [ ! -e "$pid_file" ]; then
clog_check_file_exist $CLOG_FAILED "$pid_file"
return $OCF_NOT_RUNNING
fi
read pid < "$pid_file"
if [ -z "$pid" ]; then
return $OCF_ERR_GENERIC
fi
if [ ! -d /proc/$pid ]; then
return $OCF_ERR_GENERIC
fi
return 0
}
stop_generic()
{
declare pid_file="$1"
declare stop_timeout="$2"
declare stop_sig="$3"
declare pid;
declare count=0;
if [ -z "$stop_sig" ]; then
stop_sig="-TERM"
fi
if [ ! -e "$pid_file" ]; then
clog_check_file_exist $CLOG_FAILED_NOT_FOUND "$pid_file"
# In stop-after-stop situation there is no PID file but
# it will be nice to check for it in stop-after-start
# look at bug #449394
return 0
fi
if [ -z "$stop_timeout" ]; then
stop_timeout=20
fi
read pid < "$pid_file"
# @todo: PID file empty -> error?
if [ -z "$pid" ]; then
return 0;
fi
# @todo: PID is not running -> error?
if [ ! -d "/proc/$pid" ]; then
return 0;
fi
kill $stop_sig "$pid"
if [ $? -ne 0 ]; then
return $OCF_ERR_GENERIC
fi
until [ `ps --pid "$pid" &> /dev/null; echo $?` = '1' ] || [ $count -gt $stop_timeout ]
do
sleep 1
let count=$count+1
done
if [ $count -gt $stop_timeout ]; then
clog_service_stop $CLOG_FAILED_NOT_STOPPED
return $OCF_ERR_GENERIC
fi
return 0;
}
stop_generic_sigkill() {
# Use stop_generic (kill -TERM) and if application did not stop
# correctly then use kill -QUIT and check if it was killed
declare pid_file="$1"
declare stop_timeout="$2"
declare kill_timeout="$3"
declare stop_sig="$4"
declare pid
if [ -z "$stop_sig" ]; then
stop_sig="-TERM"
fi
## If stop_timeout is equal to zero then we do not want
## to give -TERM signal at all.
if [ $stop_timeout -ne 0 ]; then
stop_generic "$pid_file" "$stop_timeout" "$stop_sig"
if [ $? -eq 0 ]; then
return 0;
fi
fi
if [ ! -e "$pid_file" ]; then
clog_check_file_exist $CLOG_FAILED_NOT_FOUND "$pid_file"
# In stop-after-stop situation there is no PID file but
# it will be nice to check for it in stop-after-start
# look at bug #449394
return 0
fi
read pid < "$pid_file"
if [ -z "$pid" ]; then
return 0;
fi
if [ ! -d "/proc/$pid" ]; then
return 0;
fi
kill -QUIT "$pid"
if [ $? -ne 0 ]; then
return $OCF_GENERIC_ERROR
fi
sleep "$kill_timeout"
ps --pid "$pid" &> /dev/null
if [ $? -eq 0 ]; then
clog_service_stop $CLOG_FAILED_KILL
return $OCF_ERR_GENERIC
fi
clog_service_stop $CLOG_SUCCEED_KILL
return 0
}
diff --git a/rgmanager/src/resources/vm.sh b/rgmanager/src/resources/vm.sh.in
old mode 100755
new mode 100644
similarity index 99%
rename from rgmanager/src/resources/vm.sh
rename to rgmanager/src/resources/vm.sh.in
index 4c602ff29..a76495f21
--- a/rgmanager/src/resources/vm.sh
+++ b/rgmanager/src/resources/vm.sh.in
@@ -1,1231 +1,1231 @@
-#!/bin/bash
+#!@BASH_SHELL@
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
PATH=/bin:/sbin:/usr/bin:/usr/sbin
# Only allow pid status checks during monitor operations.
# Otherwise we want proceed with failing if virsh is not available.
ALLOW_PID_STATUS_CHECK=0
if [ "$1" = "monitor" ] || [ "$1" = "status" ]; then
ALLOW_PID_STATUS_CHECK=1
fi
export PATH
. $(dirname $0)/ocf-shellfuncs || exit 1
#
# Virtual Machine start/stop script (requires the virsh command)
#
EMULATOR_STATE="/var/run/vm-${OCF_RESKEY_name}-emu.state"
# Indeterminate state: xend/libvirtd is down.
export OCF_APP_ERR_INDETERMINATE=150
meta_data()
{
cat <<EOT
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1-modified.dtd">
<resource-agent version="rgmanager 2.0" name="vm">
<version>1.0</version>
<longdesc lang="en">
Defines a Virtual Machine
</longdesc>
<shortdesc lang="en">
Defines a Virtual Machine
</shortdesc>
<parameters>
<parameter name="name" primary="1">
<longdesc lang="en">
This is the name of the virtual machine.
</longdesc>
<shortdesc lang="en">
Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="domain" reconfig="1">
<longdesc lang="en">
Failover domains define lists of cluster members
to try in the event that the host of the virtual machine
fails.
</longdesc>
<shortdesc lang="en">
Cluster failover Domain
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="autostart" reconfig="1">
<longdesc lang="en">
If set to yes, this resource group will automatically be started
after the cluster forms a quorum. If set to no, this virtual
machine will start in the 'disabled' state after the cluster
forms a quorum.
</longdesc>
<shortdesc lang="en">
Automatic start after quorum formation
</shortdesc>
<content type="boolean" default="1"/>
</parameter>
<parameter name="exclusive" reconfig="1">
<longdesc lang="en">
If set, this resource group will only relocate to
nodes which have no other resource groups running in the
event of a failure. If no empty nodes are available,
this resource group will not be restarted after a failure.
Additionally, resource groups will not automatically
relocate to the node running this resource group. This
option can be overridden by manual start and/or relocate
operations.
</longdesc>
<shortdesc lang="en">
Exclusive resource group
</shortdesc>
<content type="boolean" default="0"/>
</parameter>
<parameter name="recovery" reconfig="1">
<longdesc lang="en">
This currently has three possible options: "restart" tries
to restart this virtual machine locally before
attempting to relocate (default); "relocate" does not bother
trying to restart the VM locally; "disable" disables
the VM if it fails.
</longdesc>
<shortdesc lang="en">
Failure recovery policy
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="migration_mapping" reconfig="1">
<longdesc lang="en">
Mapping of the hostname of a target cluster member to a different hostname
</longdesc>
<shortdesc lang="en">
memberhost:targethost,memberhost:targethost ..
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="use_virsh">
<longdesc lang="en">
Force use of virsh instead of xm on Xen machines.
</longdesc>
<shortdesc lang="en">
If set to 1, vm.sh will use the virsh command to manage
virtual machines instead of xm. This is required when
using non-Xen virtual machines (e.g. qemu / KVM).
</shortdesc>
<content type="integer" default=""/>
</parameter>
<parameter name="xmlfile">
<longdesc lang="en">
Full path to libvirt XML file describing the domain.
</longdesc>
<shortdesc lang="en">
Full path to libvirt XML file describing the domain.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="migrate">
<longdesc lang="en">
Migration type (live or pause, default = live).
</longdesc>
<shortdesc lang="en">
Migration type (live or pause, default = live).
</shortdesc>
<content type="string" default="live"/>
</parameter>
<parameter name="migrate_options">
<longdesc lang="en">
Extra options for the guest live migration.
</longdesc>
<shortdesc lang="en">
Extra options for the guest live migration.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="tunnelled">
<longdesc lang="en">
Tunnel data over ssh to securely migrate virtual machines.
</longdesc>
<shortdesc lang="en">
Tunnel data over ssh to securely migrate virtual machines.
</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="path">
<longdesc lang="en">
Path specification vm.sh will search for the specified
VM configuration file. /path1:/path2:...
</longdesc>
<shortdesc lang="en">
Path to virtual machine configuration files.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="snapshot">
<longdesc lang="en">
Path to the snapshot directory where the virtual machine
image will be stored.
</longdesc>
<shortdesc lang="en">
Path to the snapshot directory where the virtual machine
image will be stored.
</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="depend">
<longdesc lang="en">
Service dependency; will not start without the specified
service running.
</longdesc>
<shortdesc lang="en">
Top-level service this depends on, in service:name format.
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="depend_mode">
<longdesc lang="en">
Service dependency mode.
hard - This service is stopped/started if its dependency
is stopped/started
soft - This service only depends on the other service for
initial startip. If the other service stops, this
service is not stopped.
</longdesc>
<shortdesc lang="en">
Service dependency mode (soft or hard).
</shortdesc>
<content type="string" default="hard"/>
</parameter>
<parameter name="max_restarts" reconfig="1">
<longdesc lang="en">
Maximum restarts for this service.
</longdesc>
<shortdesc lang="en">
Maximum restarts for this service.
</shortdesc>
<content type="string" default="0"/>
</parameter>
<parameter name="restart_expire_time" reconfig="1">
<longdesc lang="en">
Restart expiration time. A restart is forgotten
after this time. When combined with the max_restarts
option, this lets administrators specify a threshold
for when to fail over services. If max_restarts
is exceeded in this given expiration time, the service
is relocated instead of restarted again.
</longdesc>
<shortdesc lang="en">
Restart expiration time; amount of time before a restart
is forgotten.
</shortdesc>
<content type="string" default="0"/>
</parameter>
<parameter name="status_program" reconfig="1">
<longdesc lang="en">
Ordinarily, only the presence/health of a virtual machine
is checked. If specified, the status_program value is
executed during a depth 10 check. The intent of this
program is to ascertain the status of critical services
within a virtual machine.
</longdesc>
<shortdesc lang="en">
Additional status check program
</shortdesc>
<content type="string" default=""/>
</parameter>
<parameter name="hypervisor">
<longdesc lang="en">
Specify hypervisor tricks to use. Default = auto.
Other supported options are xen and qemu.
</longdesc>
<shortdesc lang="en">
Hypervisor
</shortdesc >
<content type="string" default="auto"/>
</parameter>
<parameter name="hypervisor_uri">
<longdesc lang="en">
Hypervisor URI. Generally, this is keyed off of the
hypervisor and does not need to be set.
</longdesc>
<shortdesc lang="en">
Hypervisor URI (normally automatic).
</shortdesc >
<content type="string" default="auto" />
</parameter>
<parameter name="migration_uri">
<longdesc lang="en">
Migration URI. Generally, this is keyed off of the
hypervisor and does not need to be set.
</longdesc>
<shortdesc lang="en">
Migration URI (normally automatic).
</shortdesc >
<content type="string" default="auto" />
</parameter>
<parameter name="no_kill">
<longdesc lang="en">
Do not force kill vm during stop, instead
fail after the timeout expires.
</longdesc>
<shortdesc lang="en">
Don't force kill vm on stop.
</shortdesc >
<content type="boolean" default="false" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="300"/>
<action name="stop" timeout="120"/>
<action name="status" timeout="10" interval="30"/>
<action name="monitor" timeout="10" interval="30"/>
<!-- depth 10 calls the status_program -->
<action name="status" depth="10" timeout="20" interval="60"/>
<action name="monitor" depth="10" timeout="20" interval="60"/>
<!-- reconfigure - reconfigure with new OCF parameters.
NOT OCF COMPATIBLE AT ALL -->
<action name="reconfig" timeout="10"/>
<action name="migrate" timeout="10m"/>
<action name="meta-data" timeout="5"/>
<action name="validate-all" timeout="5"/>
</actions>
<special tag="rgmanager">
<!-- Destroy_on_delete / init_on_add are currently only
supported for migratory resources (no children
and the 'migrate' action; see above. Do not try this
with normal services -->
<attributes maxinstances="1" destroy_on_delete="0" init_on_add="0"/>
</special>
</resource-agent>
EOT
}
build_virsh_cmdline()
{
declare cmdline=""
declare operation=$1
if [ -n "$OCF_RESKEY_hypervisor_uri" ]; then
cmdline="$cmdline -c $OCF_RESKEY_hypervisor_uri"
fi
cmdline="$cmdline $operation $OCF_RESKEY_name"
echo $cmdline
}
# this is only used on startup
build_xm_cmdline()
{
declare operation=$1
#
# Virtual domains should never restart themselves when
# controlled externally; the external monitoring app
# should.
#
declare cmdline="on_shutdown=\"destroy\" on_reboot=\"destroy\" on_crash=\"destroy\""
if [ -n "$OCF_RESKEY_path" ]; then
operation="$operation --path=\"$OCF_RESKEY_path\""
fi
if [ -n "$OCF_RESKEY_name" ]; then
cmdline="$operation $OCF_RESKEY_name $cmdline"
fi
echo $cmdline
}
do_xm_start()
{
# Use /dev/null for the configuration file, if xmdefconfig
# doesn't exist...
#
declare cmdline
echo -n "Virtual machine $OCF_RESKEY_name is "
do_status && return 0
cmdline="`build_xm_cmdline create`"
ocf_log debug "xm $cmdline"
eval xm $cmdline
return $?
}
get_timeout()
{
declare -i default_timeout=60
declare -i tout=60
if [ -n "$OCF_RESKEY_RGMANAGER_meta_timeout" ]; then
tout=$OCF_RESKEY_RGMANAGER_meta_timeout
elif [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then
tout=$OCF_RESKEY_CRM_meta_timeout
fi
if [ $tout -eq 0 ]; then
echo $default_timeout
return 0
fi
if [ $tout -lt 0 ]; then
echo $default_timeout
return 0
fi
echo $tout
return 0
}
get_emulator()
{
local emulator=""
emulator=$(virsh $VIRSH_OPTIONS dumpxml $OCF_RESKEY_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 $OCF_RESKEY_name"
fi
}
update_emulator_cache()
{
local emulator
emulator=$(get_emulator)
if [ -n "$emulator" ]; then
echo $emulator > $EMULATOR_STATE
fi
}
#
# Start a virtual machine given the parameters from
# the environment.
#
do_virsh_start()
{
declare cmdline
declare snapshotimage
declare rc
echo -n "Virtual machine $OCF_RESKEY_name is "
do_status && return 0
snapshotimage="$OCF_RESKEY_snapshot/$OCF_RESKEY_name"
if [ -n "$OCF_RESKEY_snapshot" -a -f "$snapshotimage" ]; then
eval virsh restore $snapshotimage
if [ $? -eq 0 ]; then
rm -f $snapshotimage
return 0
fi
return 1
fi
if [ -n "$OCF_RESKEY_xmlfile" -a -f "$OCF_RESKEY_xmlfile" ]; then
# TODO: try to use build_virsh_cmdline for the hypervisor_uri
cmdline="virsh create $OCF_RESKEY_xmlfile"
else
cmdline="virsh $(build_virsh_cmdline start)"
fi
ocf_log debug "$cmdline"
$cmdline
rc=$?
update_emulator_cache
return $rc
}
do_xm_stop()
{
declare -i timeout=60
declare -i ret=1
declare st
for op in $*; do
echo "CMD: xm $op $OCF_RESKEY_name"
xm $op $OCF_RESKEY_name
timeout=60
while [ $timeout -gt 0 ]; do
sleep 5
((timeout -= 5))
do_status&>/dev/null || return 0
while read dom state; do
#
# State is "stopped". Kill it.
#
if [ "$dom" != "$OCF_RESKEY_name" ]; then
continue
fi
if [ "$state" != "---s-" ]; then
continue
fi
xm destroy $OCF_RESKEY_name
done < <(xm list | awk '{print $1, $5}')
done
done
return 1
}
#
# Stop a VM. Try to shut it down. Wait a bit, and if it
# doesn't shut down, destroy it.
#
do_virsh_stop()
{
declare -i timeout=$(get_timeout)
declare -i ret=1
declare state
state=$(do_status)
[ $? -eq 0 ] || return 0
if [ -n "$OCF_RESKEY_snapshot" ]; then
virsh save $OCF_RESKEY_name "$OCF_RESKEY_snapshot/$OCF_RESKEY_name"
fi
for op in $*; do
echo virsh $op $OCF_RESKEY_name ...
virsh $op $OCF_RESKEY_name
timeout=$(get_timeout)
while [ $timeout -gt 0 ]; do
sleep 5
((timeout -= 5))
state=$(do_status)
[ $? -eq 0 ] || return 0
if [ "$state" = "paused" ]; then
virsh destroy $OCF_RESKEY_name
fi
done
done
ocf_log err "Stop operation timed out for vm '$OCF_RESKEY_name'"
return 1
}
do_start()
{
if [ "$OCF_RESKEY_use_virsh" = "1" ]; then
do_virsh_start $*
return $?
fi
do_xm_start $*
return $?
}
do_stop()
{
declare domstate rv
domstate=$(do_status)
rv=$?
ocf_log debug "Virtual machine $OCF_RESKEY_name is $domstate"
if [ $rv -eq $OCF_APP_ERR_INDETERMINATE ]; then
ocf_log crit "xend/libvirtd is dead; cannot stop $OCF_RESKEY_name"
return 1
fi
if [ "$OCF_RESKEY_use_virsh" = "1" ]; then
do_virsh_stop $*
return $?
fi
do_xm_stop $*
return $?
}
#
# Reconfigure a running VM.
#
reconfigure()
{
return 0
}
xm_status()
{
service xend status &> /dev/null
if [ $? -ne 0 ]; then
# if xend died
echo indeterminate
return $OCF_APP_ERR_INDETERMINATE
fi
xm list $OCF_RESKEY_name &> /dev/null
if [ $? -eq 0 ]; then
echo "running"
return 0
fi
xm list migrating-$OCF_RESKEY_name &> /dev/null
if [ $? -eq 0 ]; then
echo "running"
return 0
fi
echo "not running"
return $OCF_NOT_RUNNING
}
# attempt to check domain status outside of libvirt using the emulator process
vm_pid_status()
{
local rc=$OCF_ERR_GENERIC
local emulator
if [ $ALLOW_PID_STATUS_CHECK -eq 0 ]; then
echo "indeterminate"
return $OCF_APP_ERR_INDETERMINATE
fi
emulator=$(get_emulator)
case "$emulator" in
qemu-kvm|qemu-system-*)
rc=$OCF_NOT_RUNNING
ps awx | grep -E "[q]emu-(kvm|system).*-name $OCF_RESKEY_name " > /dev/null 2>&1
if [ $? -eq 0 ]; then
rc=$OCF_SUCCESS
fi
;;
# This can be expanded to check for additional emulators
*)
echo "indeterminate"
return $OCF_APP_ERR_INDETERMINATE
;;
esac
if [ $rc -eq $OCF_SUCCESS ]; then
echo "running"
elif [ $rc -eq $OCF_NOT_RUNNING ]; then
echo "shut off"
fi
return $rc
}
virsh_status()
{
declare state pid
if [ "$OCF_RESKEY_hypervisor" = "xen" ]; then
service xend status &> /dev/null
if [ $? -ne 0 ]; then
echo indeterminate
return $OCF_APP_ERR_INDETERMINATE
fi
fi
#
# libvirtd is required when using virsh even though
# not specifically when also using Xen. This is because
# libvirtd is required for migration.
#
pid=$(pidof libvirtd)
if [ -z "$pid" ]; then
# attempt to determine if vm is running from pid file
vm_pid_status
return $?
fi
state=$(virsh domstate $OCF_RESKEY_name)
echo $state
if [ "$state" = "running" ] || [ "$state" = "paused" ] || [ "$state" = "no state" ] ||
[ "$state" = "idle" ]; then
update_emulator_cache
return 0
fi
if [ "$state" = "shut off" ]; then
return $OCF_NOT_RUNNING
fi
return $OCF_ERR_GENERIC
}
#
# Simple status check: Find the VM in the list of running
# VMs
#
do_status()
{
if [ "$OCF_RESKEY_use_virsh" = "1" ]; then
virsh_status
return $?
fi
xm_status
return $?
}
#
# virsh "path" attribute support
#
check_config_file()
{
declare path=$1
if [ -f "$path/$OCF_RESKEY_name" ]; then
echo $path/$OCF_RESKEY_name
return 2
elif [ -f "$path/$OCF_RESKEY_name.xml" ]; then
echo $path/$OCF_RESKEY_name.xml
return 2
fi
return 0
}
parse_input()
{
declare delim=$1
declare input=$2
declare func=$3
declare inp
declare value
while [ -n "$input" ]; do
value=${input/$delim*/}
if [ -n "$value" ]; then
eval $func $value
if [ $? -eq 2 ]; then
return 0
fi
fi
inp=${input/$value$delim/}
if [ "$input" = "$inp" ]; then
inp=${input/$value/}
fi
input=$inp
done
}
search_config_path()
{
declare config_file=$(parse_input ":" "$OCF_RESKEY_path" check_config_file)
if [ -n "$config_file" ]; then
export OCF_RESKEY_xmlfile=$config_file
return 0
fi
return 1
}
choose_management_tool()
{
declare -i is_xml
#
# Don't override user value for use_virsh if one is given
#
if [ -n "$OCF_RESKEY_use_virsh" ]; then
return 0
fi
which xmllint &> /dev/null
if [ $? -ne 0 ]; then
ocf_log warning "Could not find xmllint; assuming virsh mode"
export OCF_RESKEY_use_virsh=1
unset OCF_RESKEY_path
return 0
fi
xmllint $OCF_RESKEY_xmlfile &> /dev/null
is_xml=$?
if [ $is_xml -eq 0 ]; then
ocf_log debug "$OCF_RESKEY_xmlfile is XML; using virsh"
export OCF_RESKEY_use_virsh=1
unset OCF_RESKEY_path
else
ocf_log debug "$OCF_RESKEY_xmlfile is not XML; using xm"
export OCF_RESKEY_use_virsh=0
unset OCF_RESKEY_xmlfile
fi
return 0
}
get_hypervisor()
{
local hypervisor="`virsh version | grep \"Running hypervisor:\" | awk '{print $3}' | tr A-Z a-z`"
# if virsh gives us nothing (likely because libvirt is down), we can attempt
# to determine auto detect the hypervisor is qemu if a qemu emulator is used
# for this domain.
if [ -z "$hypervisor" ]; then
get_emulator | grep "qemu" > /dev/null 2>&1
if [ $? -eq 0 ]; then
hypervisor="qemu"
fi
fi
echo $hypervisor
}
validate_all()
{
if [ "$(id -u)" != "0" ]; then
ocf_log err "Cannot control VMs. as non-root user."
return 1
fi
#
# If someone selects a hypervisor, honor it.
# Otherwise, ask virsh what the hypervisor is.
#
if [ -z "$OCF_RESKEY_hypervisor" ] ||
[ "$OCF_RESKEY_hypervisor" = "auto" ]; then
export OCF_RESKEY_hypervisor="`get_hypervisor`"
if [ -z "$OCF_RESKEY_hypervisor" ]; then
ocf_log err "Could not determine Hypervisor"
return $OCF_ERR_ARGS
fi
echo Hypervisor: $OCF_RESKEY_hypervisor
fi
#
# Xen hypervisor only for when use_virsh = 0.
#
if [ "$OCF_RESKEY_use_virsh" = "0" ]; then
if [ "$OCF_RESKEY_hypervisor" != "xen" ]; then
ocf_log err "Cannot use $OCF_RESKEY_hypervisor hypervisor without using virsh"
return $OCF_ERR_ARGS
fi
if [ -n "$OCF_RESKEY_xmlfile" ]; then
ocf_log err "Cannot use xmlfile if use_virsh is set to 0"
return $OCF_ERR_ARGS
fi
else
#
# Virsh path support.
#
if [ -n "$OCF_RESKEY_path" ] &&
[ "$OCF_RESKEY_path" != "/etc/xen" ]; then
if [ -n "$OCF_RESKEY_xmlfile" ]; then
ocf_log warning "Using $OCF_RESKEY_xmlfile instead of searching $OCF_RESKEY_path"
else
search_config_path
if [ $? -ne 0 ]; then
ocf_log warning "Could not find $OCF_RESKEY_name or $OCF_RESKEY_name.xml in search path $OCF_RESKEY_path"
unset OCF_RESKEY_xmlfile
else
ocf_log debug "Using $OCF_RESKEY_xmlfile"
fi
choose_management_tool
fi
else
export OCF_RESKEY_use_virsh=1
fi
fi
if [ "$OCF_RESKEY_use_virsh" = "0" ]; then
echo "Management tool: xm"
which xm &> /dev/null
if [ $? -ne 0 ]; then
ocf_log err "Cannot find 'xm'; is it installed?"
return $OCF_ERR_INSTALLED
fi
if [ "$OCF_RESKEY_hypervisor" != "xen" ]; then
ocf_log err "Cannot use $OCF_RESKEY_hypervisor hypervisor without using virsh"
return $OCF_ERR_ARGS
fi
else
echo "Management tool: virsh"
which virsh &> /dev/null
if [ $? -ne 0 ]; then
ocf_log err "Cannot find 'virsh'; is it installed?"
return $OCF_ERR_INSTALLED
fi
fi
#
# Set the hypervisor URI
#
if [ -z "$OCF_RESKEY_hypervisor_uri" -o "$OCF_RESKEY_hypervisor_uri" = "auto" ] &&
[ "$OCF_RESKEY_use_virsh" = "1" ]; then
# Virsh makes it easier to do this. Really.
if [ "$OCF_RESKEY_hypervisor" = "qemu" ]; then
OCF_RESKEY_hypervisor_uri="qemu:///system"
fi
# I just need to believe in it more.
if [ "$OCF_RESKEY_hypervisor" = "xen" ]; then
OCF_RESKEY_hypervisor_uri="xen:///"
fi
echo Hypervisor URI: $OCF_RESKEY_hypervisor_uri
fi
#
# Set the migration URI
#
if [ -z "$OCF_RESKEY_migration_uri" -o "$OCF_RESKEY_migration_uri" = "auto" ] &&
[ "$OCF_RESKEY_use_virsh" = "1" ]; then
# Virsh makes it easier to do this. Really.
if [ "$OCF_RESKEY_hypervisor" = "qemu" ]; then
export OCF_RESKEY_migration_uri="qemu+ssh://%s/system"
fi
# I just need to believe in it more.
if [ "$OCF_RESKEY_hypervisor" = "xen" ]; then
export OCF_RESKEY_migration_uri="xenmigr://%s/"
fi
[ -n "$OCF_RESKEY_migration_uri" ] && echo Migration URI format: $(printf $OCF_RESKEY_migration_uri target_host)
fi
if [ -z "$OCF_RESKEY_name" ]; then
echo No domain name specified
return $OCF_ERR_ARGS
fi
if [ "$OCF_RESKEY_hypervisor" = "qemu" ]; then
export migrateuriopt="tcp:%s"
fi
case "$OCF_RESKEY_no_kill" in
yes|true|1|YES|TRUE|on|ON)
OCF_RESKEY_no_kill=1
;;
esac
#virsh list --all | awk '{print $2}' | grep -q "^$OCF_RESKEY_name\$"
return $?
}
virsh_migrate()
{
declare target=$1
declare rv=1
#
# Xen and qemu have different migration mechanisms
#
if [ "$OCF_RESKEY_hypervisor" = "xen" ]; then
cmd="virsh migrate $migrate_opt $OCF_RESKEY_migrate_options $OCF_RESKEY_name $OCF_RESKEY_hypervisor_uri $(printf $OCF_RESKEY_migration_uri $target)"
ocf_log debug "$cmd"
err=$($cmd 2>&1 | head -1; exit ${PIPESTATUS[0]})
rv=$?
elif [ "$OCF_RESKEY_hypervisor" = "qemu" ]; then
if [ -z "$tunnelled_opt" ]; then
cmd="virsh migrate $tunnelled_opt $migrate_opt $OCF_RESKEY_migrate_options $OCF_RESKEY_name $(printf $OCF_RESKEY_migration_uri $target) $(printf $migrateuriopt $target)"
else
cmd="virsh migrate $tunnelled_opt $migrate_opt $OCF_RESKEY_migrate_options $OCF_RESKEY_name $(printf $OCF_RESKEY_migration_uri $target)"
fi
ocf_log debug "$cmd"
err=$($cmd 2>&1 | head -1; exit ${PIPESTATUS[0]})
rv=$?
fi
if [ $rv -ne 0 ]; then
ocf_log err "Migrate $OCF_RESKEY_name to $target failed:"
ocf_log err "$err"
if [ "$err" != "${err/does not exist/}" ]; then
return $OCF_ERR_CONFIGURED
fi
if [ "$err" != "${err/Domain not found/}" ]; then
return $OCF_ERR_CONFIGURED
fi
return $OCF_ERR_GENERIC
fi
return $rv
}
#
# XM migrate
#
xm_migrate()
{
declare target=$1
declare errstr rv migrate_opt cmd
rv=1
if [ "$OCF_RESKEY_migrate" = "live" ]; then
migrate_opt="-l"
fi
# migrate() function sets target using migration_mapping;
# no need to do it here anymore
cmd="xm migrate $migrate_opt $OCF_RESKEY_migrate_options $OCF_RESKEY_name $target"
ocf_log debug "$cmd"
err=$($cmd 2>&1 | head -1; exit ${PIPESTATUS[0]})
rv=$?
if [ $rv -ne 0 ]; then
ocf_log err "Migrate $OCF_RESKEY_name to $target failed:"
ocf_log err "$err"
if [ "$err" != "${err/does not exist/}" ]; then
return $OCF_NOT_RUNNING
fi
if [ "$err" != "${err/Connection refused/}" ]; then
return $OCF_ERR_CONFIGURED
fi
return $OCF_ERR_GENERIC
fi
return $?
}
#
# Virsh migrate
#
migrate()
{
declare target=$1
declare rv migrate_opt
declare tunnelled_opt
if [ "$OCF_RESKEY_migrate" = "live" ]; then
migrate_opt="--live"
fi
case "$OCF_RESKEY_tunnelled" in
yes|true|1|YES|TRUE|on|ON)
tunnelled_opt="--tunnelled --p2p"
;;
esac
# Patch from Marcelo Azevedo to migrate over private
# LANs instead of public LANs
if [ -n "$OCF_RESKEY_migration_mapping" ] ; then
target=${OCF_RESKEY_migration_mapping#*$target:} target=${target%%,*}
fi
if [ "$OCF_RESKEY_use_virsh" = "1" ]; then
virsh_migrate $target
rv=$?
else
xm_migrate $target
rv=$?
fi
return $rv
}
wait_start()
{
declare -i timeout_remaining=$(get_timeout)
declare -i start_time
declare -i end_time
declare -i delta
declare -i sleep_time
if [ -z "$OCF_RESKEY_status_program" ]; then
return 0
fi
while [ $timeout_remaining -gt 0 ]; do
start_time=$(date +%s)
bash -c "$OCF_RESKEY_status_program"
if [ $? -eq 0 ]; then
return 0
fi
end_time=$(date +%s)
delta=$(((end_time - start_time)))
sleep_time=$(((5 - delta)))
((timeout_remaining -= $delta))
if [ $sleep_time -gt 0 ]; then
sleep $sleep_time
((timeout_remaining -= $sleep_time))
fi
done
ocf_log err "Start of $OCF_RESOURCE_INSTANCE has failed"
ocf_log err "Timeout exceeded while waiting for \"$OCF_RESKEY_status_program\""
return 1
}
#
#
#
case $1 in
start)
validate_all || exit $OCF_ERR_ARGS
do_start
rv=$?
if [ $rv -ne 0 ]; then
exit $rv
fi
wait_start
exit $?
;;
stop)
validate_all || exit $OCF_ERR_ARGS
if [ $OCF_RESKEY_no_kill -eq 1 ]; then
do_stop shutdown
else
do_stop shutdown destroy
fi
exit $?
;;
kill)
validate_all || exit $OCF_ERR_ARGS
do_stop destroy
exit $?
;;
recover|restart)
exit 0
;;
status|monitor)
validate_all || exit $OCF_ERR_ARGS
echo -n "Virtual machine $OCF_RESKEY_name is "
do_status
rv=$?
if [ $rv -ne 0 ]; then
exit $rv
fi
[ -z "$OCF_RESKEY_status_program" ] && exit 0
[ -z "$OCF_CHECK_LEVEL" ] && exit 0
[ $OCF_CHECK_LEVEL -lt 10 ] && exit 0
bash -c "$OCF_RESKEY_status_program" &> /dev/null
exit $?
;;
migrate)
validate_all || exit $OCF_ERR_ARGS
migrate $2 # Send VM to this node
rv=$?
if [ $rv -eq $OCF_ERR_GENERIC ]; then
# Catch-all: If migration failed with
# an unhandled error, do a status check
# to see if the VM is really dead.
#
# If the VM is still in good health, return
# a value to rgmanager to indicate the
# non-critical error
#
# OCF states that codes 150-199 are reserved
# for application use, so we'll use 150
#
do_status > /dev/null
if [ $? -eq 0 ]; then
rv=150
fi
fi
exit $rv
;;
reload)
exit 0
;;
reconfig)
validate_all || exit $OCF_ERR_ARGS
echo "$0 RECONFIGURING $OCF_RESKEY_memory"
reconfigure
exit $?
;;
meta-data)
meta_data
exit 0
;;
validate-all)
validate_all
exit $?
;;
*)
echo "usage: $0 {start|stop|restart|status|reload|reconfig|meta-data|validate-all}"
exit 1
;;
esac
diff --git a/tools/findif.c b/tools/findif.c
index 86c97117b..fe3cdeae8 100644
--- a/tools/findif.c
+++ b/tools/findif.c
@@ -1,842 +1,845 @@
/*
* findif.c: Finds an interface which can route a given address
*
* It's really simple to write in C, but hard to write in the shell...
*
* This code is dependent on IPV4 addressing conventions...
* Sorry.
*
* Copyright (C) 2000 Alan Robertson <alanr@unix.sh>
* Copyright (C) 2001 Matt Soffen <matt@soffen.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*
***********************************************************
*
* All our arguments come through the environment as OCF
* environment variables as below:
*
* OCF_RESKEY_ip
* OCF_RESKEY_broadcast
* OCF_RESKEY_nic
* OCF_RESKEY_cidr_netmask
*
* If the CIDR netmask is omitted, we choose the netmask associated with
* the route we selected.
*
* If the broadcast address was omitted, we assume the highest address
* in the subnet.
*
* If the interface is omitted, we choose the interface associated with
* the route we selected.
*
*
* See http://www.doom.net/docs/netmask.html for a table explaining
* CIDR address format and their relationship to life, the universe
* and everything.
*
*/
#include <config.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_SOCKIO_H
#include <sys/sockio.h>
#endif
#include <net/if.h>
#include <sys/ioctl.h>
#include <errno.h>
#ifdef __linux__
#undef __OPTIMIZE__
/*
* This gets rid of some silly -Wtraditional warnings on Linux
* because the netinet header has some slightly funky constants
* in it.
*/
#endif /* __linux__ */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <agent_config.h>
#include <config.h>
#define DEBUG 0
#define EOS '\0'
#define PROCROUTE "/proc/net/route"
#define ROUTEPARM "-n get"
#ifndef HAVE_STRNLEN
/* Any system that don't provide strnlen() only has itself to blame */
#define strnlen(str, max) strlen(str)
#endif
/*
* "route -n get iii.jjj.kkk.lll" can, on Solaris at least,
* return the word "default" as the value from "mask" and "dest",
* typically if the host is remote, reached over a default route.
* We should probably treat such a mask as "0.0.0.0".
*
* Define "MASK_DEFAULT_TO_ZERO" to enable this interpretation.
*
* This is better for Solaris and is probably suitable (or irrelevant)
* for others OSes also. But if it breaks another OS, then reduce the
* "hash-if 1" below to exclude that OS.
* (David Lee, Jan 2006)
*/
#if 1
# define MASK_DEFAULT_TO_ZERO
#endif
static int OutputInCIDR=0;
/*
* Different OSes offer different mechnisms to obtain this information.
* Not all this can be determined at configure-time; need a run-time element.
*
* typedef ... SearchRoute ...:
* For routines that interface on these mechanisms.
* Return code:
* <0: mechanism invalid, so try next mechanism
* 0: mechanism worked: good answer
* >0: mechanism worked: bad answer
* On non-zero, errmsg may have been filled with an error message
*/
typedef int SearchRoute (char *address, struct in_addr *in
, struct in_addr *addr_out, char *best_if, size_t best_iflen
, unsigned long *best_netmask, char *errmsg
, int errmsglen);
static SearchRoute SearchUsingProcRoute;
static SearchRoute SearchUsingRouteCmd;
static SearchRoute *search_mechs[] = {
&SearchUsingProcRoute,
&SearchUsingRouteCmd,
NULL
};
void GetAddress (char **address, char **netmaskbits
, char **bcast_arg, char **if_specified);
int ConvertNetmaskBitsToInt(char *netmaskbits);
void ValidateNetmaskBits(int bits, unsigned long *netmask);
int ValidateIFName (const char *ifname, struct ifreq *ifr);
int netmask_bits (unsigned long netmask);
char * get_first_loopback_netdev(char * ifname);
int is_loopback_interface(char * ifname);
char * get_ifname(char * buf, char * ifname);
int ConvertQuadToInt(char *dest);
static const char *cmdname = "findif";
#define OCF_SUCCESS 0
#define OCF_ERR_GENERIC 1
#define OCF_ERR_ARGS 2
#define OCF_ERR_UNIMPLEMENTED 3
#define OCF_ERR_PERM 4
#define OCF_ERR_INSTALLED 5
#define OCF_ERR_CONFIGURED 6
#define OCF_NOT_RUNNING 7
void usage(int ec);
#define PATH_PROC_NET_DEV "/proc/net/dev"
#define DELIM '/'
#define BAD_BROADCAST (0L)
#define MAXSTR 128
static int
SearchUsingProcRoute (char *address, struct in_addr *in
, struct in_addr *addr_out, char *best_if, size_t best_iflen
, unsigned long *best_netmask
, char *errmsg, int errmsglen)
{
unsigned long flags, refcnt, use, gw, mask;
unsigned long dest;
long metric = LONG_MAX;
long best_metric = LONG_MAX;
int rc = OCF_SUCCESS;
char buf[2048];
char interface[MAXSTR];
FILE *routefd = NULL;
if ((routefd = fopen(PROCROUTE, "r")) == NULL) {
snprintf(errmsg, errmsglen
, "Cannot open %s for reading"
, PROCROUTE);
rc = OCF_ERR_GENERIC; goto out;
}
/* Skip first (header) line */
if (fgets(buf, sizeof(buf), routefd) == NULL) {
snprintf(errmsg, errmsglen
, "Cannot skip first line from %s"
, PROCROUTE);
rc = OCF_ERR_GENERIC; goto out;
}
*best_netmask = 0;
while (fgets(buf, sizeof(buf), routefd) != NULL) {
if (sscanf(buf, "%[^\t]\t%lx%lx%lx%lx%lx%lx%lx"
, interface, &dest, &gw, &flags, &refcnt, &use
, &metric, &mask)
!= 8) {
snprintf(errmsg, errmsglen, "Bad line in %s: %s"
, PROCROUTE, buf);
rc = OCF_ERR_GENERIC; goto out;
}
if ( (in->s_addr&mask) == (in_addr_t)(dest&mask)
&& metric <= best_metric && mask >= *best_netmask) {
best_metric = metric;
*best_netmask = mask;
strncpy(best_if, interface, best_iflen);
}
}
if (best_metric == LONG_MAX) {
snprintf(errmsg, errmsglen, "No route to %s\n", address);
rc = OCF_ERR_GENERIC;
}
out:
if (routefd) {
fclose(routefd);
}
return(rc);
}
static int
SearchUsingRouteCmd (char *address, struct in_addr *in
, struct in_addr *addr_out, char *best_if, size_t best_iflen
, unsigned long *best_netmask
, char *errmsg, int errmsglen)
{
char mask[20];
char routecmd[MAXSTR];
int best_metric = INT_MAX;
char buf[2048];
char interface[MAXSTR];
char *cp, *sp;
int done = 0;
FILE *routefd = NULL;
uint32_t maskbits;
/* Open route and get the information */
snprintf (routecmd, sizeof(routecmd), "%s %s %s"
, ROUTE, ROUTEPARM, address);
routefd = popen (routecmd, "r");
if (routefd == NULL)
return (OCF_ERR_GENERIC);
mask[0] = EOS;
interface[0] = EOS;
while ((done < 3) && fgets(buf, sizeof(buf), routefd)) {
int buflen = strnlen(buf, sizeof(buf));
/*cp = buf;*/
sp = buf + buflen;
while (sp!=buf && isspace((int)*(sp-1))) {
--sp;
}
*sp = EOS;
if (strstr (buf, "mask:")) {
/*strsep(&cp, ":");cp++;*/
strtok(buf, ":");
cp = strtok(NULL, ":");
if (cp) {
cp++;
- strncpy(mask, cp, sizeof(mask));
+ strncpy(mask, cp, sizeof(mask) - 1);
+ *(mask + sizeof(mask) - 1) = '\0';
done++;
}
}
if (strstr (buf, "interface:")) {
/*strsep(&cp, ":");cp++;*/
strtok(buf, ":");
cp = strtok(NULL, ":");
if (cp) {
cp++;
- strncpy(interface, cp, sizeof(interface));
+ strncpy(interface, cp, sizeof(interface) - 1);
+ *(interface + sizeof(interface) - 1) = '\0';
done++;
}
}
}
fclose(routefd);
/*
* Check to see if mask isn't available. It may not be
* returned if multiple IP's are defined.
* use 255.255.255.255 for mask then
*/
/* I'm pretty sure this is the wrong behavior...
* I think the right behavior is to declare an error and give up.
* The admin didn't define his routes correctly. Fix them.
* It's useless to take over an IP address with no way to
* return packets to the originator. Without the right subnet
* mask, you can't reply to any packets you receive.
*/
if (strnlen(mask, sizeof(mask)) == 0) {
strncpy (mask, "255.255.255.255", sizeof(mask));
}
/*
* Solaris (at least) can return the word "default" for mask and dest.
* For the moment, let's interpret this as:
* mask: 0.0.0.0
* This was manifesting itself under "BasicSanityCheck", which tries
* to use a remote IP number; these typically use the "default" route.
* Better schemes are warmly invited...
*/
#ifdef MASK_DEFAULT_TO_ZERO
if (strncmp(mask, "default", sizeof("default")) == 0) {
strncpy (mask, "0.0.0.0", sizeof(mask));
}
#endif
if (inet_pton(AF_INET, mask, &maskbits) <= 0) {
snprintf(errmsg, errmsglen,
"mask [%s] not valid.", mask);
return(OCF_ERR_CONFIGURED);
}
if (inet_pton(AF_INET, address, addr_out) <= 0) {
snprintf(errmsg, errmsglen
, "IP address [%s] not valid.", address);
return(OCF_ERR_CONFIGURED);
}
if ((in->s_addr & maskbits) == (addr_out->s_addr & maskbits)) {
if (interface[0] == EOS) {
snprintf(errmsg, errmsglen, "No interface found.");
return(OCF_ERR_GENERIC);
}
best_metric = 0;
*best_netmask = maskbits;
strncpy(best_if, interface, best_iflen);
}
if (best_metric == INT_MAX) {
snprintf(errmsg, errmsglen, "No route to %s\n", address);
return(OCF_ERR_GENERIC);
}
return (OCF_SUCCESS);
}
/*
* Getaddress gets all its real parameters from the OCF environment
* variables that its callers already use.
*/
void
GetAddress (char **address, char **netmaskbits
, char **bcast_arg, char **if_specified)
{
/*
* Here are out input environment variables:
*
* OCF_RESKEY_ip ip address
* OCF_RESKEY_cidr_netmask netmask of interface
* OCF_RESKEY_broadcast broadcast address for interface
* OCF_RESKEY_nic interface to assign to
*
*/
*address = getenv("OCF_RESKEY_ip");
*netmaskbits = getenv("OCF_RESKEY_cidr_netmask");
if (*netmaskbits == NULL || **netmaskbits == EOS) {
*netmaskbits = getenv("OCF_RESKEY_netmask");
}
*bcast_arg = getenv("OCF_RESKEY_broadcast");
*if_specified = getenv("OCF_RESKEY_nic");
}
int
ConvertNetmaskBitsToInt(char *netmaskbits)
{
size_t nmblen = strnlen(netmaskbits, 3);
/* Maximum netmask is 32 */
if (nmblen > 2 || nmblen == 0
|| (strspn(netmaskbits, "0123456789") != nmblen))
return -1;
else
return atoi(netmaskbits);
}
void
ValidateNetmaskBits(int bits, unsigned long *netmask)
{
/* Maximum netmask is 32 */
if (bits < 1 || bits > 32) {
fprintf(stderr
, "Invalid netmask specification [%d]"
, bits);
usage(OCF_ERR_CONFIGURED);
/*not reached */
}
bits = 32 - bits;
*netmask = (1L<<(bits))-1L;
*netmask = ((~(*netmask))&0xffffffffUL);
*netmask = htonl(*netmask);
}
int
ValidateIFName(const char *ifname, struct ifreq *ifr)
{
int skfd = -1;
char *colonptr;
if ( (skfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ) {
fprintf(stderr, "%s\n", strerror(errno));
return -2;
}
- strncpy(ifr->ifr_name, ifname, IFNAMSIZ);
+ strncpy(ifr->ifr_name, ifname, IFNAMSIZ - 1);
+ *(ifr->ifr_name + sizeof(ifr->ifr_name) - 1) = '\0';
/* Contain a ":"? Probably an error, but treat as warning at present */
if ((colonptr = strchr(ifname, ':')) != NULL) {
fprintf(stderr, "%s: warning: name may be invalid\n",
ifr->ifr_name);
}
if (ioctl(skfd, SIOCGIFFLAGS, ifr) < 0) {
fprintf(stderr, "%s: unknown interface: %s\n"
, ifr->ifr_name, strerror(errno));
close(skfd);
/* return -1 only if ifname is known to be invalid */
return -1;
}
close(skfd);
return 0;
}
int
netmask_bits(unsigned long netmask)
{
int j;
netmask = netmask & 0xFFFFFFFFUL;
for (j=0; j <= 32; ++j) {
if ((netmask >> j)&0x1) {
break;
}
}
return 32 - j;
}
char *
get_first_loopback_netdev(char * output)
{
char buf[512];
FILE * fd = NULL;
char *rc = NULL;
if (!output) {
fprintf(stderr, "output buf is a null pointer.\n");
goto out;
}
fd = fopen(PATH_PROC_NET_DEV, "r");
if (!fd) {
fprintf(stderr, "Warning: cannot open %s (%s).\n",
PATH_PROC_NET_DEV, strerror(errno));
goto out;
}
/* Skip the first two lines */
if (!fgets(buf, sizeof(buf), fd) || !fgets(buf, sizeof(buf), fd)) {
fprintf(stderr, "Warning: cannot read header from %s.\n",
PATH_PROC_NET_DEV);
goto out;
}
while (fgets(buf, sizeof(buf), fd)) {
char name[IFNAMSIZ];
if (NULL == get_ifname(buf, name)) {
/* Maybe somethin is wrong, anyway continue */
continue;
}
if (is_loopback_interface(name)) {
strncpy(output, name, IFNAMSIZ);
rc = output;
goto out;
}
}
out:
if (fd) {
fclose(fd);
}
return rc;
}
int
is_loopback_interface(char * ifname)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
if (ValidateIFName(ifname, &ifr) < 0)
return 0;
if (ifr.ifr_flags & IFF_LOOPBACK) {
/* this is a loopback device. */
return 1;
} else {
return 0;
}
}
char *
get_ifname(char * buf, char * ifname)
{
char * start, * end, * buf_border;
buf_border = buf + strnlen(buf, 512);
start = buf;
while (isspace((int) *start) && (start != buf_border)) {
start++;
}
end = start;
while ((*end != ':') && (end != buf_border)) {
end++;
}
if ( start == buf_border || end == buf_border ) {
/* Over the border of buf */
return NULL;
}
*end = '\0';
strncpy(ifname, start, IFNAMSIZ);
return ifname;
}
int ConvertQuadToInt(char *dest)
{
struct in_addr ad;
if (inet_pton(AF_INET, dest, &ad) <= 0)
return -1;
return netmask_bits(ntohl(ad.s_addr));
}
int
main(int argc, char ** argv) {
char * address = NULL;
char * bcast_arg = NULL;
char * netmaskbits = NULL;
struct in_addr in;
struct in_addr addr_out;
unsigned long netmask = 0;
char best_if[MAXSTR];
char * if_specified = NULL;
struct ifreq ifr;
unsigned long best_netmask = UINT_MAX;
int argerrs = 0;
int nmbits;
cmdname=argv[0];
memset(&addr_out, 0, sizeof(addr_out));
memset(&in, 0, sizeof(in));
memset(&ifr, 0, sizeof(ifr));
switch (argc) {
case 1: /* No -C argument */
break;
case 2: /* Hopefully a -C argument */
if (strncmp(argv[1], "-C", sizeof("-C")) != 0) {
argerrs=1;
}
OutputInCIDR=1;
break;
default:
argerrs=1;
break;
}
if (argerrs) {
usage(OCF_ERR_ARGS);
/* not reached */
return(1);
}
GetAddress (&address, &netmaskbits, &bcast_arg
, &if_specified);
if (address == NULL || *address == EOS) {
fprintf(stderr, "ERROR: IP address parameter is mandatory.");
usage(OCF_ERR_CONFIGURED);
/* not reached */
}
/* Is the IP address we're supposed to find valid? */
if (inet_pton(AF_INET, address, (void *)&in) <= 0) {
fprintf(stderr, "IP address [%s] not valid.", address);
usage(OCF_ERR_CONFIGURED);
/* not reached */
}
if (netmaskbits != NULL && *netmaskbits != EOS) {
if (strchr(netmaskbits, '.') != NULL) {
nmbits = ConvertQuadToInt(netmaskbits);
fprintf(stderr, "Converted dotted-quad netmask to CIDR as: %d\n", nmbits);
}else{
nmbits = ConvertNetmaskBitsToInt(netmaskbits);
}
if (nmbits < 0) {
fprintf(stderr, "Invalid netmask specification"
" [%s]", netmaskbits);
usage(OCF_ERR_CONFIGURED);
/*not reached */
}
/* Validate the netmaskbits field */
ValidateNetmaskBits (nmbits, &netmask);
}
if (if_specified != NULL && *if_specified != EOS) {
if(ValidateIFName(if_specified, &ifr) < 0) {
usage(OCF_ERR_CONFIGURED);
/* not reached */
}
- strncpy(best_if, if_specified, sizeof(best_if));
+ strncpy(best_if, if_specified, sizeof(best_if) - 1);
*(best_if + sizeof(best_if) - 1) = '\0';
}else{
SearchRoute **sr = search_mechs;
char errmsg[MAXSTR] = "No valid mechanisms";
int rc = OCF_ERR_GENERIC;
strcpy(best_if, "UNKNOWN");
while (*sr) {
errmsg[0] = '\0';
rc = (*sr) (address, &in, &addr_out, best_if
, sizeof(best_if)
, &best_netmask, errmsg, sizeof(errmsg));
if (!rc) { /* Mechanism worked */
break;
}
sr++;
}
if (rc != 0) { /* No route, or all mechanisms failed */
if (*errmsg) {
fprintf(stderr, "%s", errmsg);
}
return(rc);
}
}
if (netmaskbits) {
best_netmask = netmask;
}else if (best_netmask == 0L) {
/*
On some distributions, there is no loopback related route
item, this leads to the error here.
My fix may be not good enough, please FIXME
*/
if (0 == strncmp(address, "127", 3)) {
if (NULL != get_first_loopback_netdev(best_if)) {
best_netmask = 0x000000ff;
} else {
fprintf(stderr, "No loopback interface found.\n");
return(OCF_ERR_GENERIC);
}
} else {
fprintf(stderr
, "ERROR: Cannot use default route w/o netmask [%s]\n"
, address);
return(OCF_ERR_GENERIC);
}
}
/* Did they tell us the broadcast address? */
if (bcast_arg && *bcast_arg != EOS) {
/* Yes, they gave us a broadcast address.
* It at least should be a valid IP address
*/
struct in_addr bcast_addr;
if (inet_pton(AF_INET, bcast_arg, (void *)&bcast_addr) <= 0) {
fprintf(stderr, "Invalid broadcast address [%s].", bcast_arg);
usage(OCF_ERR_CONFIGURED);
/* not reached */
}
best_netmask = htonl(best_netmask);
if (!OutputInCIDR) {
printf("%s\tnetmask %d.%d.%d.%d\tbroadcast %s\n"
, best_if
, (int)((best_netmask>>24) & 0xff)
, (int)((best_netmask>>16) & 0xff)
, (int)((best_netmask>>8) & 0xff)
, (int)(best_netmask & 0xff)
, bcast_arg);
}else{
printf("%s\tnetmask %d\tbroadcast %s\n"
, best_if
, netmask_bits(best_netmask)
, bcast_arg);
}
}else{
/* No, we use a common broadcast address convention */
unsigned long def_bcast;
/* Common broadcast address */
def_bcast = (in.s_addr | (~best_netmask));
#if DEBUG
fprintf(stderr, "best_netmask = %08lx, def_bcast = %08lx\n"
, best_netmask, def_bcast);
#endif
/* Make things a bit more machine-independent */
best_netmask = htonl(best_netmask);
def_bcast = htonl(def_bcast);
if (!OutputInCIDR) {
printf("%s\tnetmask %d.%d.%d.%d\tbroadcast %d.%d.%d.%d\n"
, best_if
, (int)((best_netmask>>24) & 0xff)
, (int)((best_netmask>>16) & 0xff)
, (int)((best_netmask>>8) & 0xff)
, (int)(best_netmask & 0xff)
, (int)((def_bcast>>24) & 0xff)
, (int)((def_bcast>>16) & 0xff)
, (int)((def_bcast>>8) & 0xff)
, (int)(def_bcast & 0xff));
}else{
printf("%s\tnetmask %d\tbroadcast %d.%d.%d.%d\n"
, best_if
, netmask_bits(best_netmask)
, (int)((def_bcast>>24) & 0xff)
, (int)((def_bcast>>16) & 0xff)
, (int)((def_bcast>>8) & 0xff)
, (int)(def_bcast & 0xff));
}
}
return(0);
}
void
usage(int ec)
{
fprintf(stderr, "\n"
"%s version 2.99.1 Copyright Alan Robertson\n"
"\n"
"Usage: %s [-C]\n"
"Options:\n"
" -C: Output netmask as the number of bits rather "
"than as 4 octets.\n"
"Environment variables:\n"
"OCF_RESKEY_ip ip address (mandatory!)\n"
"OCF_RESKEY_cidr_netmask netmask of interface\n"
"OCF_RESKEY_broadcast broadcast address for interface\n"
"OCF_RESKEY_nic interface to assign to\n"
, cmdname, cmdname);
exit(ec);
}
/*
Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
eth0 33D60987 00000000 0005 0 0 0 FFFFFFFF 0 0 0
eth0 00D60987 00000000 0001 0 0 0 00FFFFFF 0 0 0
lo 0000007F 00000000 0001 0 0 0 000000FF 0 0 0
eth0 00000000 FED60987 0003 0 0 0 00000000 0 0 0
netstat -rn outpug from RedHat Linux 6.0
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
192.168.85.2 0.0.0.0 255.255.255.255 UH 0 0 0 eth1
10.0.0.2 0.0.0.0 255.255.255.255 UH 0 0 0 eth2
208.132.134.61 0.0.0.0 255.255.255.255 UH 0 0 0 eth0
208.132.134.32 0.0.0.0 255.255.255.224 U 0 0 0 eth0
192.168.85.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
10.0.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth2
127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo
0.0.0.0 208.132.134.33 0.0.0.0 UG 0 0 0 eth0
|--------------------------------------------------------------------------------
netstat -rn output from FreeBSD 3.3
Routing tables
Internet:
Destination Gateway Flags Refs Use Netif Expire
default 209.61.94.161 UGSc 3 8 pn0
192.168 link#1 UC 0 0 xl0
192.168.0.2 0:60:8:a4:91:fd UHLW 0 38 lo0
192.168.0.255 ff:ff:ff:ff:ff:ff UHLWb 1 7877 xl0
209.61.94.160/29 link#2 UC 0 0 pn0
209.61.94.161 0:a0:cc:26:c2:ea UHLW 6 17265 pn0 1105
209.61.94.162 0:a0:cc:27:1c:fb UHLW 1 568 pn0 1098
209.61.94.163 0:a0:cc:29:1f:86 UHLW 0 4749 pn0 1095
209.61.94.166 0:a0:cc:27:2d:e1 UHLW 0 12 lo0
209.61.94.167 ff:ff:ff:ff:ff:ff UHLWb 0 10578 pn0
|--------------------------------------------------------------------------------
netstat -rn output from FreeBSD 4.2
Routing tables
Internet:
Destination Gateway Flags Refs Use Netif Expire
default 64.65.195.1 UGSc 1 11 dc0
64.65.195/24 link#1 UC 0 0 dc0 =>
64.65.195.1 0:3:42:3b:0:dd UHLW 2 0 dc0 1131
64.65.195.184 0:a0:cc:29:1f:86 UHLW 2 18098 dc0 1119
64.65.195.194 0:a0:cc:27:2d:e1 UHLW 3 335161 dc0 943
64.65.195.200 52:54:0:db:33:b3 UHLW 0 13 dc0 406
64.65.195.255 ff:ff:ff:ff:ff:ff UHLWb 1 584 dc0
127.0.0.1 127.0.0.1 UH 0 0 lo0
192.168/16 link#2 UC 0 0 vx0 =>
192.168.0.1 0:20:af:e2:f0:36 UHLW 0 2 lo0
192.168.255.255 ff:ff:ff:ff:ff:ff UHLWb 0 1 vx0
Internet6:
Destination Gateway Flags Netif Expire
::1 ::1 UH lo0
fe80::%dc0/64 link#1 UC dc0
fe80::%vx0/64 link#2 UC vx0
fe80::%lo0/64 fe80::1%lo0 Uc lo0
ff01::/32 ::1 U lo0
ff02::%dc0/32 link#1 UC dc0
ff02::%vx0/32 link#2 UC vx0
ff02::%lo0/32 fe80::1%lo0 UC lo0
*/
diff --git a/tools/ocft/caselib.in b/tools/ocft/caselib.in
index 2c5735aff..1857e6381 100644
--- a/tools/ocft/caselib.in
+++ b/tools/ocft/caselib.in
@@ -1,299 +1,299 @@
#
# Copyright (c) 2010-2011 Novell Inc, John Shi
# 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.
quit()
{
local ret
ret="$1"
while [ $__OCFT__atexit_num -gt 0 ]; do
atexit$__OCFT__atexit_num
let __OCFT__atexit_num--
done
rm -rf $__OCFT__fakebin
exit $ret
}
agent_install()
{
local pkg
if [ $# -eq 0 ]; then
return 0
fi
for pkg in "$@"; do
if [ -e /etc/SuSE-release ]; then
if ! zypper -q install -y "$pkg" >/dev/null 2>&1; then
echo
echo "${__OCFT__showhost}ERROR: Install '$pkg' failed."
quit 2
fi
elif [ -e /etc/debian_version ]; then
if ! apt-get -y install "$pkg" >/dev/null 2>&1; then
echo
echo "${__OCFT__showhost}ERROR: Install '$pkg' failed."
quit 2
fi
elif [ -e /etc/redhat-release ]; then
if ! yum -y install "$pkg" >/dev/null 2>&1; then
echo
echo "${__OCFT__showhost}ERROR: Install '$pkg' failed."
quit 2
fi
else
echo "${__OCFT__showhost}ERROR: Cannot detect your OS type."
quit 2
fi
done
}
set_ocf_env()
{
export OCF_RA_VERSION_MAJOR=1
export OCF_RA_VERSION_MINOR=0
export OCF_RESOURCE_TYPE=$1
export OCF_RESOURCE_INSTANCE=${OCF_RESOURCE_INSTANCE:-"ocft"}
}
agent_run()
{
local agent cmd timeout pid i ret aroot
agent="$1"
cmd="$2"
timeout="$3"
set_ocf_env $agent
export OCF_RESKEY_CRM_meta_timeout
: ${OCF_RESKEY_CRM_meta_timeout:=$timeout}
aroot=${__OCFT__MYROOT:-$__OCFT__AGENT_ROOT}
setsid $aroot/$agent $cmd >/tmp/.ocft_runlog 2>&1 &
pid=$!
i=0
while [ $i -lt $timeout ]; do
if [ ! -e /proc/$pid ]; then
break
fi
sleep 1
let i++
done
if [ $i -ge $timeout ]; then
kill -SIGTERM -$pid >/dev/null 2>&1
sleep 3
kill -SIGKILL -$pid >/dev/null 2>&1
echo -n "${__OCFT__showhost}ERROR: The agent was hanging, killed it, "
echo "maybe you damaged the agent or system's environment, see details below:"
cat /tmp/.ocft_runlog
echo
quit 1
fi
wait $pid
}
check_success()
{
local ret msg
ret="$1"
msg="$2"
if [ $ret -ne 0 ]; then
echo "${__OCFT__showhost}ERROR: '${msg}' failed, the return code is ${ret}."
quit 1
fi
}
__maxfd()
{
(echo 0; ls -1 /proc/$$/fd) | sort -rn | head -1
}
__getfd()
{
local host rw fd file
host="$1"
rw="$2"
for fd in /proc/$$/fd/*; do
file=$(basename "$(readlink $fd)")
if [ "$file" = "${host}_$rw" ]; then
basename $fd
break
fi
done
}
backbash_start()
{
local host fd rfd wfd
host="$1"
if [ ! -d "$__OCFT__CASES_DIR" ]; then
echo "${__OCFT__showhost}ERROR: Could not found Directory: ${__OCFT__CASES_DIR}."
quit 1
fi
if lsof $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w >/dev/null 2>&1; then
echo "${__OCFT__showhost}ERROR: Connection exist with $host."
quit 1
fi
if [ ! -p "$__OCFT__CASES_DIR/${host}_r" ] || [ ! -p "$__OCFT__CASES_DIR/${host}_w" ]; then
rm -f $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w
if ! mkfifo $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w >/dev/null 2>&1; then
echo "${__OCFT__showhost}ERROR: Could not create pipe file: $__OCFT__CASES_DIR/${host}_*."
quit 1
fi
fi
- ssh root@$host '/bin/bash 2>&1
+ ssh root@$host '@BASH_SHELL@ 2>&1
sed "s/00/001/g" /tmp/.backbash-log
echo 000
echo 1' >$__OCFT__CASES_DIR/${host}_r <$__OCFT__CASES_DIR/${host}_w &
fd=$(__maxfd)
rfd=$(expr $fd + 1)
wfd=$(expr $fd + 2)
eval "exec ${rfd}<$__OCFT__CASES_DIR/${host}_r ${wfd}>$__OCFT__CASES_DIR/${host}_w"
}
backbash()
{
local host rfd wfd ret
host="$1"
rfd=$(__getfd $host r)
wfd=$(__getfd $host w)
if [ -z "$rfd" -o -z "$wfd" ]; then
echo "${__OCFT__showhost}ERROR: Could not found connection with $host."
fi
cat >&$wfd <<EOF
{
true
EOF
cat >&$wfd
cat >&$wfd <<EOF
} >&/tmp/.backbash-log
sed 's/00/001/g' /tmp/.backbash-log
echo 000
echo 0
EOF
if [ $? -ne 0 ]; then
echo "${__OCFT__showhost}ERROR: Broken connection with $host."
quit 1
fi
awk -vlive=2 '{
if (sub(/000$/, "")) {
if ($0 != "") {
gsub("001", "00");
printf("%s", $0);
}
getline live;
exit;
}
gsub("001", "00");
print;
} END {
exit(live);
}' <&$rfd
case $? in
1)
quit 1
;;
2)
echo "${__OCFT__showhost}ERROR: Broken connection with $host."
quit 1
;;
esac
}
backbash_stop()
{
local host rfd wfd
host="$1"
wfd=$(__getfd $host w)
if [ -n "$wfd" ]; then
cat >&$wfd <<<'quit 0'
fi
rm -f $__OCFT__CASES_DIR/${host}_r $__OCFT__CASES_DIR/${host}_w
}
export OCF_ROOT=@OCF_ROOT_DIR@
export OCF_LIB=@OCF_LIB_DIR@/heartbeat
__OCFT__AGENT_ROOT=@OCF_RA_DIR@/heartbeat
__OCFT__CASES_DIR=/var/lib/@PACKAGE_NAME@/ocft/cases
OCFT_DIR=@datadir@/@PACKAGE_NAME@/ocft
. $OCFT_DIR/helpers.sh
__OCFT__atexit_num=0
if [ $EUID -ne 0 ]; then
echo "${__OCFT__showhost}ERROR: '$0' needs to be run by root."
quit 3
fi
__OCFT__fakebin=./fakebin
mkdir -p $__OCFT__fakebin >/dev/null 2>&1 &&
ln -sf /bin/true $__OCFT__fakebin/crm_master >/dev/null 2>&1 &&
ln -sf /bin/true $__OCFT__fakebin/crm_mon >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "${__OCFT__showhost}ERROR: initialize 'fakebin' failed."
quit 3
fi
export HA_SBIN_DIR=$__OCFT__fakebin
. $OCF_LIB/ocf-returncodes || {
echo "${__OCFT__showhost}ERROR: $OCF_LIB/ocf-returncodes not found."
quit 3
}
. $OCF_LIB/ocf-directories || {
echo "${__OCFT__showhost}ERROR: $OCF_LIB/ocf-directories not found."
quit 3
}
while read __OCFT__line; do
if [ -n "$__OCFT__line" ]; then
__OCFT__retn=${__OCFT__line%%=*}
__OCFT__reti=$(eval echo \$$__OCFT__retn)
__OCFT__retval[__OCFT__reti]=$__OCFT__retn
fi
done <<<"$(sed 's/#.*//' $OCF_LIB/ocf-returncodes)"
# vim:ts=2:sw=2:et:
diff --git a/tools/ocft/ocft.in b/tools/ocft/ocft.in
index 3f7dfcf48..0d7f64570 100644
--- a/tools/ocft/ocft.in
+++ b/tools/ocft/ocft.in
@@ -1,893 +1,893 @@
-#!/bin/bash
+#!@BASH_SHELL@
# Copyright (c) 2010-2013 Novell Inc, John Shi
# 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.
die()
{
local str
str="$1"
echo "ERROR: $str" >&2
exit 1
}
warn()
{
local str
str="$1"
echo "WARNING: $str" >&2
}
parse_die()
{
local str
str="$1"
agent_parse_finish
die "${agent}: line ${line_num}: ${str}"
}
# add quotes to string for Here Documents
add_quotes()
{
local typ str a b
typ="$1"
str="$2"
case "$typ" in
1) a=\'; b=\";;
2) a=\"; b=\';;
esac
echo "$str" | sed "s/$a/$a$b$a$b$a/g; 1 s/^/$a/; $ s/$/$a/"
}
# split strings
explode()
{
local str
str="$1"
echo "$str" | awk -F'"' '{
if (NF > 0 && NF%2 == 0)
exit(1);
for (i=1; i<=NF; i++) {
if (i%2 == 0)
print $i;
else {
len = split($i, str, /[ \t]+/);
for (j=1; j<=len; j++) {
sb = sub(/#.*/, "", str[j]);
if (str[j] != "")
print str[j];
if (sb)
exit(0);
}
}
}
}'
}
# phase 1: parse the string to 'command' and 'argument collection'.
line2trunk()
{
trunk[0]="${line%%[[:blank:]]*}"
trunk[1]="${line#*[[:blank:]]}"
}
# phase 2: split the argument collection.
trunk2branch()
{
local IFS
# Some of statements need one parameter at least.
if [ "$line" = "${trunk[0]}" ]; then
parse_die "missing parameter."
fi
IFS=$'\n'
branch=($(explode "${trunk[1]}"))
if [ $? -ne 0 ]; then
parse_die "missing '\"'."
fi
}
preparse_cfg()
{
local agent line trunk branch macro num host
agent="$1"
if [ ! -r "$opt_cfgsdir/$agent" ]; then
die "${agent}: configuration file not found."
fi
line_num=0
while read -r line; do
let line_num++
num=" $line_num"
case "$line" in
""|\#*) continue;;
esac
line2trunk
case "${trunk[0]}" in
CASE-BLOCK)
trunk2branch
macro="$CASES_DIR/${agent}_macro.${branch[0]}"
continue
;;
Include|Include@*)
host=$(echo "${trunk[0]}" | awk -F@ '{print $2}')
trunk2branch
if [ ! -r "$CASES_DIR/${agent}_macro.${branch[0]}" ]; then
parse_die "Macro '${branch[0]}' not found."
fi
if [ -n "$host" ]; then
line="$(sed -e 's/^\([^[:blank:]]*\)@[^[:blank:]]*/\1/' -e "s/^[^[:blank:]]*/&@$host/" "$CASES_DIR/${agent}_macro.${branch[0]}")"
else
line="$(<"$CASES_DIR/${agent}_macro.${branch[0]}")"
fi
num=
;;
*[!A-Z-]*)
:
;;
*)
macro=
;;
esac
if [ -n "$macro" ]; then
echo "$line$num" >>"$macro"
else
echo "$line$num" >>"$CASES_DIR/${agent}_preparse"
fi
done <"$opt_cfgsdir/$agent"
}
case_parse_finish()
{
local host
if [ -n "$sh" ]; then
cat >>$sh <<EOF
if [ -n "\$__OCFT__VERBOSE" ]; then
echo
fi
# Cleanup and exit
EOF
for host in $hosts; do
echo "backbash_stop $host" >>$sh
done
echo "quit 0" >>$sh
fi
atexit_num=0
hosts=
sh=
}
init_cfg_vars()
{
cfg_agent=
cfg_agent_root=
cfg_install_package=()
cfg_hang_timeout=20
}
agent_parse_finish()
{
local suf
for suf in preparse setup cleanup var hosts; do
rm -f $CASES_DIR/${agent}_$suf
done
rm -f $CASES_DIR/${agent}_macro.*
init_cfg_vars
}
need_make()
{
local src_time obj_time
if [ ! -f "$CASES_DIR/0_${agent}.sh" ]; then
return 0
fi
src_time=$(stat -c '%Y' "$opt_cfgsdir/$agent")
obj_time=$(stat -c '%Y' "$CASES_DIR/0_${agent}.sh")
test $src_time -ge $obj_time
}
parse_cfg()
{
local agents i line stat sh trunk branch atexit_num host hosts
if [ $# -eq 0 ]; then
agents=($opt_cfgsdir/*)
else
agents=("$@")
fi
for agent in "${agents[@]}"; do
agent="$(basename "$agent")"
if ! need_make; then
continue
fi
agent_obj_clean $agent
agent_parse_finish
i=0
echo "Making '$agent': "
preparse_cfg "$agent"
while read -r line; do
line_num="${line##* }"
line="${line% *}"
line2trunk
# state switch
case "${trunk[0]}" in
CONFIG)
case_parse_finish
stat=1
continue
;;
VARIABLE)
case_parse_finish
stat=2
continue
;;
SETUP-AGENT)
case_parse_finish
stat=3
continue
;;
CLEANUP-AGENT)
case_parse_finish
stat=4
continue
;;
CASE)
case_parse_finish
trunk2branch
echo " - case ${i}: ${branch[0]}"
sh="$CASES_DIR/${i}_${agent}.sh"
cat >$sh <<EOF
-#!/bin/bash
+#!@BASH_SHELL@
# Agent: $cfg_agent
# Summary: ${branch[0]}
. $OCFT_DIR/caselib || {
echo "ERROR: '$OCFT_DIR/caselib' not found."
exit 2
}
$(test -r $CASES_DIR/${agent}_var && cat $CASES_DIR/${agent}_var)
__OCFT__MYROOT="$cfg_agent_root"
$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
if [ -n "\$__OCFT__VERBOSE" ]; then
echo -e $(add_quotes 1 "Starting '\\033[33m${agent}\\033[0m' case $i '\\033[33m${branch[0]}\\033[0m':")
else
echo -n "${agent}: ${branch[0]} - "
fi
EOF
chmod a+x $sh
let i++
stat=5
continue
;;
esac
case "$stat" in
1)
case "${trunk[0]}" in
Agent)
trunk2branch
cfg_agent="${branch[0]}"
;;
AgentRoot)
trunk2branch
cfg_agent_root="${branch[0]}"
;;
InstallPackage)
trunk2branch
cfg_install_package=(${cfg_install_package[@]} ${branch[@]})
;;
HangTimeout)
trunk2branch
if ! echo "${branch[0]}" | grep -qxE '[0-9]+'; then
parse_die "numeric argument required."
fi
cfg_hang_timeout="${branch[0]}"
;;
*)
parse_die "unimplemented statement: ${trunk[0]}"
;;
esac
;;
2)
if echo "$line" | grep -q '^__OCFT__'; then
parse_die "reserved key word '__OCFT__'."
fi
echo "declare $line" >>$CASES_DIR/${agent}_var
;;
3)
echo "$line" >>$CASES_DIR/${agent}_setup
;;
4)
echo "$line" >>$CASES_DIR/${agent}_cleanup
;;
5)
host=$(echo ${trunk[0]} | awk -F@ '{print $2}')
if [ -n "$host" ]; then
if ! echo "$hosts" | grep -q "$host"; then
echo "$host" >>$CASES_DIR/${agent}_hosts
hosts=$hosts$'\n'$host
cat >>$sh <<EOF
# Initialize remote shell
backbash_start $host
backbash $host <<CMD
__OCFT__VERBOSE=\$__OCFT__VERBOSE
CMD
backbash $host <$OCFT_DIR/caselib
backbash $host <<'CMD'
$(test -r $CASES_DIR/${agent}_var && cat $CASES_DIR/${agent}_var)
__OCFT__MYROOT="$cfg_agent_root"
__OCFT__showhost="${host}: "
$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
CMD
EOF
fi
fi
echo "
# CASE statement: $line" >>$sh
if [ -n "$host" ]; then
echo "backbash $host <<'CMD'" >>$sh
fi
case "${trunk[0]}" in
Env|Env@*)
cat >>$sh <<EOF
if [ -n "\$__OCFT__VERBOSE" ]; then
echo $(add_quotes 2 " \${__OCFT__showhost}Setting agent environment: export ${trunk[1]}")
fi
export ${trunk[1]}
check_success \$? $(add_quotes 1 "export ${trunk[1]}")
EOF
;;
Unenv|Unenv@*)
cat >>$sh <<EOF
if [ -n "\$__OCFT__VERBOSE" ]; then
echo $(add_quotes 2 " \${__OCFT__showhost}Removing agent environment: unset ${trunk[1]}")
fi
unset ${trunk[1]}
check_success \$? $(add_quotes 1 "unset ${trunk[1]}")
EOF
;;
AgentRun|AgentRun@*)
trunk2branch
if [ -z "${branch[1]}" ]; then
if [ "${branch[0]}" = "start" ]; then
cat >>$sh <<EOF
agent_run $(add_quotes 1 "$cfg_agent") monitor $cfg_hang_timeout
__OCFT__rc=\$?
if [ \$__OCFT__rc -eq \$OCF_SUCCESS -o \$__OCFT__rc -eq \$OCF_RUNNING_MASTER ]; then
: #The status I want, so I can do nothing.
elif [ \$__OCFT__rc -eq \$OCF_NOT_RUNNING ]; then
if [ -n "\$__OCFT__VERBOSE" ]; then
echo $(add_quotes 2 " \${__OCFT__showhost}Running agent: ./$cfg_agent ${branch[0]}")
fi
agent_run $(add_quotes 1 "$cfg_agent") start $cfg_hang_timeout
check_success \$? $(add_quotes 1 "./$cfg_agent ${branch[0]}")
else
check_success \$__OCFT__rc $(add_quotes 1 "./$cfg_agent monitor")
fi
EOF
elif [ "${branch[0]}" = "stop" ]; then
cat >>$sh <<EOF
agent_run $(add_quotes 1 "$cfg_agent") monitor $cfg_hang_timeout
__OCFT__rc=\$?
if [ \$__OCFT__rc -eq \$OCF_NOT_RUNNING ]; then
: #The status I want, so I can do nothing.
elif [ \$__OCFT__rc -eq \$OCF_SUCCESS -o \$__OCFT__rc -eq \$OCF_RUNNING_MASTER ]; then
if [ -n "\$__OCFT__VERBOSE" ]; then
echo $(add_quotes 2 " \${__OCFT__showhost}Running agent: ./$cfg_agent ${branch[0]}")
fi
agent_run $(add_quotes 1 "$cfg_agent") stop $cfg_hang_timeout
check_success \$? $(add_quotes 1 "./$cfg_agent ${branch[0]}")
else
check_success \$__OCFT__rc $(add_quotes 1 "./$cfg_agent monitor")
fi
EOF
elif [ "${branch[0]}" = "monitor" ]; then
cat >>$sh <<EOF
if [ -n "\$__OCFT__VERBOSE" ]; then
echo $(add_quotes 2 " \${__OCFT__showhost}Running agent: ./$cfg_agent ${branch[0]}")
fi
agent_run $(add_quotes 1 "$cfg_agent") $(add_quotes 1 "${branch[0]}") $cfg_hang_timeout
EOF
else
cat >>$sh <<EOF
if [ -n "\$__OCFT__VERBOSE" ]; then
echo $(add_quotes 2 " \${__OCFT__showhost}Running agent: ./$cfg_agent ${branch[0]}")
fi
agent_run $(add_quotes 1 "$cfg_agent") $(add_quotes 1 "${branch[0]}") $cfg_hang_timeout
check_success \$? $(add_quotes 1 "./$cfg_agent ${branch[0]}")
EOF
fi
else
cat >>$sh <<EOF
test -n $(add_quotes 2 "\$${branch[1]}")
check_success \$? $(add_quotes 1 "test -n \"\$${branch[1]}\"")
if [ -n "\$__OCFT__VERBOSE" ]; then
echo $(add_quotes 2 " \${__OCFT__showhost}Running agent: ./$cfg_agent ${branch[0]}")
fi
agent_run $(add_quotes 1 "$cfg_agent") $(add_quotes 1 "${branch[0]}") $cfg_hang_timeout
__OCFT__ret=\$?
if [ -n "\$__OCFT__VERBOSE" ]; then
echo -n " \${__OCFT__showhost}Checking return value:"
fi
if [ -n "\${__OCFT__retval[__OCFT__ret]}" ]; then
__OCFT__retstr="\${__OCFT__retval[__OCFT__ret]}"
else
__OCFT__retstr=\$__OCFT__ret
fi
if [ \$__OCFT__ret -eq \$${branch[1]} ]; then
if [ -n "\$__OCFT__VERBOSE" ]; then
echo -e $(add_quotes 2 " \\033[32mOK\\033[0m. The return value '\\033[34m\$__OCFT__retstr\\033[0m' == '\\033[34m${branch[1]}\\033[0m'")
else
echo -e "\\033[32mOK\\033[0m."
fi
else
if [ -n "\$__OCFT__VERBOSE" ]; then
echo -en $(add_quotes 2 " \\033[31mFAILED\\033[0m. The return value '\\033[34m\$__OCFT__retstr\\033[0m' != '\\033[34m${branch[1]}\\033[0m'. ")
else
echo -en "\\033[31mFAILED\\033[0m. Agent returns unexpected value: '\$__OCFT__retstr'. "
fi
echo "See details below:"
cat /tmp/.ocft_runlog
echo
quit 1
fi
EOF
fi
;;
Bash|Bash@*)
cat >>$sh <<EOF
if [ -n "\$__OCFT__VERBOSE" ]; then
echo $(add_quotes 2 " \${__OCFT__showhost}Setting system environment: ${trunk[1]}")
fi
${trunk[1]}
check_success \$? $(add_quotes 1 "${trunk[1]}")
EOF
;;
BashAtExit|BashAtExit@*)
let atexit_num++
cat >>$sh <<EOF
atexit${atexit_num}()
{
if [ -n "\$__OCFT__VERBOSE" ]; then
echo $(add_quotes 2 " \${__OCFT__showhost}Setting system environment: ${trunk[1]}")
fi
${trunk[1]}
}
let __OCFT__atexit_num++
EOF
;;
*)
parse_die "unimplemented statement: ${trunk[0]}"
;;
esac
if [ -n "$host" ]; then
echo 'CMD' >>$sh
fi
;;
*)
parse_die "unimplemented statement: ${trunk[0]}"
;;
esac
done <$CASES_DIR/${agent}_preparse
if [ -r "$CASES_DIR/${agent}_setup" ]; then
cat >$CASES_DIR/setup_${agent}.sh <<EOF
-#!/bin/bash
+#!@BASH_SHELL@
# Agent: $cfg_agent
# Summary: SETUP before test
echo "Initializing '$cfg_agent' ..."
. $OCFT_DIR/caselib || {
echo "ERROR: '$OCFT_DIR/caselib' not found."
exit 2
}
$(test -r "$CASES_DIR/${agent}_var" && cat $CASES_DIR/${agent}_var)
$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
EOF
for host in $(test -r $CASES_DIR/${agent}_hosts && cat $CASES_DIR/${agent}_hosts); do
cat >>$CASES_DIR/setup_${agent}.sh <<EOF
# Initialize remote shell
backbash_start $host
backbash $host <<CMD
__OCFT__VERBOSE=\$__OCFT__VERBOSE
CMD
backbash $host <$OCFT_DIR/caselib
backbash $host <<'CMD'
$(test -r "$CASES_DIR/${agent}_var" && cat $CASES_DIR/${agent}_var)
__OCFT__MYROOT="$cfg_agent_root"
__OCFT__showhost="${host}: "
$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
$(cat $CASES_DIR/${agent}_setup)
check_success \$? "SETUP-AGENT"
CMD
backbash_stop $host
EOF
done
cat >>$CASES_DIR/setup_${agent}.sh <<EOF
$(cat $CASES_DIR/${agent}_setup)
check_success \$? "SETUP-AGENT"
echo "Done."
echo
quit 0
EOF
chmod a+x $CASES_DIR/setup_${agent}.sh
fi
if [ -r "$CASES_DIR/${agent}_cleanup" ]; then
cat >$CASES_DIR/cleanup_${agent}.sh <<EOF
-#!/bin/bash
+#!@BASH_SHELL@
# Agent: $cfg_agent
# Summary: CLEANUP after test
echo "Cleaning '$cfg_agent' ..."
. $OCFT_DIR/caselib || {
echo "ERROR: '$OCFT_DIR/caselib' not found."
exit 2
}
$(test -r "$CASES_DIR/${agent}_var" && cat $CASES_DIR/${agent}_var)
$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
$(cat $CASES_DIR/${agent}_cleanup)
check_success \$? "CLEANUP-AGENT"
EOF
for host in $(test -r $CASES_DIR/${agent}_hosts && cat $CASES_DIR/${agent}_hosts); do
cat >>$CASES_DIR/cleanup_${agent}.sh <<EOF
# Initialize remote shell
backbash_start $host
backbash $host <<CMD
__OCFT__VERBOSE=\$__OCFT__VERBOSE
CMD
backbash $host <$OCFT_DIR/caselib
backbash $host <<'CMD'
$(test -r "$CASES_DIR/${agent}_var" && cat $CASES_DIR/${agent}_var)
__OCFT__MYROOT="$cfg_agent_root"
__OCFT__showhost="${host}: "
$(test -n "$cfg_install_package" && echo "agent_install ${cfg_install_package[@]}")
$(cat $CASES_DIR/${agent}_cleanup)
check_success \$? "CLEANUP-AGENT"
CMD
backbash_stop $host
EOF
done
cat >>$CASES_DIR/cleanup_${agent}.sh <<EOF
echo "Done."
echo
quit 0
EOF
chmod a+x $CASES_DIR/cleanup_${agent}.sh
fi
case_parse_finish
agent_parse_finish
done
}
start_test()
{
local sh shs testsh agents line ret
local rc=0
local varlib
local rc_f
if ! cd $CASES_DIR >/dev/null 2>&1; then
die "cases directory not found."
fi
if [ ! -d logs ]; then
mkdir logs
fi
export __OCFT__VERBOSE=$opt_verbose
if [ $# -eq 0 ]; then
agents=($(ls -1 *.sh 2>/dev/null | sed 's/.*_\([^_]*\)\.sh$/\1/' | sort | uniq))
else
agents=("$@")
fi
for shs in "${agents[@]}"; do
if [ -z "$opt_incremental" ]; then
testsh="setup_${shs}.sh
$(ls -1 [0-9]*_${shs}.sh 2>/dev/null | sort -n)
cleanup_${shs}.sh"
else
testsh="setup_${shs}.sh
$(ls -1 [0-9]*_${shs}.retest 2>/dev/null | sed 's/retest$/sh/' | sort -n)
cleanup_${shs}.sh"
fi
if [ -n "$opt_trace_ra" ]; then
varlib=${HA_VARLIB:="/var/lib/heartbeat"}
export OCF_RESKEY_trace_ra=1
echo "RA trace on, output in $varlib/trace_ra"
fi
rc_f=`mktemp`
(for sh in $testsh; do
if [ -r "$sh" ]; then
if [ -n "$opt_trace_ra" ]; then
export OCF_RESOURCE_INSTANCE="`echo $sh | sed 's/_.*//'`"
fi
./$sh
ret=$?
case "$sh" in
setup*)
rc=$((rc|ret))
if [ $ret -ne 0 ]; then
warn "SETUP failed, break all tests of '$shs'."
break
fi
;;
cleanup*)
if [ $ret -ne 0 ]; then
warn "CLEANUP failed."
fi
;;
[0-9]*)
case $ret in
3) die "core function failed, break all tests." ;;
2) warn "core function failed, break all tests of '$shs'."; break ;;
1) touch ${sh%.*}.retest ;;
0) rm -f ${sh%.*}.retest ;;
esac
rc=$((rc|ret))
;;
esac
fi
done 2>&1; echo $rc > $rc_f) | while read -r line; do
echo "$line"
echo "$(date '+%F %T'): $line" | cat -A |
sed -r 's/\^\[\[[0-9]+m|\^I|.$//g' >>logs/$shs.log
done
done
rc=`cat $rc_f`
rm -f $rc_f
return $rc
}
agent_clean()
{
local typ ra
typ=$1
shift
if [ $# -eq 0 ]; then
rm -f $CASES_DIR/*.$typ
else
for ra in "$@"; do
rm -f $CASES_DIR/*_${ra}.$typ
done
fi
}
agent_retest_clean()
{
agent_clean retest "$@"
}
agent_obj_clean()
{
agent_clean sh "$@"
}
usage()
{
cat <<EOF
$0 ACTION [OPTION] [agent1 [agent2] [...]]
ACTIONs include:
make [-d dir] Generate the testing shell scripts.
-d The directory that contains
configuration of cases.
test [-v|-i|-X] Execute the testing shell scripts.
-v Verbose output mode.
-i Incremental mode, skip case
which succeeded. If cleaning
the status of incremental mode
is needed, try to '$0 clean RA_NAME'.
-X Trace the RA
clean Delete the testing shell scripts.
help [-v] Show this help and exit.
-v Show HOWTO and exit.
Version 0.44
See '$OCFT_DIR/README' for detail.
EOF
}
howto()
{
cat <<EOF
HOW TO USE THIS TOOL
- Ocft is a testing tool for resource agents. Instead of the policy of HA,
it mainly concerns whether resource agents run correct locally. It can
design types of complicated environments to test the reliability of
resource agents. Precisely, it is to display whether resource agents can
return to correct or expected value. The advantage of the tool provides
us with competence to design conditions which can be recorded or reproduced.
Hence it is useful to debuggers.
* Components
** Test case generator (/usr/sbin/ocft)
- Turning configuration files of test case to executable scripts.
** Configuration file ($CONFIGS_DIR/)
- Every configuration file directs only one resource agent and share the same
name with resource agent but contains more test cases.
** The testing script ($CASES_DIR/)
- After the generator reads configuration files and generates many testing
scripts and the script is underway, the test begins.
* How to customize the environment of testing
- Ocft designs the running conditions through two ways, one is changing the
environment variables of resource agents (it is the interface left by OCF itself),
the other is modifying the OS environment of resource agents, such as altering
the permission of some key file or IP address of the machine.
* How to test
- Firstly, you need to sketch the all complex and uncommon environments against
a certain resource agent and keep in mind what consequences may be caused by
these uncommon environments.
Secondly, write the designed conditions and foreknown consequences into
configuration files, and then run the generator to translate the test case to
executable scripts.
Finally, you need running these scripts to observe the output and learn
the running status of each test case, which will compares the predicated result
with the actual one. If they differ, you will be able to find the bugs of the
resource agent.
- All of the output with test will be recorded into the log files, you can find them
in $CASES_DIR/logs.
EOF
}
export LANG=C
# system variable
OCFT_DIR=@datadir@/@PACKAGE_NAME@/ocft
CONFIGS_DIR=@datadir@/@PACKAGE_NAME@/ocft/configs
CASES_DIR=/var/lib/@PACKAGE_NAME@/ocft/cases
# global variable
agent=
line_num=
# default configuration
init_cfg_vars
# default option
opt_verbose=
opt_incremental=
opt_cfgsdir=$CONFIGS_DIR
command="$1"
shift
case "$command" in
make)
if [ "$1" = "-d" ]; then
if [ ! -d "$2" ]; then
usage
exit 1
fi
opt_cfgsdir="$2"
shift 2
fi
if [ ! -d "$CASES_DIR" ]; then
mkdir -p "$CASES_DIR" || die "Can not create directory: ${CASES_DIR}."
fi
parse_cfg "$@"
;;
test)
for v in 1 2 3; do
case "$1" in
-v)
opt_verbose=1
shift
;;
-X)
opt_trace_ra=1
shift
;;
-i)
opt_incremental=1
shift
;;
-*)
die "bad option $1"
;;
esac
done
start_test "$@"
;;
clean)
agent_obj_clean "$@"
agent_retest_clean "$@"
;;
help)
if [ "$1" = "-v" ]; then
howto
else
usage
fi
exit 0
;;
*)
usage
exit 1
;;
esac
# vim:ts=2:sw=2:et:

File Metadata

Mime Type
text/x-diff
Expires
Mon, Apr 21, 1:40 PM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1664879
Default Alt Text
(858 KB)

Event Timeline