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 \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 ]]) AM_CONDITIONAL(BUILD_TICKLE, test "$ac_cv_member_struct_iphdr_saddr" = "yes" ) dnl ======================================================================== dnl libnet dnl ======================================================================== libnet="" libnet_version="none" LIBNETLIBS="" LIBNETDEFINES="" AC_MSG_CHECKING(if libnet is required) libnet_fatal=$enable_libnet case $enable_libnet in no) ;; yes|libnet10|libnet11|10|11) libnet_fatal=yes;; try) case $host_os in *Linux*|*linux*) libnet_fatal=no;; *) libnet_fatal=yes;; dnl legacy behavior esac ;; *) libnet_fatal=yes; enable_libnet=try;; esac AC_MSG_RESULT($libnet_fatal) if test "x$enable_libnet" != "xno"; then AC_PATH_PROGS(LIBNETCONFIG, libnet-config) AC_CHECK_LIB(nsl, t_open) dnl -lnsl AC_CHECK_LIB(socket, socket) dnl -lsocket AC_CHECK_LIB(net, libnet_get_hwaddr, LIBNETLIBS=" -lnet", []) fi AC_MSG_CHECKING(for libnet) if test "x$LIBNETLIBS" != "x" -o "x$enable_libnet" = "xlibnet11"; then LIBNETDEFINES="" if test "$ac_cv_lib_nsl_t_open" = yes; then LIBNETLIBS="-lnsl $LIBNETLIBS" fi if test "$ac_cv_lib_socket_socket" = yes; then LIBNETLIBS="-lsocket $LIBNETLIBS" fi libnet=net libnet_version="libnet1.1" fi if test "x$enable_libnet" = "xtry" -o "x$enable_libnet" = "xlibnet10"; then if test "x$LIBNETLIBS" = x -a "x${LIBNETCONFIG}" != "x" ; then LIBNETDEFINES="`$LIBNETCONFIG --defines` `$LIBNETCONFIG --cflags`"; LIBNETLIBS="`$LIBNETCONFIG --libs`"; libnet_version="libnet1.0 (old)" case $LIBNETLIBS in *-l*) libnet=`echo $LIBNETLIBS | sed 's%.*-l%%'`;; *) libnet_version=none;; esac CPPFLAGS="$CPPFLAGS $LIBNETDEFINES" AC_CHECK_HEADERS(libnet.h) if test "$ac_cv_header_libnet_h" = no; then libnet_version=none fi fi fi AC_MSG_RESULT(found $libnet_version) if test "$libnet_version" = none; then LIBNETLIBS="" LIBNETDEFINES="" if test $libnet_fatal = yes; then AC_MSG_ERROR(libnet not found) fi else AC_CHECK_LIB($libnet,libnet_init, [new_libnet=yes; AC_DEFINE(HAVE_LIBNET_1_1_API, 1, Libnet 1.1 API)], [new_libnet=no; AC_DEFINE(HAVE_LIBNET_1_0_API, 1, Libnet 1.0 API)],$LIBNETLIBS) AC_SUBST(LIBNETLIBS) fi if test "$new_libnet" = yes; then AC_MSG_CHECKING(for libnet API 1.1.4: ) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fgnu89-inline -Wall -Werror" AC_COMPILE_IFELSE([ AC_LANG_SOURCE(#include int main(){libnet_t *l=NULL; libnet_pblock_record_ip_offset(l, l->total_size); return(0); })], [AC_MSG_RESULT(no)], [AC_DEFINE(HAVE_LIBNET_1_1_4_API, 1, Libnet 1.1.4 API) AC_MSG_RESULT(yes)]) CFLAGS="$save_CFLAGS" fi sendarp_linux=0 case $host_os in *Linux*|*linux*) sendarp_linux=1;; esac 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 ]) 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 < 1.0 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. Manages ATA-over-Ethernet (AoE) target exports The local block device (or file) to export as an AoE target. Device to export The local Ethernet interface to use for exporting this AoE target. Ethernet interface The AoE shelf number to use when exporting this target. AoE shelf number The AoE slot number to use when exporting this target. AoE slot number The file to record the daemon pid to. Daemon pid file Location of the vblade binary. vblade binary EOF } ####################################################################### AoEtarget_usage() { cat <&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 < 1.00.2 Manages starting, stopping and monitoring of RAID devices which are preconfigured in /etc/conf.d/HB-ManageRAID. Manages RAID devices Name (case sensitive) of RAID to manage. (preconfigured in /etc/conf.d/HB-ManageRAID) RAID name 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 < 1.00.4 This OCF compliant resource agent manages OpenVZ VEs and thus requires a proper OpenVZ installation including a recent vzctl util. Manages an OpenVZ Virtual Environment (VE) OpenVZ ID of virtual environment (see output of vzlist -a for all assigned IDs) OpenVZ ID of VE 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 < 1.0 The resource agent of Squid. This manages a Squid instance as an HA resource. Manages a Squid proxy server instance This is a required parameter. This parameter specifies squid's executable file. Executable file This is a required parameter. This parameter specifies a configuration file for a squid instance managed by this RA. Configuration file This is a required parameter. This parameter specifies a process id file for a squid instance managed by this RA. Pidfile 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. Port number On stop, a squid shutdown is invoked first. If the resource doesn't stop within this timeout, we resort to stopping processes by sending signals and finally KILLing them. how long to wait for squid shutdown to stop the instance before resorting to kill This is an optional parameter. This RA runs in debug mode when this parameter includes 'x' or 'v'. If 'x' is included, both of STDOUT and STDERR redirect to the logfile specified by "debug_log", and then the builtin shell option 'x' is turned on. It is similar about 'v'. Debug mode This is an optional 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. A destination of the debug log END return $OCF_SUCCESS } get_pids() { SQUID_PIDS=( ) # Seek by pattern SQUID_PIDS[0]=$(pgrep -f "$PROCESS_PATTERN") # Seek by 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 < 1.0 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 Records various node attributes in the CIB PID file PID file Interval to allow values to stabilize Dampening Delay 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 ' to the equivalent 'tail -'. 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 < $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 < 1.0 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 Update Route53 VPC record for AWS EC2 Hosted zone ID of Route 53. This is the table of the Route 53 record. AWS hosted zone ID 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! Full service name Time to live for Route53 ARECORD ARECORD TTL 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". AWS Profile Name 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 # 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 < 1.0 This agent manages the clvmd daemon. clvmd Start with cmirrord (cluster mirror log daemon). activate cmirrord Options to clvmd. Refer to clvmd.8 for detailed descriptions. Daemon Options 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. Activate volume groups 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 </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 < 1.2 Master/Slave OCF Resource Agent for conntrackd This resource agent manages conntrackd 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" Name of the conntrackd executable Full path to the conntrackd.conf file. For example "/packages/conntrackd-0.9.14/etc/conntrackd/conntrackd.conf" Path to conntrackd.conf 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 < 1.0 This resource agent manages IP take-over via dynamic DNS updates. IP take-over via dynamic DNS update The hostname whose IP address will need to be updated. Hostname to update IP address to set. IP address to set 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. TTL for the DNS record The file containing the shared secret needed to update the DNS record. Please see the nsupdate man page for the exact syntax. nsupdate key file Which DNS server to send these updates for. When no server is provided, this defaults to the master server for the correct zone. DNS server to contact 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! Port number on the DNS server Additional options to be passed to nsupdate. Additional nsupdate options 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. Remove A record on stop 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 1.0 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. Manages a Novell eDirectory directory server Path to configuration file for eDirectory instance. eDir config file Should we monitor if LDAP is running for the eDirectory instance? eDir monitor ldap Should we monitor if IDM is running for the eDirectory instance? eDir monitor IDM Value for the DHOST_INITIAL_HEAP java environment variable. If unset, java defaults will be used. DHOST_INITIAL_HEAP value Value for the DHOST_MAX_HEAP java environment variable. If unset, java defaults will be used. DHOST_MAX_HEAP value Value for the DHOST_OPTIONS java environment variable. If unset, original values will be used. DHOST_OPTIONS value 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 < 1.0 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. fio IO load generator Arguments to the fio client. Minimally, this should be a (list of) job descriptions to run. fio arguments END } ####################################################################### fio_usage() { cat </dev/null 2>&1 ${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 < 0.9 Manages iSCSI Logical Unit. An iSCSI Logical unit is a subdivision of an SCSI Target, exported via a daemon that speaks the iSCSI protocol. Manages iSCSI Logical Units (LUs) 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". iSCSI target daemon implementation The iSCSI Qualified Name (IQN) that this Logical Unit belongs to. iSCSI target IQN The Logical Unit number (LUN) exposed to initiators. Logical Unit number (LUN) The path to the block device exposed. Some implementations allow this to be a regular file, too. Block device (or file) path The SCSI ID to be configured for this Logical Unit. The default is the resource name, truncated to 24 bytes. SCSI ID The SCSI serial number to be configured for this Logical Unit. The default is a hash of the resource name, truncated to 8 bytes. SCSI serial number The SCSI UNMAP command to be configured for this Logical Unit. Setting this integer to 1 will enable TPU IOCTL emulation. SCSI UNMAP (for TRIM / DISCARD) The SCSI EXTENDED COPY command to be configured for this Logical Unit. Setting this integer to 1 will enable 3PC IOCTL emulation. SCSI extended write The SCSI Compare and Write command to be configured for this Logical Unit. Setting this integer to 1 will enable CAW IOCTL emulation. SCSI compare and write The SCSI vendor ID to be configured for this Logical Unit. SCSI vendor ID The SCSI product ID to be configured for this Logical Unit. SCSI product ID TGT specific backing store type. If you want to use aio, make sure your tgtadm is built against libaio. See tgtadm(8). TGT backing store type TGT specific backing store open flags (direct|sync). See tgtadm(8). TGT backing store open flags TGT specific backing store options. See tgtadm(8). TGT backing store options TGT specific device type. See tgtadm(8). TGT device type 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. List of iSCSI LU parameters 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. List of iSCSI initiators allowed to connect to this lun. 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/. LIO iblock device number END } ####################################################################### iSCSILogicalUnit_usage() { cat < /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 < 0.9 Manages iSCSI targets. An iSCSI target is a collection of SCSI Logical Units (LUs) exported via a daemon that speaks the iSCSI protocol. iSCSI target export agent 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". Specifies the iSCSI target implementation ("iet", "tgt", "lio", or "lio-t"). The target iSCSI Qualified Name (IQN). Should follow the conventional "iqn.yyyy-mm.<reversed domain name>[:identifier]" syntax. iSCSI target IQN The iSCSI target ID. Required for tgt. iSCSI target ID 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}. iSCSI portal addresses iSCSI iSER network portal addresses. Not supported by all implementations. iSCSI iSER enabled portal addresses 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. List of iSCSI initiators allowed to connect to this target 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. Incoming account username A password used for incoming initiator authentication. Incoming account password 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. List of iSCSI target parameters END } ####################################################################### iSCSITarget_usage() { cat <> /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 # # 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 < 0.1 OCF Resource Agent to manage JIRA software JIRA OCF RA Status URL for JIRA monitoring JIRA status url Java Home in the Linux instance Java Home JIRA installation directory (binaries, ... etc) JIRA installation directory User to run Jira software with Jira user 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 < 1.0 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="" Resource agent for Kamailio The kamailio binary The kamailio binary 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. Configuration file name with full path 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. PID file 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 & characters, which need to be replaced with two ampersand characters within "kamailio.cfg": if (is_method("OPTIONS") && ($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; } Monitoring IP address used for SIP OPTIONS polling. SIP IP address the kamailio will listen on. Listening SIP address SIP port for the kamailio instance. SIP Port Extra options to add to kamailio start. extra_options 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. protocol The installation path of the sipsak tool, which is used for monitoring Kamailio via SIP OPTIONS polling. sipsak path The installation path of the "kamctl" control tool. kamctl path 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. kamctlrc path 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. kamailio user The group for kamailio process to run with. Uses the current group, if not specified or empty. kamailio group 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 < 0.1 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. Manages LXC containers The unique name for this 'Container Instance' e.g. 'test1'. Container Name Absolute path to the file holding the specific configuration for this container e.g. '/etc/lxc/test1/config'. The LXC config file. Absolute path to the container log file Container log file 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 Use 'screen' for container 'root console' output END } LXC_usage() { cat <${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 < 1.0 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 Records various node attributes in the CIB PID file PID file Interval to allow values to stabilize Dampening Delay 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 < $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 < 1.0 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 Records various node attributes in the CIB PID file PID file Interval to allow values to stabilize Dampening Delay 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 < $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 < 1.0 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. Manages a MariaDB master/slave instance Location of the MariaDB server binary MariaDB server binary Location of the MariaDB client binary MariaDB client binary Configuration file MariaDB config Directory containing databases MariaDB datadir User running MariaDB daemon MariaDB user Group running MariaDB daemon (for logfile and directory permissions) MariaDB group The logfile to be used for mysqld. MariaDB log file 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. node list The pidfile to be used for mysqld. MariaDB pid file The socket to be used for mysqld. MariaDB socket Table to be tested in monitor statement (in database.table notation) MariaDB test table MariaDB test user, must have select privilege on test_table MariaDB test user MariaDB test user password MariaDB test user password If the MariaDB database does not exist, it will be created Create the database if it does not exist Additional parameters which are passed to the mysqld on startup. (e.g. --skip-external-locking or --skip-grant-tables) Additional parameters to pass to mysqld 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. MariaDB replication user MariaDB replication password. Used for replication client and slave. Mandatory if you define a master-slave resource. MariaDB replication user password The port on which the Master MariaDB instance is listening. MariaDB replication port 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, # Zhu Lingshan # 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 < 1.1 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. Manages SCSI persistent reservations on multipath devices The name of the binary that manages the resource. the binary name of the resource Device list. Multiple devices can be listed with blank space as separator. Shell wildcars are allowed. device list Minimum number of "working" devices from device list 1) existing 2) "mpathpersist --in --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 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" minimum number of working devices reservation type reservation type 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. base master_score value 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. working device factor in master_score calculation 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. master_score decrease/increase delay time 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 <&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 # 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 < 1.0 This agent sends NFSv3 reboot notifications to clients which informs clients to reclaim locks. sm-notify reboot notifications 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. source IP addresses 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. sm-notify arguments END } v3notify_usage() { cat < /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 # 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 < 1.0 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. Redis server Path to \`redis-server\` Path to \`redis-server\` Path to \`redis-cli\` Path to \`redis-cli\` Path to 'redis.conf' Path to 'redis.conf' User to run redis as Redis user Directory to store socket and pid file in Redis var/run dir The filename to use for the pidfile. Will be created in the rundir. Should only be a basename, not a full path. Redis pidfile name The filename to use for the socket. Will be crated in the rundir. Should only be a basename, not a full path. Redis socket name Port for replication client to connect to on remote server Replication port 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. Tunnel host for replication traffic 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 Mapping of Redis server name to redis port 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. Wait for last known master 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 < 1.0 This script manages a rsyslog instance as an HA resource. rsyslog resource agent This parameter specifies a configuration file for a rsyslog instance managed by this RA. Configuration file This parameter specifies rsyslog's executable file. rsyslog executable 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. Start options 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 < 1.1 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. Manages SCSI PERSISTENT RESERVATIONS The name of the binary that manages the resource. the binary name of the resource Device list. Multiple devices can be listed with blank space as separator. Shell wildcars are allowed. device list 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" minimum number of working devices reservation type reservation type 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. base master_score value 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. working device factor in master_score calculation 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. master_score decrease/increase delay time 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 <&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 . # # 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 < 0.1 Resource script for Stand-alone LDAP Daemon (slapd). It manages a slapd instance as an OCF resource. Manages a Stand-alone LDAP Daemon (slapd) instance Full path to the slapd binary. For example, "/usr/sbin/slapd". Full path to slapd binary Full path to the ldapsearch binary. For example, "/usr/bin/ldapsearch". Full path to ldapsearch binary Full path to a slapd configuration directory or a slapd configuration file. For example, "/etc/ldap/slapd.d" or "/etc/ldap/slapd.conf". Full path to configuration directory or file File to read the PID from; read from olcPidFile/pidfile in config if not set. File to read PID from 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. User name or id slapd will run with Group name or id slapd will run with. Group name or id slapd will run with LDAP (and other scheme) URLs slapd will serve. For example, "ldap://127.0.0.1:389 ldaps:/// ldapi:///" LDAP (and other scheme) URLs to serve 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. Suffix that will be monitored for availability. 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. Suffix that will not be monitored for availability. Distinguished Name used to bind to the LDAP directory for testing. Leave blank to bind to the LDAP directory anonymously. Distinguished Name used to bind to the LDAP directory for testing. Password used to bind to the LDAP directory for testing. Password used to bind to the LDAP directory for testing. slapd may be called with additional parameters. Specify any of them here. Any additional parameters to slapd. Number of seconds to wait for shutdown (using SIGTERM) before resorting to SIGKILL Seconds before stop escalation to KILL Maximum number of open files (for ulimit -n) Max open files 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 < 1.0 This script manages a syslog-ng instance as an HA resource. Syslog-ng resource agent This parameter specifies a configuration file for a syslog-ng instance managed by this RA. Configuration file This parameter specifies syslog-ng's executable file. syslog-ng executable 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. Start options 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. Number of seconds to await to confirm a normal stop method 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 ## # # # # # # # # # # # # ### 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 : 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 < 1.0 This script manages vsftpd Manages an vsftpd The vsftpd binary path. For example, "/usr/sbin/vsftpd" Full path to the vsftpd binary The vsftpd configuration file name with full path. For example, "/etc/vsftpd/vsftpd.conf" Configuration file name with full path The vsftpd pidfile with full path. For example, "/var/run/vsftpd.pid" PID file with full path 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 # # 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: # # # # # # # # # # # # # # 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 < 1.0 Sybase ASE Failover Instance Sybase ASE Failover Instance Instance name of resource agent "ASEHAagent" name The home directory of sybase products SYBASE home directory The directory name under sybase_home where ASE products are installed SYBASE_ASE directory name The directory name under sybase_home where OCS products are installed, i.e. ASE-15_0 SYBASE_OCS directory name The ASE server name which is configured for the HA service ASE server name The full path of login file which contains the login/password pair Login file The full path of interfaces file which is used to start/access the ASE server Interfaces file The user who can run ASE server Sybase user The maximum seconds to wait for the ASE server to shutdown before killing the process directly Shutdown timeout value The maximum seconds to wait for an ASE server to complete before determining that the server had failed to start Start timeout value The maximum seconds to wait for the response of ASE server before determining that the server had no response while running deep probe Deep probe timeout value 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 < 1.0 Defines a bind mount. Defines a bind mount. Symbolic name for this bind mount. Bind Mount Name Target of this bind mount Target mountpoint Source of the bind mount Source of the bind mount 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. Force Unmount 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 < 1.0 This defines a cluster file system mount (i.e. GFS) Defines a cluster file system mount. Symbolic name for this file system. File System Name Path in file system heirarchy to mount this file system. Mount Point Block device, file system label, or UUID of file system. Device or Label File system type. If not specified, mount(8) will attempt to determine the file system type. File system type 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. Force Unmount 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. Seppuku Unmount File system ID for NFS exports. This can be overridden in individual nfsclient entries. NFS File system ID 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. Enable NFS lock workarounds 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. Enable NFS daemon and lockd workaround 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. Mount Options 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). Utilize findmnt to detect if and where filesystems are mounted 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 # Copyright (c) 2014 David Vossel # # 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 < 1.0 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. Resource Agent that manages an IBM DB2 LUW databases in Standard role with multiple partition support. The instance of the database(s). instance List of databases to be managed, e.g "db1 db2". Defaults to all databases in the instance. List of databases to be managed The number of the partion (DBPARTITIONNUM) to be managed. database partition number (DBPARTITIONNUM) 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 < 1.0 This defines a standard file system mount (= not a clustered or otherwise shared file system). Defines a file system mount. Symbolic name for this file system. File System Name Path in file system heirarchy to mount this file system. Mount Point Block device, file system label, or UUID of file system. Device or Label File system type. If not specified, mount(8) will attempt to determine the file system type. File system type 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. Force Unmount 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. Quick/brief status checks. 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. Seppuku Unmount If set and unmounting the file system fails, the node will try to kill lockd and issue reclaims across all remaining network interface cards. Enable NFS lock workarounds 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. Enable NFS daemon and lockd workaround File system ID for NFS exports. This can be overridden in individual nfsclient entries. NFS File system ID 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. Force fsck support Options used when the file system is mounted. These are often file-system specific. See mount(8) for supported mount options. Mount Options 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). Utilize findmnt to detect if and where filesystems are mounted 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 < 1.0 This is an IP address. Both IPv4 and IPv6 addresses are supported, as well as NIC link monitoring for each IP address. This is an IP address. 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. IP Address IPv4 or IPv6 address protocol family. Family Enabling this causes the status check to fail if the link on the NIC to which this IP address is bound is not present. Monitor NIC Link If set and unmounting the file system fails, the node will try to kill lockd and issue reclaims across all remaining network interface cards. Enable NFS lock workarounds Amount of time to sleep after removing an IP address. Value is specified in seconds. Default value is 10. Amount of time (seconds) to sleep. Disable updating of routing using RDISC protocol and preserve static routes. Disable updating of routing using RDISC protocol 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. Network interface 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 " 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 " 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 " 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
[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
# 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
# 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
[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 < 1.0 This defines an NFS/CIFS mount for use by cluster services. Defines an NFS/CIFS file system mount. Symbolic name for this file system. File System Name Path in file system heirarchy to mount this file system. Mount Point Server IP address or hostname IP or Host NFS Export directory name or CIFS share Export File System type (nfs, nfs4 or cifs) File System Type Do not unmount the filesystem during a stop or relocation operation Skip unmount opration 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. Force Unmount 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. Seppuku Unmount Provides a list of mount options. If none are specified, the NFS file system is mounted -o sync. Mount Options 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). Utilize findmnt to detect if and where filesystems are mounted 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 < 1.0 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. Defines an NFS client. 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. Client Name 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. Target Hostname, Wildcard, or Netgroup This is the path to export to the target. This field is generally left blank, as it inherits the path from the parent export. Path to Export File system ID inherited from the parent nfsexport/ clusterfs/fs resource. Putting fsid in the options field will override this. File system ID Defines a list of options for this particular client. See 'man 5 exports' for a list of available options. Export Options 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. Allow recovery Service this NFS export belongs to. Used for caching exports on a per-service basis. Service Name 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. Enable exportfs list caching 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="\" 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 < 1.0 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. This defines an NFS export. Descriptive name for this export. Generally, only one export is ever defined, and it's called "generic nfs export". Name If you can see this, your GUI is broken. If you can see this, your GUI is broken. If you can see this, your GUI is broken. If you can see this, your GUI is broken. If you can see this, your GUI is broken. If you can see this, your GUI is broken. 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 < 1.0 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. This defines an NFS server resource. Descriptive name for this server. Generally, only one server is ever defined per service. Name 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. This is the path you intend to export. 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". This is the path containing shared NFS recovery information, relative to the path parameter. 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. This is the port where rpc.statd should listen on. This is the Kerberos hostname, which should be set according to the floating IP. This is the Kerberos hostname. 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 # Lon Hohberger # Michael Moon # Ryan McCabe # # 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 < 1.0 Oracle 10g/11g Failover Instance Oracle 10g/11g Failover Instance Instance name (SID) of oracle instance Oracle SID 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. Oracle Listener Instance Name Oracle user name. This is the user name of the Oracle user which the Oracle AS instance runs as. Oracle User Name This is the Oracle (application, not user) home directory. This is configured when you install Oracle. Oracle Home Directory 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) Oracle Installation Type 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. Virtual Hostname 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. Full path to the directory containing tnsnames.ora 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 [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 # Lon Hohberger # Michael Moon # Ryan McCabe # # 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 # Lon Hohberger # Michael Moon # Ryan McCabe # # 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 < 1.0 The script resource allows a standard LSB-compliant init script to be used to start a clustered service. LSB-compliant init script as a clustered resource. Name Name Path to script Path to script Inherit the service name, in case the script wants to know this information. Inherit the service name. 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 < 1.0 This defines a collection of resources, known as a resource group or cluster service. Defines a service (resource group). This is the name of the resource group. Name. Failover domains define lists of cluster members to try in the event that a resource group fails. Failover domain. 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. Automatic start after quorum formation 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. Exclusive service. 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. Enable NFS lock workarounds. 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. Enable exportfs list caching (performance). 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. Failure recovery policy (restart, relocate, or disable). Service dependency; will not start without the specified service running. Top-level service this depends on, in service:name format. 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. Service dependency mode (soft or hard). Maximum restarts for this service. Maximum restarts for this service. 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. Restart expiration time; amount of time before a restart is forgotten. 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. Service priority. 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 < 1.0 Dynamic smbd/nmbd resource agent Dynamic smbd/nmbd resource agent Samba Symbolic Name. This name will correspond to /etc/samba/smb.conf.NAME Samba Name Workgroup name Workgroup name Inherit the service name. We need to know the service name in order to determine file systems and IPs for this smb service. Inherit the service name. 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" < "$conf" < $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 # # Copy out a list from , merge them with the system nfs lock # list, and send them out as 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 " 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 # # Send the contents of 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 /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 EOT } sha1_addToFile() { declare sha1line="# rgmanager-sha1 $(sha1sum "$1")" echo $sha1line >> "$1" } sha1_addToFileXML() { declare sha1line="" 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/^\( 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>.*$/\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>.*$/\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 * Copyright (C) 2001 Matt Soffen * * 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 #include #include #include #include #include #include #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_SYS_SOCKIO_H #include #endif #include #include #include #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 #include #include #include #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 <&$wfd cat >&$wfd <&/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 <>$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 <>$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 <>$sh if [ -n "$host" ]; then echo "backbash $host <<'CMD'" >>$sh fi case "${trunk[0]}" in Env|Env@*) cat >>$sh <>$sh <>$sh <>$sh <>$sh <>$sh <>$sh <>$sh <>$sh <>$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 <>$CASES_DIR/setup_${agent}.sh <>$CASES_DIR/setup_${agent}.sh <$CASES_DIR/cleanup_${agent}.sh <>$CASES_DIR/cleanup_${agent}.sh <>$CASES_DIR/cleanup_${agent}.sh </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 <