diff --git a/configure.in b/configure.in index d165d9bcf..11821f7b0 100644 --- a/configure.in +++ b/configure.in @@ -1,2860 +1,2859 @@ dnl dnl autoconf for heartbeat dnl Started by David Lee December 2000 dnl automake stuff dnl added by Michael Moerz February 2001 dnl dnl License: GNU General Public License (GPL) dnl Initialiase, with sanity check of a unique file in the hierarchy AC_INIT(heartbeat.spec) AC_PREREQ(2.53) AC_CONFIG_AUX_DIR(.) AC_REVISION($Revision: 1.552 $) dnl cvs revision 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/hb_config.h dnl - Contains a subset of defines checked here dnl - Manually edit include/hb_config.h.in to have configure include dnl new defines dnl - Should not include HAVE_* defines dnl - Safe to include anywhere AM_CONFIG_HEADER(include/config.h include/hb_config.h) ALL_LINGUAS="en fr" AC_ARG_WITH(hapkgversion, [ --with-hapkgversion=name Override package version (if you're a packager needing to pretend) ], [ HAPKGVERSION="$withval" ], [ HAPKGVERSION="" ], ) if test -z "$HAPKGVERSION" ; then HAPKGVERSION="2.99.3" fi AM_INIT_AUTOMAKE(heartbeat, $HAPKGVERSION) RPMREL=1 AC_SUBST(RPMREL) HB_PKG=heartbeat AC_SUBST(HB_PKG) DISTDIR=$HB_PKG-$VERSION TARFILE=$DISTDIR.tar.gz AC_SUBST(DISTDIR) AC_SUBST(TARFILE) CC_IN_CONFIGURE=yes export CC_IN_CONFIGURE INIT_EXT="" USE_MODULES=0 echo Our Host OS: $host_os/$host 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". pf_argv_set="" case "$host_os" in *bsd*) LIBS="-L/usr/local/lib" CPPFLAGS="$CPPFLAGS -I/usr/local/include" INIT_EXT=".sh" REBOOT_OPTIONS="-f" POWEROFF_OPTIONS="-f" ;; *solaris*) pf_argv_set="PF_ARGV_NONE" REBOOT_OPTIONS="-n" POWEROFF_OPTIONS="-n" ;; *linux*) USE_MODULES=1 REBOOT_OPTIONS="-nf" POWEROFF_OPTIONS="-nf" ;; dnl anything? darwin*) AC_DEFINE_UNQUOTED(ON_DARWIN, 1, Compiling for Darwin platform) LIBS="$LIBS -L${prefix}/lib" CFLAGS="$CFLAGS -I${prefix}/include" REBOOT_OPTIONS="-f" POWEROFF_OPTIONS="-f" ;; esac AC_SUBST(INIT_EXT) AC_SUBST(USE_MODULES) AC_SUBST(REBOOT_OPTIONS) AC_SUBST(POWEROFF_OPTIONS) AC_DEFINE_UNQUOTED(REBOOT_OPTIONS, "$REBOOT_OPTIONS", reboot options) AC_DEFINE_UNQUOTED(POWEROFF_OPTIONS, "$POWEROFF_OPTIONS", poweroff options) AC_DEFINE_UNQUOTED(HA_LOG_FACILITY, LOG_DAEMON, Default logging facility) dnl Info for building/packaging systems. dnl dnl "pkg" (typically Solaris) generally suggests package names of the form: dnl COMPname dnl where: dnl COMP: (upper case) resembles a four character company "stock ticker"; dnl name: (lower case) is short-form (few character) product name. dnl dnl It is also conventional for the name to be closely related to the dnl installation location, typically "/opt/COMPname". dnl dnl See "linux-ha-dev" discussion, "heartbeat package name", from 12/Oct/2005. dnl "LXHAhb" seems the least evil compromise for a default. dnl Any site or packager may, of course, override this. dnl AC_ARG_WITH(pkgname, [ --with-pkgname=name name for pkg (typically for Solaris) ], [ PKGNAME="$withval" ], [ PKGNAME="LXHAhb" ], ) AC_SUBST(PKGNAME) MISSINGTHINGS="" MISSINGOPTIONALS="" FatalMissingThing() { if test X"$MISSINGTHINGS" = X; then MISSINGTHINGS="$MISSINGTHINGS $1" else MISSINGTHINGS="$MISSINGTHINGS, $1" fi shift AC_MSG_RESULT(configure: ERROR: $1 ====================) shift for j in "$@" do if test "X$j" != X-; then AC_MSG_RESULT(configure: $j ==) fi done } WarnMissingThing() { if test X"$MISSINGOPTIONALS" = X; then MISSINGOPTIONALS="$MISSINGOPTIONALS $1" else MISSINGOPTIONALS="$MISSINGOPTIONALS, $1" fi shift AC_MSG_RESULT(configure: WARNING: $1 ====================) shift for j in "$@" do if test "X$j" != X-; then AC_MSG_RESULT(configure: $j ==) fi done } CheckMissingThings() { if test "X$MISSINGOPTIONALS" != "X" then AC_MSG_WARN(The following recommended components noted earlier are missing: $MISSINGOPTIONALS We will continue but you may have lost some non-critical functionality.) fi if test "X$MISSINGTHINGS" != "X" then AC_MSG_ERROR(The following required components noted earlier are missing: $MISSINGTHINGS Please supply them and try again.) fi } dnl dnl dnl Don't ya just hate working around buggy code? dnl dnl At least code that doesn't do what you want... dnl dnl This is to make substitutions work right in RPM specfiles. dnl dnl Horms says "This is pretty ugly". dnl Alanr says: "It works. s/ ugly//" dnl dnl Patches are being accepted... dnl dnl Keep copy of original (default) prefix prefix_orig="$prefix" prefix=`eval echo "$prefix"` case $prefix in NONE) prefix=/usr/local;; esac var() { case $1 in *'${'*) res=`eval echo "$1"`;; *) res="$1";; esac case "$res" in ""|NONE) echo "$2";; *) echo "$res";; esac } dnl Keep copy of original (default) localstatedir localstatedir_orig="$localstatedir" exec_prefix=`var "$exec_prefix" "$prefix"` bindir=`var "$bindir" "$exec_prefix/bin"` sbindir=`var "$sbindir" "$exec_prefix/sbin"` datarootdir=`var "$datarootdir" "$prefix/share"` datadir=`var "$datadir" "$prefix/share"` sysconfdir=`var "$sysconfdir" "$prefix/etc"` sharedstatedir=`var "$sharedstatedir" "$prefix/com"` localstatedir=`var "$localstatedir" "$prefix/var"` includedir=`var "$includedir" "$exec_prefix/include"` oldincludedir=`var "$oldincludedir" "$exec_prefix/include"` infodir=`var "$infodir" "$prefix/info"` mandir=`var "$mandir" "$exec_prefix/man"` docdir=${datadir}/doc/${HB_PKG}-${VERSION} stdocdir=${datadir}/doc/${HB_PKG}-${VERSION}/stonith libdir=`var "$libdir" "$exec_prefix/lib"` libexecdir=`var "$libexecdir" "$exec_prefix/libexec"` noarchlibdir=`var "$noarchlibdir" "$prefix/lib"` LDD=ldd dnl Which C compiler? dnl Defaults to GNU C compiler if available. dnl Always tries to set the compiler to ANSI C via options (AM) dnl Can force other with environment variable "CC". AC_PROG_CC AC_PROG_CC_STDC AM_PROG_CC_C_O dnl ************************************************************************ dnl Override the RPM target architecture on those platforms that need it... dnl ************************************************************************ case "$host_cpu" in ppc64|powerpc64) RPMTARGET="--target ppc";; *) RPMTARGET="";; esac AC_SUBST(RPMTARGET) dnl ************************************************************************ dnl Test to see whether library directories should be lib or lib64... dnl ************************************************************************ AC_MSG_CHECKING(for proper library directory suffix) tmpdir=/tmp tmpCfile=${tmpdir}/$$test.c tmpOutfile=${tmpdir}/$$test echo 'int main(int argc, char** argv) { return(1);}' >$tmpCfile if ${CC} ${CFLAGS} ${tmpCfile} -o ${tmpOutfile} then LIBC=`${LDD} ${tmpOutfile} | grep libc | sed -e 's%.*=> *%%' -e 's% .*$%%'` LibCdir=`dirname $LIBC` dirlist=`echo $LibCdir | tr '/' ' '` LibDirSuffix=unknown - for dir in dirlist + for dir in $dirlist do case $dir in *lib*) LibDirSuffix=$dir; break;; *);; esac done case $LibDirSuffix in unknown) LibDirSuffix=`basename $LibCdir`;; esac OutFileType=`file $tmpOutfile` rm -f $tmpCfile $tmpOutfile else AC_MSG_ERROR([Cannot Compile trivial C program]) fi # # The code above doesn't work right everywhere # (like Fedora and OpenBSD) # case ${LibDirSuffix} in *lib*) : Cool;; *) : Sigh... case $OutFileType in *64-bit*) case $host_os in openbsd*) LibDirSuffix=lib;; *) LibDirSuffix=lib64;; esac;; *32-bit*) LibDirSuffix=lib;; *) LibDirSuffix=lib;; esac;; esac # # This may not yet be quite right for PPC where the default # is to produce 32-bit binaries, even though the OS is 64-bit # or for that matter for system Z, But, it's a lot better than # it used to be. # AC_MSG_RESULT($LibDirSuffix) case $libdir in */*${LibDirSuffix}) : Cool ;; *) : Uh Oh... libdir=`dirname $libdir`/$LibDirSuffix AC_MSG_WARN([Overriding libdir to: $libdir]);; esac case $libexecdir in */$LibDirSuffix) : Cool ;; *) : Uh Oh... libexecdir=`dirname $libexecdir`/$LibDirSuffix AC_MSG_WARN([Overriding libexecdir to: $libexecdir]);; esac for j in exec_prefix bindir sbindir datadir sysconfdir localstatedir \ includedir oldincludedir mandir docdir stdocdir libdir noarchlibdir do dirname=`eval echo '${'${j}'}'` if test ! -d "$dirname" then AC_MSG_WARN([$j directory ($dirname) does not exist!]) fi done dnl The GNU conventions for installation directories don't always dnl sit well with this software. In particular, GNU's stated: dnl dnl '$(localstatedir)' should normally be '/usr/local/var', ... dnl dnl is poor for us: much better would be somewhere under '/var'. dnl dnl Here within "configure" it would be poor practice for us to interfere dnl with such values, irrespective of our opinion: dnl 1. user perspective: we would have gone behind their back; dnl 2. autoconf perspective: autoconf should avoid any OS-specific mindset. dnl dnl So if localstatedir still has its default value, we issue an advisory dnl warning and inform folk of our own "ConfigureMe", which is ideally dnl suited for setting such aspects (by user, and per-OS). dnl dnl [ Another option would be to detect, and to warn of, (post-expansion) dnl non-"/var/[...]" values: something like: dnl if test `expr "$localstatedir" : '^/var/.*'` -ge '5' \ dnl -o `expr "$localstatedir" : '^/var.*'` -eq '4' dnl then else fi dnl ] # If original localstatedir had defaulted then sanity-check the result. if test "x$localstatedir_orig" = 'x${prefix}/var' && # Note quote types test "x$prefix_orig" = xNONE then SNOOZING=10 AC_MSG_WARN(value/default "--localstatedir=$localstatedir" is poor.) AC_MSG_WARN("/var/something" is strongly recommended.) AC_MSG_WARN(We also recommend using "ConfigureMe".) AC_MSG_WARN(Sleeping for $SNOOZING seconds.) sleep $SNOOZING fi AC_DEFINE_UNQUOTED(HA_SYSCONFDIR, "$sysconfdir", Location of system configuration files) HA_URLBASE="http://linux-ha.org/" AC_SUBST(HA_URLBASE) AC_DEFINE_UNQUOTED(HA_URLBASE, "$HA_URLBASE", Web site base URL) HA_LIBDIR="${libdir}" AC_SUBST(HA_LIBDIR) AC_DEFINE_UNQUOTED(HA_LIBDIR,"$HA_LIBDIR", lib directory) HA_DATADIR="${datadir}" AC_SUBST(HA_DATADIR) AC_DEFINE_UNQUOTED(HA_DATADIR,"$HA_DATADIR", data (arch-independent) directory) HA_NOARCHDATAHBDIR="$HA_DATADIR/${HB_PKG}" AC_SUBST(HA_NOARCHDATAHBDIR) AC_DEFINE_UNQUOTED(HA_NOARCHDATAHBDIR,"$HA_NOARCHDATAHBDIR", $HB_PKG noarch data directory) HA_LIBHBDIR="$HA_LIBDIR/${HB_PKG}" AC_SUBST(HA_LIBHBDIR) AC_DEFINE_UNQUOTED(HA_LIBHBDIR,"$HA_LIBHBDIR", $HB_PKG lib directory) HA_VARRUNDIR="${localstatedir}/run" AC_SUBST(HA_VARRUNDIR) AC_DEFINE_UNQUOTED(HA_VARRUNDIR,"$HA_VARRUNDIR", var run directory) HA_VARRUNHBDIR="$HA_VARRUNDIR/${HB_PKG}" AC_SUBST(HA_VARRUNHBDIR) AC_DEFINE_UNQUOTED(HA_VARRUNHBDIR,"$HA_VARRUNHBDIR", var run heartbeat directory) HA_VARRUNHBRSCDIR="$HA_VARRUNHBDIR/rsctmp" AC_SUBST(HA_VARRUNHBRSCDIR) AC_DEFINE_UNQUOTED(HA_VARRUNHBRSCDIR,"$HA_VARRUNHBRSCDIR", var run heartbeat rsctmp directory) dnl Test the default first (priority) and last (to make sure some value is set) AC_MSG_CHECKING(for the location of the lock directory) for HA_VARLOCKDIR in ${localstatedir}/lock ${localstatedir}/spool/lock ${localstatedir}/spool/locks ${localstatedir}/lock do if test -d "$HA_VARLOCKDIR" then AC_MSG_RESULT($HA_VARLOCKDIR) break fi done AC_SUBST(HA_VARLOCKDIR) AC_DEFINE_UNQUOTED(HA_VARLOCKDIR,"$HA_VARLOCKDIR", System lock directory) HA_VARLIBDIR="${localstatedir}/lib" AC_SUBST(HA_VARLIBDIR) AC_DEFINE_UNQUOTED(HA_VARLIBDIR,"$HA_VARLIBDIR", var lib directory) HA_VARLIBHBDIR="${HA_VARLIBDIR}/${HB_PKG}" AC_SUBST(HA_VARLIBHBDIR) AC_DEFINE_UNQUOTED(HA_VARLIBHBDIR,"$HA_VARLIBHBDIR", var lib heartbeat directory) HA_COREDIR="${HA_VARLIBHBDIR}/cores" AC_SUBST(HA_COREDIR) AC_DEFINE_UNQUOTED(HA_COREDIR,"$HA_COREDIR", top directory of area to drop core files in) HA_LOGDAEMON_IPC="${HA_VARLIBDIR}/log_daemon" AC_SUBST(HA_LOGDAEMON_IPC) AC_DEFINE_UNQUOTED(HA_LOGDAEMON_IPC, "$HA_LOGDAEMON_IPC", Logging Daemon IPC socket name) dnl This IS a default but we should make sure we can override it for any dnl odd OS requirements. HA_VARLOGDIR="${localstatedir}/log" AC_SUBST(HA_VARLOGDIR) AC_DEFINE_UNQUOTED(HA_VARLOGDIR,"$HA_VARLOGDIR", var log directory) STONITHPKG=stonith AC_SUBST(STONITHPKG) PILSPKG=pils AC_SUBST(PILSPKG) pils_includedir="${includedir}/${PILSPKG}" pils_plugindir="${libdir}/${PILSPKG}/plugins" stonith_includedir="${includedir}/${STONITHPKG}" stonith_plugindir="${libdir}/${STONITHPKG}/plugins" stonith_ext_plugindir="${stonith_plugindir}/external" base_includedir="${includedir}" saf_includedir="${includedir}/saf" AC_SUBST(pils_includedir) AC_SUBST(pils_plugindir) AC_SUBST(stonith_includedir) AC_SUBST(stonith_plugindir) AC_SUBST(stonith_ext_plugindir) AC_DEFINE_UNQUOTED(STONITH_EXT_PLUGINDIR, "$stonith_ext_plugindir", directory for the external stonith plugins) AC_SUBST(base_includedir) AC_SUBST(saf_includedir) AC_SUBST(docdir) AC_SUBST(stdocdir) # # Other interesting variables: ${host_vendor} and ${host_os} # sample values: suse linux # dnl We use this in the RPM specfile... AC_SUBST(ac_configure_args) cleaned_configure_args="" for j in ${ac_configure_args} do case $j in *--libdir=*|*--libexecdir=*) ;; *) cleaned_configure_args="$cleaned_configure_args $j";; esac done AC_SUBST(cleaned_configure_args) dnl ************************************************************************* PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin" export PATH dnl checks for programs dnl AC_PROG_YACC AC_DECL_YYTEXT AM_PROG_LEX AM_PATH_PYTHON AC_LIBTOOL_DLOPEN dnl Enable dlopen support... AC_LIBLTDL_CONVENIENCE dnl make libltdl a convenience lib AC_PROG_LIBTOOL dnl Replacing AC_PROG_LIBTOOL with AC_CHECK_PROG because LIBTOOL dnl was NOT being expanded all the time thus causing things to fail. AC_CHECK_PROGS(LIBTOOL, glibtool libtool libtool15 libtool13) AC_MSG_CHECKING(for glibtool or libtool*) if test x"${LIBTOOL}" = x""; then FatalMissingThing "libtool" "You need libtool to build heartbeat." \ "You can get the source from ftp://www.gnu.org/pub/gnu/" \ "or you can locate it via http://www.gnu.org/software/libtool" else AC_MSG_RESULT($LIBTOOL has been found.) fi AC_CHECK_PROGS(MAKE, gmake make) AC_MSG_CHECKING(for gmake or make) if test x"${MAKE}" = x""; then FatalMissingThing "gmake" "You need gmake to build heartbeat." \ "You can get the source from ftp://www.gnu.org/pub/gnu/" \ "or you can locate it via http://www.gnu.org/software/make/" else AC_MSG_RESULT($MAKE has been found.) fi AC_SYS_LARGEFILE AC_PATH_PROGS(HTML2TXT, lynx w3m) case $HTML2TXT in */*) ;; *) HTML2TXT="";; esac AC_PATH_PROGS(POD2MAN, pod2man, pod2man) AC_PATH_PROGS(ROUTE, route) AC_PATH_PROGS(RPM, rpmbuild) if test x"${RPM}" = x""; then AC_PATH_PROGS(RPM, rpm) fi AC_DEFINE_UNQUOTED(ROUTE, "$ROUTE", path to route command) AC_PATH_PROGS(NETSTAT, netstat, /sbin/netstat) AC_DEFINE_UNQUOTED(NETSTAT, "$NETSTAT", path to the netstat command) AC_PATH_PROGS(PING, ping, /bin/ping) AC_PATH_PROGS(IFCONFIG, ifconfig, /sbin/ifconfig) AC_PATH_PROGS(SSH, ssh, /usr/bin/ssh) AC_PATH_PROGS(SCP, scp, /usr/bin/scp) AC_PATH_PROGS(PYTHON, python) dnl Need a "mail" program which can handle "-s subject" flag. dnl Ideally would write a suitable autoconf test here. dnl Pragmatically observe: dnl Solaris: "mail" doesn't offer "-s", but "mailx" does. Want "mailx". dnl Linux: "mail" offers "-s". Some releases have "mailx" symlink to "mail". dnl *BSD: Online man pages suggest similar to Linux. dnl HP-UX: Online man pages suggest similar to Solaris. dnl Thus "mailx", if it exists, should always be good; look for it first. AC_PATH_PROGS(MAILCMD, mailx mail) AC_SUBST(MAILCMD) AC_DEFINE_UNQUOTED(IFCONFIG, "$IFCONFIG", path to the ifconfig command) AC_PATH_PROGS(GETENT, getent) AC_PATH_PROGS(IP2UTIL, ip, /sbin/ip) AC_PATH_PROGS(XML2CONFIG, xml2-config) AC_PATH_PROGS(REBOOT, reboot, /sbin/reboot) AC_PATH_PROGS(POWEROFF_CMD, poweroff, /sbin/poweroff) AC_SUBST(REBOOT) AC_SUBST(POWEROFF_CMD) AC_DEFINE_UNQUOTED(REBOOT, "$REBOOT", path to the reboot command) AC_DEFINE_UNQUOTED(POWEROFF_CMD, "$POWEROFF_CMD", path to the poweroff command) dnl "whoami", if it exists, may be hidden away on some System-V (e.g. Solaris) AC_PATH_PROGS(WHOAMI, whoami, , ${PATH}:/usr/ucb) AC_PATH_PROGS(SWIG, swig) AC_SUBST(SWIG) AC_PATH_PROGS(EGREP, egrep) AC_SUBST(EGREP) AC_PATH_PROGS(MSGFMT, msgfmt, [msgfmt not found],) AC_SUBST(MSGFMT) AC_PATH_PROGS(HG, hg, /usr/local/hg) AC_SUBST(HG) AC_PATH_PROGS(GZIP_PROG, gzip) AC_PATH_PROGS(TAR, tar) AC_PATH_PROGS(MD5, md5) AC_SUBST(GZIP_PROG) AC_SUBST(TAR) AC_SUBST(MD5) dnl The "test" program can be different from the "sh" builtin. AC_PATH_PROGS(TEST, test) AC_PATH_PROGS(PKGCONFIG, pkg-config) dnl ************************************************************************ dnl Check whether non-root user can chown. dnl ************************************************************************ if test -n "$WHOAMI"; then IAM=`$WHOAMI` fi AC_MSG_CHECKING(if chown works for non-root) F="./.chown-test.$$" touch $F if case "$IAM" in root) chown nobody $F; su nobody -c "chown root $F";; *) chown root $F esac >/dev/null 2>&1 then nonroot_chown=yes AC_MSG_RESULT(yes) else nonroot_chown=no AC_MSG_RESULT(no) fi rm -f $F AM_CONDITIONAL(NONROOT_CHOWN, test "$nonroot_chown" = yes ) dnl ************************************************************************ dnl checks for libraries dnl ************************************************************************ AC_CHECK_LIB(posix4, sched_getscheduler) dnl -lposix4 AC_CHECK_LIB(c, dlopen) dnl if dlopen is in libc... AC_CHECK_LIB(dl, dlopen) dnl -ldl (for Linux) AC_CHECK_LIB(rt, sched_getscheduler) dnl -lrt (for Tru64) AC_CHECK_LIB(gnugetopt, getopt_long) dnl -lgnugetopt ( if available ) AC_CHECK_LIB(pam, pam_start) dnl -lpam (if available) # Not sure what OSes need this... Linux and AIX don't... # and AIX barfs on it... if test "$DLPREOPEN" = yes; then DLOPEN_FORCE_FLAGS="-dlpreopen force -dlopen-self" AC_DEFINE(DLPREOPEN, 1, [enable -dlpreopen flag]) else DLOPEN_FORCE_FLAGS="" fi AC_SUBST(DLOPEN_FORCE_FLAGS) dnl ************ uuid ********************** AC_ARG_WITH(uuid, [ --with-uuid=UUID mechanism for uuid {e2fsprogs|ossp|any|no} "e2fsprogs": e2fsprogs, typically Linux "ossp": not yet implemented "any": (default) any of the above, fallback to inbuilt "no": use inbuilt ], [ uuidimpl="$withval" ], [ uuidimpl="any" ], ) case $uuidimpl in e2fsprogs) AC_CHECK_LIB(uuid, uuid_parse,, AC_MSG_ERROR([e2fsprogs uuid library was explicitly requested but not found]) ) ;; ossp) AC_CHECK_LIB(uuid, uuid_create,, AC_MSG_ERROR([ossp uuid library was explicitly requested but not found]) ) ;; no) # Do not define anything; so use inbuilt (replace) implementation. ;; any) # Default: try to discover an implementation that we can use. AC_CHECK_LIB(uuid, uuid_parse) dnl e2fsprogs dnl AC_CHECK_LIB(uuid, uuid_create) dnl ossp ;; *) AC_MSG_ERROR([An invalid uuid library was explicitly requested]) ;; esac case "$host_os" in darwin*) dnl Recent Darwin versions do not need to link against a uuid library dnl Maybe this can be moved up into the previous block but it also might dnl break things (ie. the later check for uuid_parse) AC_CHECK_FUNCS(uuid_parse) esac AC_MSG_CHECKING(uuid implementation:) if test "$ac_cv_lib_uuid_uuid_parse" = yes; then AC_MSG_RESULT(e2fsprogs) elif test "$ac_cv_func_uuid_parse" = yes; then AC_MSG_RESULT(native) elif test "$ac_cv_lib_uuid_uuid_create" = yes; then AC_MSG_RESULT(ossp) AC_MSG_ERROR([heartbeat does not yet support ossp implementation of uuid]) else AC_MSG_RESULT(inbuilt) if test x"$uuidimpl" != x"no"; then WarnMissingThing "uuid library" \ "e2fsprogs uuid library is recommended" \ "On Linux this is the e2fsprogs-devel package" \ "See also http://sourceforge.net/projects/e2fsprogs/" fi fi dnl ************ uuid ********************** EXTRAGLIBMSG="-" if test "X${PKGCONFIG}" = "X"; then AC_MSG_RESULT(not found) FatalMissingThing "pkgconfig" "Package pkgconfig is required" \ "See http://pkgconfig.sourceforge.net/" EXTRALIBMSG="(this message might be bogus because pkgconfig is missing)" fi if test "x${enable_thread_safe}" = "xyes"; then GPKGNAME="gthread-2.0" else GPKGNAME="glib-2.0" fi if test "X${PKGCONFIG}" != "X" && $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 FatalMissingThing "glib2-devel" \ "Package glib2-devel is missing." \ "You can get the source from ftp://ftp.gtk.org/pub/gtk/" \ "or you can locate it via http://www.gtk.org/download/" "$EXTRALIBMSG" fi AC_MSG_RESULT(using $GLIBCONFIG) AC_ARG_ENABLE([libnet], [ --enable-libnet Use libnet for ARP based funcationality, [default=try]], [enable_libnet=$withval], [enable_libnet=try]) 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 FatalMissingThing "libnet" "You need libnet to continue." \ "You can get libnet from http://www.packetfactory.net/libnet" \ "Note that some RPMs split libnet up into libnet and libnet-devel." \ "In this case you have to install libnet-devel too" 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) fi sendarp_linux=0 case $host_os in *Linux*|*linux*) sendarp_linux=1;; esac AC_SUBST(LIBNETLIBS) AC_SUBST(LIBNETDEFINES) AC_DEFINE(HAVE_LIBNET_API, test "x$libnet_version" != "xnone", Libnet API) AM_CONDITIONAL(SENDARP_LINUX, test $sendarp_linux = 1 ) AM_CONDITIONAL(USE_LIBNET, test "x$libnet_version" != "xnone" ) AC_MSG_CHECKING(where is python installed) if test "x${PYTHON}" = x; then PYTHON="/usr/bin/env python"; fi AC_MSG_RESULT(using $PYTHON); AC_MSG_CHECKING(if netstat supports -f inet flag) $NETSTAT -rn -f inet > /dev/null 2>&1 if test x"$?" = x"0"; then AC_DEFINE(NETSTATPARM, "-rn -f inet ", parameters to netstat to retrieve route information) AC_MSG_RESULT(yes) else AC_DEFINE(NETSTATPARM, "-rn ", parameters to netstat to retrieve route information) AC_MSG_RESULT(no) fi if test X${PING} = X then FatalMissingThing "ping" "ping command is mandantory" fi dnl Determine if we use -w1 or -t1 for ping (in PYTHON Scripts) AC_MSG_CHECKING(ping option for timeout - w or t) for PING_TIMEOUT_OPT in "-w1" "-t1" do $PING -nq -c1 $PING_TIMEOUT_OPT localhost > /dev/null 2>&1 if test "$?" = 0 then AC_DEFINE_UNQUOTED(PING_TIMEOUT_OPT, "$PING_TIMEOUT_OPT", option for ping timeout) AC_MSG_RESULT($PING_TIMEOUT_OPT) break fi done AC_SUBST(PING_TIMEOUT_OPT) dnl Determining a route (particularly for "findif"). dnl There are various mechanisms on different systems. dnl Some mechanisms require root access to evaluate, but configure is often dnl (indeed, some say should be always) running non-root. dnl dnl Therefore much of the determination has to be run-time. dnl So the principle here, at configure time, is to explore what might be dnl available, and offer as much as possible to run-time. dnl AC_DEFINE(ROUTEPARM, "-n get", paramters for route to retrieve route information) AC_DEFINE(PROCROUTE, "/proc/net/route", path were to find route information in proc) 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) AC_SUBST(WHOAMI) AC_SUBST(HTML2TXT) AC_SUBST(POD2MAN) AC_SUBST(ROUTEPARM) AC_SUBST(PROCROUTE) dnl Locales check - is a real ugly workaround for now til I find dnl something more useful dnl dnl "Eric Z. Ayers" wrote: dnl > dnl > Here are some more data points: dnl > dnl > SUN: /usr/lib/locale/ dnl > HP : /usr/lib/nls/loc/ dnl > OSF: /usr/lib/nls/loc/ dnl > LINUX: /usr/share/locale/ dnl > UNIXWARE: /usr/lib/locale/ dnl > FREEBSD: /usr/share/locale dnl > VMS: just kidding dnl FindADir() { type="$1" whatfor="$2" shift; shift; AC_MSG_CHECKING(for $whatfor directory) for dir do if test -d "$dir" then AC_MSG_RESULT($dir) echo $dir return 0 fi done AC_MSG_RESULT(not found) return 1 } locale_locations="/usr/share/locale /usr/lib/locale /usr/lib/nls/loc" LOCALE=`FindADir error "locale" $locale_locations` if test "X$LOCALE" = X then FatalMissingThing "Locale directory" "Locale directory is mandantory." fi RPMDIR=`FindADir warn "RPM" /usr/src/packages /usr/src/redhat` if test x"${HAVE_LIBRT}" = x""; then LIBRT="" else LIBRT=-lrt fi AC_SUBST(LIBRT) # # Where is dlopen? # if test "$ac_cv_lib_c_dlopen" = yes; then LIBADD_DL="" elif test "$ac_cv_lib_dl_dlopen" = yes; then LIBADD_DL=-ldl else LIBADD_DL=${lt_cv_dlopen_libs} fi dnl dnl Check for location of gettext dnl dnl On at least Solaris 2.x, where it is in libc, specifying lintl causes dnl grief. Ensure minimal result, not the sum of all possibilities. dnl And do libc first. dnl Known examples: dnl c: Linux, Solaris 2.6+ dnl intl: BSD, AIX FunIsInLib() { fun=$1 lib=$2 lib_var1="ac_cv_lib_${lib}_$fun" lib_var2="ac_cv_lib_${lib}___$fun" for v in $lib_var1 $lib_var2 do var=`eval echo '${'${v}'}'` case $var in yes) return 0;; no) return 1;; esac done return 0 } for gt_test_lib in c intl do AC_CHECK_LIB($gt_test_lib, gettext) if FunIsInLib gettext $gt_test_lib; then break fi done # # Where is gettext()? # if FunIsInLib gettext c ; then LIBADD_INTL="" elif FunIsInLib gettext intl ; then LIBADD_INTL=-lintl elif test -f /usr/local/lib/libintl.so -a -s /usr/local/lib/libintl.so; then # This was added for FreeBSD LIBADD_INTL="-lintl" elif test -f /sw/lib/libintl.a -a -s /sw/lib/libintl.la -a -s /sw/lib/libintl.dylib; then # This was added for Darwin + Fink LIBADD_INTL="-lintl" else FatalMissingThing "gettext function" "no library providing gettext found" fi dnl dnl Glib allows its headers/libraries to be installed anywhere. dnl And they provide a command to let you know where they are. dnl This is nice, but having them in standard places is nice too ;-) dnl if test "X$GLIBCONFIG" != X; then AC_MSG_CHECKING(for special glib includes: ) GLIBHEAD=`$GLIBCONFIG --cflags` AC_MSG_RESULT($GLIBHEAD) CPPFLAGS="$CPPFLAGS $GLIBHEAD" AC_SUBST(GLIBHEAD) dnl Note: Not bundling "GLIBLIB" with general "LIBS". dnl 1. Only very few programs require GLIBLIB dnl (This isn't true anymore -- AlanR) dnl 2. Danger of creating run-time dependency on build-time LD_LIBRARY_PATH AC_MSG_CHECKING(for glib library flags) GLIBLIB=`$GLIBCONFIG --libs` AC_MSG_RESULT($GLIBLIB) AC_SUBST(GLIBLIB) fi dnl ************************************************************************ dnl checks for header files dnl dnl check for ANSI *.h files first dnl asm/page.h: Linux, for system PAGE_SIZE AC_HEADER_STDC AC_CHECK_HEADERS(db.h) AC_CHECK_HEADERS(asm/page.h) AC_CHECK_HEADERS(time.h) AC_CHECK_HEADERS(stdarg.h) AC_CHECK_HEADERS(tcpd.h) AC_CHECK_HEADERS(uuid.h) AC_CHECK_HEADERS(uuid/uuid.h) AC_CHECK_HEADERS(sys/param.h) AC_CHECK_HEADERS(netinet/in.h) AC_CHECK_HEADERS([stdint.h unistd.h]) AC_CHECK_HEADERS(sys/termios.h) AC_CHECK_HEADERS(sys/reboot.h) AC_CHECK_HEADERS(termios.h) dnl ************************************************************************ dnl FreeBSD requires sys/param.h and in.h to compile test netinet headers. dnl ************************************************************************ if test "$ac_cv_header_sys_param_h" -a "$ac_cv_header_netinet_in_h" = no; then AC_CHECK_HEADERS(netinet/in_systm.h) AC_CHECK_HEADERS(netinet/ip.h) AC_CHECK_HEADERS(netinet/ip_var.h) AC_CHECK_HEADERS(netinet/ip_compat.h) AC_CHECK_HEADERS(netinet/ip_fw.h) else AC_CHECK_HEADERS(netinet/in_systm.h,[],[],[#include #include ]) if test "$ac_cv_header_in_systm_h" = no; then AC_CHECK_HEADERS(netinet/ip.h,[],[],[#include #include ]) else AC_CHECK_HEADERS(netinet/ip.h,[],[],[#include #include #include ]) fi AC_CHECK_HEADERS(netinet/ip_var.h,[],[],[#include #include ]) AC_CHECK_HEADERS(netinet/ip_compat.h,[],[],[#include #include ]) AC_CHECK_HEADERS(netinet/ip_fw.h,[],[],[#include #include ]) fi AC_CHECK_HEADERS(sys/sockio.h) AC_CHECK_HEADERS(libintl.h) AC_CHECK_HEADERS(sys/types.h) AC_CHECK_HEADERS(sys/socket.h) AC_CHECK_HEADERS(arpa/inet.h) AC_CHECK_HEADERS(net/ethernet.h) AC_CHECK_HEADERS(malloc.h) AC_CHECK_HEADERS(termio.h) AC_CHECK_HEADERS(getopt.h) AC_CHECK_HEADERS(sys/prctl.h) AC_CHECK_HEADERS(linux/watchdog.h,[],[],[#include ]) dnl Sockets are our preferred and supported comms mechanism. But the dnl implementation needs to be able to convey credentials: some don't. dnl So on a few OSes, credentials-carrying streams might be a better choice. dnl dnl Solaris releases up to and including "9" fall into this category dnl (its sockets don't carry credentials; streams do). dnl dnl At Solaris 10, "getpeerucred()" is available, for both sockets and dnl streams, so it should probably use (preferred) socket mechanism. AC_CHECK_HEADERS(stropts.h) dnl streams available (fallback option) AC_CHECK_HEADERS(ucred.h) dnl e.g. Solaris 10 decl. of "getpeerucred()" AC_CHECK_FUNCS(getpeerucred) dnl ************************************************************************ dnl checks for headers needed by clplumbing On BSD AC_CHECK_HEADERS(sys/syslimits.h) if test "$ac_cv_header_sys_param_h" = no; then AC_CHECK_HEADERS(sys/ucred.h) else AC_CHECK_HEADERS(sys/ucred.h,[],[],[#include ]) fi dnl ************************************************************************ dnl checks for headers needed by clplumbing On Solaris AC_CHECK_HEADERS(sys/cred.h xti.h) dnl ************************************************************************ dnl checks for headers needed by clplumbing On FreeBSD/Solaris AC_CHECK_HEADERS(sys/filio.h) dnl dnl These next two are used to help us figure out whether to include dnl some optional STONITH plugins... dnl AC_CHECK_HEADERS(vacmclient_api.h) AC_CHECK_HEADERS(curl/curl.h) AC_CHECK_HEADERS(openhpi/SaHpi.h) AC_MSG_CHECKING(for special libxml2 includes) if test "x$XML2CONFIG" = "x"; then AC_MSG_RESULT(libxml2 config not found) else XML2HEAD=`$XML2CONFIG --cflags` AC_MSG_RESULT($XML2HEAD) AC_CHECK_LIB(xml2, xmlReadMemory) fi CPPFLAGS="$CPPFLAGS $XML2HEAD" dnl ************************************************************************ dnl * Check for netinet/icmp6.h to enable the IPv6addr resource agent AC_CHECK_HEADERS(netinet/icmp6.h,[],[],[#include ]) AM_CONDITIONAL(USE_IPV6ADDR, test "$ac_cv_header_netinet_icmp6_h" = yes -a "$new_libnet" = yes ) AC_CHECK_HEADERS(libxml/xpath.h) dnl dnl Could check for the libraries, but if you have the headers, dnl you're a dolt for not having installed the libs ;-) dnl AM_CONDITIONAL(USE_VACM, test "$ac_cv_header_vacmclient_api_h" = yes) AM_CONDITIONAL(USE_DRAC3, test "$ac_cv_header_curl_curl_h" = yes -a "$ac_cv_header_libxml_xpath_h" = yes) AM_CONDITIONAL(USE_OPENHPI, test "$ac_cv_header_openhpi_SaHpi_h" = yes && pkg-config --atleast-version 2.6 openhpi) dnl dnl SNMP checks dnl SNMPLIB="" SNMPCONFIG="" ENABLE_SNMP="yes" if test "x${enable_snmp}" = "xno"; then ENABLE_SNMP="no" fi AC_CHECK_HEADERS(ucd-snmp/snmp.h,[],[],[#include #include ]) AC_CHECK_HEADERS(net-snmp/net-snmp-config.h) if test "x${ENABLE_SNMP}" = "xno"; then # nothing : elif test "x${ac_cv_header_net_snmp_net_snmp_config_h}" = "xyes"; then AC_PATH_PROGS(SNMPCONFIG, net-snmp-config) if test "X${SNMPCONFIG}" = "X"; then AC_MSG_RESULT(You need the net_snmp development package to continue.) ENABLE_SNMP="no" else AC_MSG_CHECKING(for special snmp libraries) SNMPLIB=`net-snmp-config --libs` AC_MSG_RESULT($SNMPLIB) fi elif test "x${ac_cv_header_ucd_snmp_snmp_h}" = "xyes"; then # UCD SNMP # ucd-snmp-config does not seem to exist, so just # rely on people having their LDFLAGS set to the path where AC_CHECK_LIB(snmp, init_snmp, SNMPLIB="-lsnmp") if test "X${SNMPLIB}" = "X"; then AC_CHECK_LIB(ucdsnmp, init_snmp, SNMPLIB="-lucdsnmp") fi if test "X${SNMPLIB}" = "X"; then ENABLE_SNMP="no" AC_MSG_RESULT("Could not find ucdsnmp libary." "Please make sure that libsnmp or libucdsnmp" "are in your library path. Or the path to LDFLAGS") fi else ENABLE_SNMP="no" fi AC_SUBST(SNMPLIB) AM_CONDITIONAL(USE_APC_SNMP, test "$ENABLE_SNMP" = "yes") # # We've had this new API for a very long time # AC_DEFINE(HAVE_NEW_HB_API, 1, [have new heartbeat api]) dnl dnl OpenIMPI checks dnl if test "x${enable_ipmilan}" = "x"; then enable_ipmilan="yes" fi if test "x${enable_ipmilan}" = "xyes" -o "x${enable_ipmilan}" = "xtry"; then AC_MSG_CHECKING(For libOpenIPMI version 1.4 or greater) AC_TRY_COMPILE([#include ], [ #if (OPENIPMI_VERSION_MAJOR == 1) && (OPENIPMI_VERSION_MINOR < 4) #error "Too Old" #endif ], AC_MSG_RESULT("yes"); enable_ipmilan="yes", AC_MSG_RESULT("no"); enable_ipmilan="no") else enable_ipmilan="no" fi AM_CONDITIONAL(IPMILAN_BUILD, test "X$enable_ipmilan" = "Xyes") dnl dnl On many systems libcrypto is needed when linking against libsnmp. dnl Check to see if it exists, and if so use it. dnl AC_CHECK_LIB(crypto, CRYPTO_free, CRYPTOLIB="-lcrypto",) AC_SUBST(CRYPTOLIB) dnl *************************************************************************** dnl Enable distro-style RPMs dnl *************************************************************************** AC_ARG_ENABLE([distro-rpm], [ --enable-distro-rpm Enable distro-style RPMs [default=no]], [], [enable_distro_rpm=no]) case $enable_distro_rpm in yes) DISTRO_STYLE_RPMS=1;; *) DISTRO_STYLE_RPMS=0;; esac AC_SUBST(DISTRO_STYLE_RPMS) dnl *************************************************************************** dnl TIPC communication module dnl *************************************************************************** AC_ARG_ENABLE([tipc], [ --enable-tipc Enable TIPC Communication module, [default=try]], [], [enable_tipc=try]) AC_ARG_WITH([tipc], [ --with-tipc-source TIPC source code directory], [], []) TIPC_DEV_ROOT=${with_tipc_source} tipc_headers_found=yes if test "x${TIPC_DEV_ROOT}" != "x"; then dnl checking tipc.h in specified directory TIPC_HEADER_DIR=${TIPC_DEV_ROOT}/include AC_CHECK_HEADER([${TIPC_HEADER_DIR}/net/tipc/tipc.h], [], \ [tipc_headers_found=no] ) TIPC_INCLUDE="-I${TIPC_HEADER_DIR}" else dnl checking tipc.h in standard include directory AC_CHECK_HEADERS(net/tipc/tipc.h, [], [tipc_headers_found=no]) fi AC_SUBST(TIPC_INCLUDE) AM_CONDITIONAL(BUILD_TIPC_MODULE, test "x${tipc_headers_found}" = "xyes" && test "x${enable_tipc}" != "xno") dnl *************************************************************************** dnl Thread safe configuration dnl *************************************************************************** AM_CONDITIONAL(ENABLE_THREAD_SAFE, test "x${enable_thread_safe}" = "xyes") dnl ************************************************************************ dnl Handy function for checking for typedefs or struct defs dnl ************************************************************************ check_for_type() { type="$1" headers="" shift for arg do headers="${headers}${arg} " done program="if ((${type} *) 0) return 0; if (sizeof(${type})) return 0; return 0;" have="HAVE_`echo "$type" | tr ' ' '_' | dd conv=ucase 2>/dev/null`" varhave="heartbeat_cv_$have" AC_CACHE_CHECK([for type $type ],$varhave,[ AC_TRY_COMPILE([$headers], [$program], eval $varhave=yes, eval $varhave=no , eval $varhave=cross) ]) if test x"`eval echo '${'$varhave'}'`" = xyes; then return 0 fi return 1 } check_for_type_member() { type="$1" member="$2" headers="" shift shift for arg do headers="${headers}${arg} " done program="${type} foo; if ((${type} *) 0) return 0; if (sizeof(${type})) return 0; if (sizeof(foo)) return 0; (void*)foo.${member}; return 0;" have="HAVE_`echo "$type" | tr ' ' '_' | dd conv=ucase 2>/dev/null`" varhave="heartbeat_cv_$have" AC_CACHE_CHECK([for type $type ],$varhave,[ AC_TRY_COMPILE([$headers], [$program], eval $varhave=yes, eval $varhave=no , eval $varhave=cross) ]) if test x"`eval echo '${'$varhave'}'`" = xyes; then return 0 fi return 1 } dnl ************************************************************************ dnl checks for typedefs dnl dnl if not known on this system, #define size_t unsigned AC_TYPE_SIZE_T dnl dnl Check poll.h for nfds_t (Linux Only), if not define it as an unsigned long int. dnl if check_for_type "nfds_t" "#include "; then AC_DEFINE(HAVE_NFDS_T,1,[Do we have nfds_t?]) fi dnl ************************************************************************ dnl checks for structures dnl # # Look for all the variants of local/UNIX socket credentials # # Include all of these headers that we can find... # headers="" for hdr in "sys/param.h" "sys/socket.h" "sys/ucred.h" do hdrvar=ac_cv_header_`echo $hdr | sed -e 's%\.%_%' -e 's%/%_%'` if test x"`eval echo '${'$hdrvar'}'`" = xyes; then headers="$headers #include <$hdr>" fi done if check_for_type_member "struct ucred" "cr_ref" "$headers"; then AC_DEFINE(HAVE_STRUCT_UCRED_DARWIN,1,[Do we have the Darwin version of struct ucred?]) fi if check_for_type "struct ucred" "$headers"; then AC_DEFINE(HAVE_STRUCT_UCRED,1,[Do we have struct ucred?]) fi if check_for_type "struct cmsgcred" "$headers" ; then AC_DEFINE(HAVE_STRUCT_CMSGCRED,1,[Do we have struct cmsgcred?]) fi if check_for_type "struct fcred" "$headers"; then AC_DEFINE(HAVE_STRUCT_FCRED,1,[Do we have struct fcred?]) fi if check_for_type "struct cred" "$headers"; then AC_DEFINE(HAVE_STRUCT_CRED,1,[Do we have struct cred?]) fi if check_for_type "struct sockcred" "$headers"; then AC_DEFINE(HAVE_STRUCT_SOCKCRED,1,[Do we have struct sockcred?]) fi dnl Check TERMIOS for components (e.g. c_line not present on Solaris) dnl AC_CACHE_CHECK([for c_line in termios],samba_cv_HAVE_TERMIOS_C_LINE,[ AC_TRY_COMPILE([#include #include ], [struct termios ti; ti.c_line = 'a';], samba_cv_HAVE_TERMIOS_C_LINE=yes,samba_cv_HAVE_TERMIOS_C_LINE=no,samba_cv_HAVE_TERMIOS_C_LINE=cross)]) if test x"$samba_cv_HAVE_TERMIOS_C_LINE" = x"yes"; then AC_DEFINE(HAVE_TERMIOS_C_LINE,1,[ ]) fi dnl Check sockaddr_in for components (e.g. sin_len not present on Solaris) dnl AC_CACHE_CHECK([for sin_len in sockaddr_in],samba_cv_HAVE_SOCKADDR_IN_SIN_LEN,[ AC_TRY_COMPILE([#include #include ], [struct sockaddr_in si; si.sin_len = 1;], samba_cv_HAVE_SOCKADDR_IN_SIN_LEN=yes,samba_cv_HAVE_SOCKADDR_IN_SIN_LEN=no,samba_cv_HAVE_SOCKADDR_IN_SIN_LEN=cross)]) if test x"$samba_cv_HAVE_SOCKADDR_IN_SIN_LEN" = x"yes"; then AC_DEFINE(HAVE_SOCKADDR_IN_SIN_LEN,1,[ ]) fi dnl Check msghdr for components (e.g. msg_control/msg_controlen not present on Solaris) dnl AC_CACHE_CHECK([for msg_control in msghdr],samba_cv_HAVE_MSG_CONTROL_MSGHDR,[ AC_TRY_COMPILE([#include #include ], [struct msghdr mh; mh.msg_control = (void *)0;], samba_cv_HAVE_MSG_CONTROL_MSGHDR=yes,samba_cv_HAVE_MSG_CONTROL_MSGHDR=no,samba_cv_HAVE_MSG_CONTROL_MSGHDR=cross)]) if test x"$samba_cv_HAVE_MSG_CONTROL_MSGHDR" = x"yes"; then MSGHDR_TYPE="msghdr" IPCSOCKET_C="ipcsocket.c" IPCSOCKET_LO="ipcsocket.lo" else MSGHDR_TYPE="nmsghdr" IPCSOCKET_C="" IPCSOCKET_LO="" fi dnl Check syslog.h for 'facilitynames' table dnl AC_CACHE_CHECK([for facilitynames in syslog.h],ac_cv_HAVE_SYSLOG_FACILITYNAMES,[ AC_TRY_COMPILE([ #define SYSLOG_NAMES #include #include ], [ void *fnames; fnames = facilitynames; ], ac_cv_HAVE_SYSLOG_FACILITYNAMES=yes,ac_cv_HAVE_SYSLOG_FACILITYNAMES=no,ac_cv_HAVE_SYSLOG_FACILITYNAMES=cross)]) if test x"$ac_cv_HAVE_SYSLOG_FACILITYNAMES" = x"yes"; then AC_DEFINE(HAVE_SYSLOG_FACILITYNAMES,1,[ ]) fi dnl 'reboot()' system call: one argument (e.g. Linux) or two (e.g. Solaris)? dnl AC_CACHE_CHECK([number of arguments in reboot system call], ac_cv_REBOOT_ARGS,[ AC_TRY_COMPILE( [#include ], [(void)reboot(0);], ac_cv_REBOOT_ARGS=1, [AC_TRY_COMPILE( [#include ], [(void)reboot(0,(void *)0);], ac_cv_REBOOT_ARGS=2, ac_cv_REBOOT_ARGS=0 )], ac_cv_REBOOT_ARGS=0 ) ] ) dnl Argument count of 0 suggests no known 'reboot()' call. if test "$ac_cv_REBOOT_ARGS" -ge "1"; then AC_DEFINE_UNQUOTED(REBOOT_ARGS,$ac_cv_REBOOT_ARGS,[number of arguments for reboot system call]) fi dnl dnl Check for ALIGN in /sys/param.h dnl AC_MSG_CHECKING("for ALIGN in sys/param.h") AC_EGREP_CPP(FoundAlign, [#include #ifdef ALIGN FoundAlign #endif ], [ ALIGN="ALIGN" AC_MSG_RESULT(Yes) ], AC_MSG_RESULT("No")) AC_MSG_CHECKING("for T_ALIGN in xti.h") AC_EGREP_CPP(FoundAlign, [#include #ifdef T_ALIGN FoundAlign #endif ], [ ALIGN="T_ALIGN" AC_MSG_RESULT(Yes) ], AC_MSG_RESULT(No)) AC_SUBST(IPCSOCKET_C) AC_SUBST(IPCSOCKET_LO) AC_SUBST(ALIGN) AC_SUBST(MSGHDR_TYPE) dnl ************************************************************************ dnl checks for compiler characteristics dnl dnl Warnings for C compilers. Note: generic, portable warnings only. dnl Things likely to be specific to a particular OS or module should be dnl carefully handled afterwards. AC_C_STRINGIZE dnl ********************************************************************** dnl time-related declarations etc. AC_STRUCT_TIMEZONE if check_for_type_member "struct tm" "tm_gmtoff" "#include "; then AC_DEFINE(HAVE_TM_GMTOFF,1,[Do we have structure member tm_gmtoff?]) fi dnl ********************************************************************** dnl Check the size of the integer types dnl So we can have integers of known sizes as needed dnl AC_CHECK_SIZEOF(char) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) AC_ARG_ENABLE([all], [ --enable-all Activate ALL features [default=no]]) AC_ARG_ENABLE([rpath], [ --enable-rpath Enable RPATH in libtool [default=yes]]) 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]], [], [enable_fatal_warnings=unknown]) AC_ARG_ENABLE([times-kludge], [ --enable-times-kludge enables a kludge to workaround a bug in glibc's times(2) call [default=yes]], [], [enable_times_kludge=unknown]) AC_ARG_ENABLE([no-long-long], [ --enable-no-long-long removes no long long warning for gcc [default=yes]], [], [enable_no_long_long=yes]) AC_ARG_ENABLE([traditional-warnings], [ --enable-traditional-warnings enable traditional warnings gcc (-Wtraditional) [default=no]]) AC_ARG_ENABLE([pretty], [ --enable-pretty Pretty-print compiler output unless there is an error [default=no]]) AC_ARG_ENABLE([quiet], [ --enable-quiet Supress make output unless there is an error [default=no]]) AC_ARG_ENABLE([ldirectord], [ --enable-ldirectord Enable Linix Director Daemon for use with LVS [default=yes]], [], [enable_ldirectord=yes]) AM_CONDITIONAL(LDIRECTORD_BUILD, test "X$enable_ldirectord" = "Xyes") AC_ARG_ENABLE([thread-safe], [ --enable-thread-safe Enable some client libraries to be thread safe. [default=no]]) AC_ARG_ENABLE([snmp], [ --enable-snmp Enable building of SNMP related functionality. [default=yes]]) AC_ARG_ENABLE([ipmilan], [ --enable-ipmilan enable IPMILan Stonith Plugin [default=yes]]) CC_WARNINGS="" enable_crm=no dnl - If requested, enable ALL subsystems. if test "${enable_all}" = "yes" ; then echo "Enabling all optional features." enable_ansi=yes; enable_fatal_warnings=yes; enable_lrm=yes; enable_quorumd=try; enable_ipmilan=try fi AC_ARG_ENABLE([bundled-ltdl], [ --enable-bundled-ltdl Configure, build and install the standalone ltdl library bundled with Heartbeat [default=no]]) LTDL_LIBS="" dnl Check before we enable -Wstrict-prototypes as it causes the test to fail AC_CHECK_LIB(ltdl, lt_dlopen, [LTDL_foo=1]) if test "x${enable_bundled_ltdl}" = "xyes"; then if test $ac_cv_lib_ltdl_lt_dlopen = yes; then AC_MSG_NOTICE([Disabling usage of installed ltdl]) fi ac_cv_lib_ltdl_lt_dlopen=no fi LIBLTDL_DIR="" if test $ac_cv_lib_ltdl_lt_dlopen != yes ; then AC_MSG_NOTICE([Installing local ltdl]) LIBLTDL_DIR=libltdl ( cd $srcdir ; $TAR -xvf libltdl.tar ) if test "$?" -ne 0; then AC_MSG_ERROR([$TAR of libltdl.tar in $srcdir failed]) fi AC_CONFIG_SUBDIRS(libltdl) else LIBS="$LIBS -lltdl" AC_MSG_NOTICE([Using installed ltdl]) INCLTDL="" LIBLTDL="" fi dnl libltdl additions AC_SUBST(INCLTDL) AC_SUBST(LIBLTDL) AC_SUBST(LIBLTDL_DIR) dnl ************ curses ********************** dnl A few OSes (e.g. Linux) deliver a default "ncurses" alongside "curses". dnl Many non-Linux deliver "curses"; sites may add "ncurses". dnl dnl However, the source-code recommendation for both is to #include "curses.h" dnl (i.e. "ncurses" still wants the include to be simple, no-'n', "curses.h"). dnl dnl Andrew Beekhof (author of heartbeat code that uses this functionality) dnl wishes "ncurses" to take precedence. So the following ordering has dnl been devised to implement this. dnl dnl Look first for the headers, then set the libraries accordingly. dnl (Normally autoconf suggests looking for libraries first.) dnl AC_CHECK_HEADERS(curses.h) AC_CHECK_HEADERS(curses/curses.h) AC_CHECK_HEADERS(ncurses.h) AC_CHECK_HEADERS(ncurses/ncurses.h) dnl Although n-library is preferred, only look for it if the n-header was found. CURSESLIBS='' if test "$ac_cv_header_ncurses_h" = "yes"; then AC_CHECK_LIB(ncurses, printw, [CURSESLIBS='-lncurses'; AC_DEFINE(HAVE_LIBNCURSES,1, have ncurses library)] ) fi if test "$ac_cv_header_ncurses_ncurses_h" = "yes"; then AC_CHECK_LIB(ncurses, printw, [CURSESLIBS='-lncurses'; AC_DEFINE(HAVE_LIBNCURSES,1, have ncurses library)] ) fi dnl Only look for non-n-library if there was no n-library. if test X"$CURSESLIBS" = X"" -a "$ac_cv_header_curses_h" = "yes"; then AC_CHECK_LIB(curses, printw, [CURSESLIBS='-lcurses'; AC_DEFINE(HAVE_LIBCURSES,1, have curses library)] ) fi dnl Only look for non-n-library if there was no n-library. if test X"$CURSESLIBS" = X"" -a "$ac_cv_header_curses_curses_h" = "yes"; then AC_CHECK_LIB(curses, printw, [CURSESLIBS='-lcurses'; AC_DEFINE(HAVE_LIBCURSES,1, have curses library)] ) fi AC_SUBST(CURSESLIBS) dnl ************ curses ********************** if test "$GCC" = yes; then dnl dnl We make sure warnings are carefully scrubbed out of the output if dnl you're running on some platforms. You can enable that behavior with dnl the option "fatal-warnings", by specifying --enable-fatal-warnings. dnl Or, you can disable it with --disable-fatal-warnings. dnl dnl Horms 10th August 2001 dnl Don't do this, it seems to cause configure in dnl the libltdl/ directory to die under Debian Woody dnl I'm suspecting it will be a problem on other systems too. dnl For this reason it now defaults to off. dnl AlanR 11 August 2001 dnl Show no mercy to broken OSes and other software. If you have broken dnl software, turn this feature off. dnl NO warnings WHATSOVER will be tolerated without good reason. dnl A distribution being broken isn't a good reason. dnl The cure for that is fix the distribution, not destroy the integrity dnl of the entire project by defaulting it to "off". dnl In my experience, there are ways of making individual warnings go dnl away. dnl The only way I know to keep them out is to make them an absolute dnl pain to deal with. Otherwise they're a pain to fix. dnl This policy is not an accident, nor was it chosen without significant dnl thought and experience. dnl cc_supports_flag() { AC_MSG_CHECKING(whether $CC supports "$@") Cfile=/tmp/foo${$} touch ${Cfile}.c $CC -c "$@" ${Cfile}.c -o ${Cfile}.o >/dev/null 2>&1 rc=$? rm -f ${Cfile}.c ${Cfile}.o case $rc in 0) AC_MSG_RESULT(yes);; *) AC_MSG_RESULT(no);; esac return $rc } dnl ************ printw ********************** if test X"$CURSESLIBS" != X"" && cc_supports_flag -Wcast-qual \ && cc_supports_flag -Werror; then dnl Check for printw() prototype compatibility dnl FIXME: We can check che prototype compatibility only if $CC supports dnl -Wcast-qual and -Werror AC_MSG_CHECKING(whether printw() requires argument of "const char *") ac_save_LIBS=$LIBS LIBS="$CURSESLIBS $LIBS" ac_save_CFLAGS=$CFLAGS CFLAGS="-Wcast-qual -Werror" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [ #if defined(HAVE_CURSES_H) # include #elif defined(HAVE_NCURSES_H) # include #endif ], [printw((const char *)"Test");] )], [ac_cv_compatible_printw=yes], [ac_cv_compatible_printw=no] ) LIBS=$ac_save_LIBS CFLAGS=$ac_save_CFLAGS AC_MSG_RESULT([$ac_cv_compatible_printw]) if test "$ac_cv_compatible_printw" = no; then AC_MSG_WARN([The printw() function of your ncurses or curses library is old, we will disable usage of the library. If you want to use this library anyway, please update to newer version of the library, ncurses 5.4 or later is recommended. You can get the library from http://www.gnu.org/software/ncurses/.]) AC_MSG_NOTICE([Disabling curses]) AC_DEFINE(HAVE_INCOMPATIBLE_PRINTW, 1, [Do we have incompatible printw() in curses library?]) dnl AC_DEFINE(HAVE_CURSES_H, 0) dnl AC_DEFINE(HAVE_NCURSES_H, 0) fi fi dnl ************ printw ********************** EXTRA_WARNINGS="" # We had to eliminate -Wnested-externs because of libtool changes WARNLIST="all missing-prototypes missing-declarations strict-prototypes declaration-after-statement pointer-arith write-strings cast-qual cast-align bad-function-cast inline missing-format-attribute format=2 format-security format-nonliteral no-long-long no-strict-aliasing" for j in $WARNLIST do if cc_supports_flag -W$j then case $j in "no-long-long") if test "${enable_no_long_long}" = "yes"; then EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j" fi;; *) EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j";; esac fi done dnl Add any system specific options here. if test "${enable_ansi}" = "unknown"; then enable_ansi=yes fi case "$host_os" in *linux*|*bsd*) if test "${enable_fatal_warnings}" = "unknown"; then enable_fatal_warnings=yes fi ;; *solaris*) ;; esac case "$host_os" in *linux*) if test "${enable_times_kludge}" = "unknown"; then enable_times_kludge=yes fi ;; esac if test "${enable_ansi}" = yes && cc_supports_flag -std=iso9899:199409 ; then echo "Enabling ANSI Compatibility on this platform" ANSI="-ansi -D_GNU_SOURCE -DANSI_ONLY" fi if test "${enable_fatal_warnings}" = yes && cc_supports_flag -Werror ; then echo "Enabling Fatal Warnings (-Werror) on this platform" FATAL_WARNINGS="-Werror" fi if test "$enable_traditional_warning" = yes && \ cc_supports_flag -Wtraditional; then echo "Enabling traditional warnings" EXTRA_WARNINGS="$EXTRA_WARNINGS -Wtraditional" fi CC_WARNINGS="$EXTRA_WARNINGS $FATAL_WARNINGS $ANSI" NON_FATAL_CC_WARNINGS="$EXTRA_WARNINGS" dnl Inline semantics are to be changed as of gcc v4.3. Since dnl 4.1.3 gcc issues a warning in case there are inlines. That's the dnl case with glib2. ver2num() { - awk -F. '{print $3+($2+($1*16))*16;}' + awk -F. '{print $3+($2+($1*100))*100;}' } - GCCVER=`gcc --version | head -1 | - awk '{for(i=1;i<=NF;i++) if($i~/)$/) {print $(i+1);exit}}' | + GCCVER=`gcc -v 2>&1 | awk 'END{print $3}' | ver2num` - firstver=`echo 4.1.3 | ver2num` - lastver=`echo 4.3.0 | ver2num` + firstver=40103 # 4.1.3 + lastver=40300 # 4.3.0 if test $GCCVER -ge $firstver -a $GCCVER -lt $lastver; then CFLAGS="$CFLAGS -fgnu89-inline" fi if test "x${ENABLE_SNMP}" = "xyes" && echo "${SNMPLIB}" | grep netsnmp >/dev/null; then inline_ver=`echo 4.3.0 | ver2num` if test $GCCVER -ge $inline_ver; then CFLAGS="$CFLAGS -DNETSNMP_BROKEN_INLINE" fi fi fi if test "${enable_times_kludge}" = no; then echo "Disabling times(2) kludge" AC_DEFINE(DISABLE_TIMES_KLUDGE, 1, [disable times(2) kludge]) fi AC_SUBST(DISABLE_TIMES_KLUDGE) AC_MSG_CHECKING(which init (rc) directory to use) INITDIR="" 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 AC_MSG_RESULT($INITDIR); break fi done AC_ARG_WITH(initdir, [ --with-initdir=DIR directory for init (rc) scripts [${INITDIR}]], [ if test x"$withval" = xprefix; then INITDIR=${prefix}; else INITDIR="$withval"; fi ]) if test "X$INITDIR" = X then FatalMissingThing "init directory" "Could not locate init directory" fi AC_SUBST(INITDIR) dnl Checking for init defaults directory dnl Linux: /etc/sysconfig dnl Solaris: /etc/default AC_MSG_CHECKING(which init defaults directory to use) INITDEFDIR="" for iddir in /etc/sysconfig /etc/default do if test -d $iddir then INITDEFDIR=$iddir AC_MSG_RESULT($INITDEFDIR); break fi done AC_ARG_WITH(iddir, [ --with-initdefdir=DIR directory for init defaults [${INITDEFDIR}]], [ if test x"$withval" = xprefix; then INITDEFDIR=${prefix}; else INITDEFDIR="$withval"; fi ]) if test "X$INITDEFDIR" = X then WarnMissingThing "init defaults directory" "Could not locate init defaults directory" fi AC_SUBST(INITDEFDIR) dnl ********************************************************************** dnl checks for group to install fifos as dnl dnl These checks aren't right. We need to locate the lowest dnl unused group id if haclient isn't in the /etc/group file dnl and no one has overridden group-id with a --with-group-id dnl option. dnl AC_ARG_WITH( group-name, [ --with-group-name=GROUP_NAME GROUP_NAME to run our programs as. [default=haclient] ], [ HA_APIGROUP="$withval" ], [ HA_APIGROUP="haclient" ], ) AC_SUBST(HA_APIGROUP) AC_DEFINE_UNQUOTED(HA_APIGROUP, "$HA_APIGROUP", group for our programs) if test -z "${GETENT}" -o ! -x "${GETENT}" then GETENT=getent getent() { grep "^${2}:" /etc/$1 } fi if test -z "${IP2UTIL}" -o ! -x "${IP2UTIL}" then IP2UTIL=/sbin/ip fi AC_ARG_WITH( group-id, [ --with-group-id=GROUP_ID GROUP_ID to run our programs as. [default=60] ], [ HA_APIGID="$withval" ], [ HA_APIGID=65 ], ) if getent group "$HA_APIGROUP" > /dev/null then HA_APIGID=`getent group "$HA_APIGROUP" | cut -d: -f3` fi AC_SUBST(HA_APIGID) AC_DEFINE_UNQUOTED(HA_APIGID, $HA_APIGID, id for api group) AC_ARG_WITH( ccmuser-name, [ --with-ccmuser-name=HA_CCMUSER_NAME HA_CCMUSER_NAME to run privileged non-root things as. [default=hacluster] ], [ HA_CCMUSER="$withval" ], [ HA_CCMUSER="hacluster" ], ) AC_SUBST(HA_CCMUSER) AC_DEFINE_UNQUOTED(HA_CCMUSER, "$HA_CCMUSER", user to run privileged non-root things as) AC_ARG_WITH( ccmuser-id, [ --with-ccmuser-id=HA_HA_CCMUSER_ID USER_ID to run privileged non-root things as. [default=17] ], [ HA_CCMUID="$withval" ], [ HA_CCMUID=17 ], ) if getent passwd "$HA_CCMUSER" >/dev/null then HA_CCMUID=`getent passwd "$HA_CCMUSER" | cut -d: -f3` fi AC_SUBST(HA_CCMUID) AC_DEFINE_UNQUOTED(HA_CCMUID, $HA_CCMUID, id for ccm user) # # Priority for starting via init startup scripts # AC_ARG_WITH( start-init-priority, [ --with-start-init-priority=number Init start priority. [default=75] ], [ HB_INITSTARTPRI="$withval" ], [ HB_INITSTARTPRI=75 ], ) AC_SUBST(HB_INITSTARTPRI) AC_DEFINE_UNQUOTED(HB_INITSTARTPRI,"$HB_INITSTARTPRI", init start priority) AC_ARG_WITH( logd-start-init-priority, [ --with-logd-start-init-priority=number ha_logd init start priority. [default=10] ], [ LOGD_INITSTARTPRI="$withval" ], [ LOGD_INITSTARTPRI=10 ], ) AC_SUBST(LOGD_INITSTARTPRI) AC_DEFINE_UNQUOTED(LOGD_INITSTARTPRI,"$LOGD_INITSTARTPRI", ha_logd init start priority) # # Priority for stopping via init shutdown scripts # AC_ARG_WITH( stop-init-priority, [ --with-stop-init-priority=number Init stop priority. [default=5] ], [ HB_INITSTOPPRI="$withval" ], [ HB_INITSTOPPRI=05 ], ) AC_SUBST(HB_INITSTOPPRI) AC_DEFINE_UNQUOTED(HB_INITSTOPPRI,"$HB_INITSTOPPRI", init stop priority) AC_ARG_WITH( logd-stop-init-priority, [ --with-logd-stop-init-priority=number Init stop priority. [default=75] ], [ LOGD_INITSTOPPRI="$withval" ], [ LOGD_INITSTOPPRI=75 ], ) AC_SUBST(LOGD_INITSTOPPRI) AC_DEFINE_UNQUOTED(LOGD_INITSTOPPRI,"$LOGD_INITSTOPPRI", init stop priority) # # Name of UCD-SNMP development package # AC_ARG_WITH( ucd-snmp-devel, [ --with-snmp-name=name Name of ucd snmp developemnt RPM. [default=ucd-snmp-devel] ], [ UCDSNMPDEVEL=$withval ], [ UCDSNMPDEVEL=ucd-snmp-devel ], ) if test "$ac_cv_header_ucd_snmp_snmp_h" = no; then UCDSNMPDEVEL="" fi AC_SUBST(UCDSNMPDEVEL) AC_DEFINE_UNQUOTED(UCDSNMPDEVEL, $UCDSNMPDEVEL, Name of UCD SNMP development package) dnl ************************************************************************ dnl checks for library functions to replace them dnl dnl alphasort: Only on BSD. dnl System-V systems may have it, but hidden and/or deprecated. dnl A replacement function is supplied for it. dnl dnl NoSuchFunctionName: dnl is a dummy function which no system supplies. It is here to make dnl the system compile semi-correctly on OpenBSD which doesn't know dnl how to create an empty archive dnl dnl scandir: Only on BSD. dnl System-V systems may have it, but hidden and/or deprecated. dnl A replacement function is supplied for it. dnl dnl setenv: is some bsdish function that should also be avoided (use dnl putenv instead) dnl On the other hand, putenv doesn't provide the right API for the dnl code and has memory leaks designed in (sigh...) Fortunately this dnl A replacement function is supplied for it. dnl dnl setproctitle: sets the process title to a given string dnl dnl strerror: returns a string that corresponds to an errno. dnl A replacement function is supplied for it. dnl dnl unsetenv: is some bsdish function that should also be avoided (No dnl replacement) dnl A replacement function is supplied for it. dnl dnl strnlen: is a gnu function similar to strlen, but safer. dnl We wrote a tolearably-fast replacement function for it. dnl dnl strndup: is a gnu function similar to strdup, but safer. dnl We wrote a tolearably-fast replacement function for it. dnl dnl daemon: is a GNU function. The daemon() function is for programs wishing to dnl detach themselves from the controlling terminal and run in the dnl background as system daemon dnl A replacement function is supplied for it. dnl dnl Check Only dnl dnl getopt: If this is valid, define HAVE_DECL_GETOPT to make the getopt.h header compile cleanly. dnl AC_REPLACE_FUNCS(alphasort inet_pton NoSuchFunctionName scandir setenv strerror unsetenv strnlen strndup daemon uuid_parse strlcpy strlcat) dnl AC_CHECK_FUNCS(alphasort inet_pton NoSuchFunctionName scandir setenv strerror unsetenv strnlen strndup daemon uuid_parse) AC_CHECK_FUNCS(getopt, AC_DEFINE(HAVE_DECL_GETOPT, 1, [Have getopt function])) AC_CHECK_FUNCS(fcntl) AC_CHECK_FUNCS(flock) AC_CHECK_FUNCS(inet_aton) AC_CHECK_FUNCS(mallinfo) AC_CHECK_FUNCS(mallopt) AC_CHECK_FUNCS(__default_morecore) AC_CHECK_FUNCS(seteuid) AC_CHECK_FUNCS(setegid) AC_CHECK_FUNCS(getpeereid) dnl ********************************************************************** dnl Check for various argv[] replacing functions on various OSs dnl dnl Borrowed from Proftpd dnl Proftpd is Licenced under the terms of the GNU General Public Licence dnl and is available from http://www.proftpd.org/ dnl AC_CHECK_FUNCS(setproctitle) AC_CHECK_HEADERS(libutil.h) AC_CHECK_LIB(util, setproctitle, [AC_DEFINE(HAVE_SETPROCTITLE,1,[ ]) ac_cv_func_setproctitle="yes" ; LIBS="$LIBS -lutil"]) if test "$ac_cv_func_setproctitle" = "yes"; then pf_argv_set="PF_ARGV_NONE" fi if test "$pf_argv_set" = ""; then AC_CHECK_HEADERS(sys/pstat.h) if test "$ac_cv_header_pstat_h" = "yes"; then AC_CHECK_FUNCS(pstat) if test "$ac_cv_func_pstat" = "yes"; then pf_argv_set="PF_ARGV_PSTAT" else pf_argv_set="PF_ARGV_WRITEABLE" fi fi if test "$pf_argv_set" = ""; then AC_EGREP_HEADER([#define.*PS_STRINGS.*],sys/exec.h, have_psstrings="yes",have_psstrings="no") if test "$have_psstrings" = "yes"; then pf_argv_set="PF_ARGV_PSSTRINGS" fi fi if test "$pf_argv_set" = ""; then AC_CACHE_CHECK(whether __progname and __progname_full are available, pf_cv_var_progname, AC_TRY_LINK([extern char *__progname, *__progname_full;], [__progname = "foo"; __progname_full = "foo bar";], pf_cv_var_progname="yes", pf_cv_var_progname="no")) if test "$pf_cv_var_progname" = "yes"; then AC_DEFINE(HAVE___PROGNAME,1,[ ]) fi AC_CACHE_CHECK(which argv replacement method to use, pf_cv_argv_type, AC_EGREP_CPP(yes,[ #if defined(__GNU_HURD__) yes #endif ],pf_cv_argv_type="new", pf_cv_argv_type="writeable")) if test "$pf_cv_argv_type" = "new"; then pf_argv_set="PF_ARGV_NEW" fi if test "$pf_argv_set" = ""; then pf_argv_set="PF_ARGV_WRITEABLE" fi fi fi AC_DEFINE_UNQUOTED(PF_ARGV_TYPE, $pf_argv_set, mechanism to pretty-print ps output: setproctitle-equivalent) dnl End of tests borrowed from Proftpd dnl check if header file and lib are there for hbaping hbaping_build="yes" AC_CHECK_HEADERS(time.h hbaapi.h, , [hbaping_build="no"],[[#if HAVE_TIME_H #include #endif]]) AC_CHECK_LIB(HBAAPI, HBA_SendScsiInquiry, , [hbaping_build="no"]) AM_CONDITIONAL(HBAAPI_BUILD, test "x${hbaping_build}" = "xyes") dnl check if header file and lib are there for zlib zlib_installed="yes" AC_CHECK_HEADERS(zlib.h, , [zlib_installed="no"],) AC_CHECK_LIB(z, compress , , [zlib_installed="no"]) AM_CONDITIONAL(BUILD_ZLIB_COMPRESS_MODULE, test "x${zlib_installed}" = "xyes") if test "x${zlib_installed}" = "xno"; then FatalMissingThing "zlib" \ "The zlib library is missing" fi dnl check if header file and lib are there for zlib bz2_installed="yes" AC_CHECK_HEADERS(bzlib.h, , [bz2_installed="no"],) AC_CHECK_LIB(bz2, BZ2_bzBuffToBuffCompress , , [bz2_installed="no"]) AM_CONDITIONAL(BUILD_BZ2_COMPRESS_MODULE, test "x${bz2_installed}" = "xyes") dnl check if header file and lib are there for openais module openais_installed="yes" AC_CHECK_HEADERS(evs.h, , [openais_installed="no"],) AC_CHECK_LIB(evs, evs_initialize , , [openais_installed="no"]) AM_CONDITIONAL(BUILD_OPENAIS_MODULE, test "x${openais_installed}" = "xyes") AC_MSG_CHECKING(if clock_t is long enough) if test $ac_cv_sizeof_long -ge 8; then AC_MSG_RESULT(yes) AC_DEFINE(CLOCK_T_IS_LONG_ENOUGH, 1, [Set if CLOCK_T is adequate by itself for the "indefinite future" (>= 100 years)]) else AC_MSG_RESULT(no) fi dnl check if there are getpid() inconsistency dnl Note: reduce LIBS; in particular, ltdl can cause confusion. dnl Possibly better: move 'LIBS="$LIBS -lltdl"' from above to beyond here. dnl AC_MSG_CHECKING(for getpid() consistency in multi-process/threads program) ac_save_LIBS=$LIBS LIBS="-lpthread" AC_TRY_RUN(`cat $srcdir/config/pidtest.c`, AC_MSG_RESULT(ok), [AC_MSG_RESULT(fail); AC_DEFINE(GETPID_INCONSISTENT, 1 , [pid inconsistent])],) LIBS=$ac_save_LIBS dnl check byte order AC_MSG_CHECKING(for byteorder) AC_TRY_RUN(`cat $srcdir/config/byteorder_test.c`, [AC_MSG_RESULT(little-endian); AC_DEFINE(CONFIG_LITTLE_ENDIAN, 1, [little-endian])], [AC_MSG_RESULT(big-endian); AC_DEFINE(CONFIG_BIG_ENDIAN, 1, [big-endian])],) dnl dnl Lex and yacc can't be trusted to produce code that won't produce dnl warnings dnl NON_FATAL_CFLAGS="$CFLAGS $NON_FATAL_CC_WARNINGS" 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 CFLAGS="$CFLAGS $CC_WARNINGS" dnl NOTE: dnl This check should only be done after CFLAGS is set. Otherwise dnl linux box will complain because of a warning of the undefined dnl function sigignore(). dnl dnl In theory, all function checks should be done after the CFLAGS is dnl set since we are enforcing the -Werror. But this would have a big dnl impact on the whole source tree so I am only moving the dnl sigignore for now. A bit of a hack. dnl dnl sigignore: Only on Solaris. dnl it is a solaris replacement for signal(s,SIG_IGN). dnl AC_CHECK_FUNCS(sigignore) 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. This causes a problem when configure dnl is run in the libltdl directory. Horms 16th July 2002 dnl if export | fgrep " CFLAGS=" > /dev/null; then export -n CFLAGS || true # We don't want to bomb out if this fails fi if test "$GCC" = yes; then CFLAGS="$CFLAGS -ggdb3" if cc_supports_flag -funsigned-char then CFLAGS="$CFLAGS -funsigned-char" fi else CFLAGS="$CFLAGS -g" fi dnl AC_SUBST(CC_WARNINGS) dnl ************************************************************************ dnl pre AC_OUTPUT stuff dnl dnl th aux dir (for holding config & autogenerated stuff) dnl AC_SUBST(ac_aux_dir) AC_SUBST(LIBADD_DL) dnl extra flags for dynamic linking libraries AC_SUBST(LIBADD_INTL) dnl extra flags for GNU gettext stuff... AC_SUBST(LOCALE) HA_HBCONF_DIR=$sysconfdir/ha.d AC_SUBST(HA_HBCONF_DIR) AC_DEFINE_UNQUOTED(HA_HBCONF_DIR,"$HA_HBCONF_DIR", Heartbeat configuration directory) HA_RC_DIR=$HA_HBCONF_DIR/rc.d AC_SUBST(HA_RC_DIR) AC_DEFINE_UNQUOTED(HA_RC_DIR,"$HA_RC_DIR", heartbeat v1 script directory) enable_crm=no CRM_DIR="" CRM_ENABLED=0 AC_SUBST(CRM_DIR) AC_SUBST(CRM_ENABLED) AM_CONDITIONAL(CRM_BUILD, test "x${enable_crm}" = "xyes") AC_MSG_NOTICE([whether to enable the Cluster Resource Manager... ${enable_crm}]) dnl lrm configuration AC_ARG_ENABLE([lrm], [ --enable-lrm Compile the new Local Resource Manager. [default=yes]], [], [enable_lrm=yes]) LRM_ENABLED=0 if test "x${enable_crm}" = "xyes"; then if test "x${enable_lrm}" = "xno"; then AC_MSG_WARN([crm enabled, overriding --enable-lrm=no with --enable-lrm=yes]) elif test -z "${enable_lrm}"; then AC_MSG_WARN([crm enabled, defaulting to --enable-lrm=yes]) fi enable_lrm="yes" elif test -z "${enable_lrm}"; then enable_lrm="no" fi if test "x${enable_lrm}" = "xyes"; then LRM_ENABLED=1 fi if test -h /proc/$$/exe then AC_MSG_NOTICE("/proc/{pid}/exe link is supported") AC_DEFINE_UNQUOTED(HAVE_PROC_PID, 1, Define to 1 if /proc/{pid} is supported.) fi AC_SUBST(LRM_ENABLED) AM_CONDITIONAL(LRM_BUILD, test "x${enable_lrm}" = "xyes") AC_MSG_NOTICE([whether to enable the Local Resource Manager... ${enable_lrm}]) dnl ************************************************************************ dnl management and quorum daemons. AC_CHECK_HEADERS(gnutls/gnutls.h) AC_CHECK_HEADERS(security/pam_appl.h pam/pam_appl.h) dnl ************************************************************************ dnl * Check for (debian style?) $sysconfdir/pam.d/common-{account,auth} AC_CHECK_FILE($sysconfdir/pam.d/common-account) AC_CHECK_FILE($sysconfdir/pam.d/common-auth) AM_CONDITIONAL(USE_PAM_COMMON, test -f $sysconfdir/pam.d/common-account -a \ -f /etc/pam.d/common-auth) dnl GNUTLS library: Attempt to determine by 'libgnutls-config' program. dnl If no 'libgnutls-config', try traditional autoconf means. AC_PATH_PROGS(LIBGNUTLS_CONFIG, libgnutls-config) if test -n "$LIBGNUTLS_CONFIG"; then AC_MSG_CHECKING(for gnutls header flags) GNUTLSHEAD="`$LIBGNUTLS_CONFIG --cflags`"; AC_MSG_RESULT($GNUTLSHEAD) AC_MSG_CHECKING(for gnutls library flags) GNUTLSLIBS="`$LIBGNUTLS_CONFIG --libs`"; AC_MSG_RESULT($GNUTLSLIBS) else AC_CHECK_LIB(gnutls, gnutls_init) fi AC_SUBST(GNUTLSHEAD) AC_SUBST(GNUTLSLIBS) if test "x${enable_openhpi}" != "xno"; then RPM_ENABLE_OPENHPI=1 else RPM_ENABLE_OPENHPI=0 fi AC_SUBST(RPM_ENABLE_OPENHPI) dnl quorum server configuration AC_ARG_ENABLE([quorumd], [ --enable-quorumd Compile the quorum server. [default=no]], [], [enable_quorumd=no]) if test "x${enable_quorumd}" != "xno"; then if test "x${enable_quorumd}" = "xtry"; then MISSING_FN="WarnMissingThing" else MISSING_FN="FatalMissingThing" fi enable_quorumd="yes" QUORUMD_ENABLED=1 if test "$ac_cv_header_gnutls_gnutls_h" = "no"; then $MISSING_FN "gnutls/gnutls.h" \ "The quorum server module needs GNU/TLS header files" enable_quorumd="no" QUORUMD_ENABLED=0 fi fi AC_SUBST(QUORUMD_ENABLED) AM_CONDITIONAL(QUORUMD_BUILD, test "x${enable_quorumd}" != "xno") AC_MSG_NOTICE([whether to enable the quorum server... ${enable_quorumd}]) dnl ********************************************** dnl drbd peer outdate plugin configuration dnl ********************************************** case "$host_os" in *linux*) AC_ARG_ENABLE([dopd], [ --enable-dopd Compile the Drbd Outdate Peer Daemon and tools. [default=yes]], [], [enable_dopd=yes]) ;; *) enable_dopd=no ;; esac AM_CONDITIONAL(BUILD_DRBD_OUTDATE_PEER, test "x${enable_dopd}" != "xno") hb_libdir="${libdir}/${HB_PKG}" AC_SUBST(hb_libdir) HA_PLUGIN_DIR="${hb_libdir}/plugins" AC_SUBST(HA_PLUGIN_DIR) AC_DEFINE_UNQUOTED(HA_PLUGIN_DIR,"$HA_PLUGIN_DIR", PILS plugin dir) LRM_PLUGIN_DIR="${hb_libdir}/plugins/RAExec" AC_SUBST(LRM_PLUGIN_DIR) AC_DEFINE_UNQUOTED(LRM_PLUGIN_DIR,"$LRM_PLUGIN_DIR", LRM plugin dir) HB_RA_DIR="${sysconfdir}/ha.d/resource.d/" AC_SUBST(HB_RA_DIR) AC_DEFINE_UNQUOTED(HB_RA_DIR,"$HB_RA_DIR", Location for v1 Heartbeat v1 RAs) dnl ************ OCF (Open Cluster Framework) ********************** dnl Should be consistent with the OCF standard fixed pathname /usr/lib/ocf dnl Changing it from this value violates the OCF standard. dnl This is why it is not affected by the PREFIX setting. dnl We do not recommend changing it. dnl OCF_ROOT_DIR="/usr/lib/ocf" AC_ARG_WITH(ocf-root, [ --with-ocf-root=DIR directory for OCF scripts [${OCF_ROOT_DIR}]], [ if test x"$withval" = xprefix; then OCF_ROOT_DIR=${prefix}; else OCF_ROOT_DIR="$withval"; fi ]) if test "X$OCF_ROOT_DIR" = X; then FatalMissingThing "OCF directory" "Could not locate OCF directory" fi AC_SUBST(OCF_ROOT_DIR) AC_DEFINE_UNQUOTED(OCF_ROOT_DIR,"$OCF_ROOT_DIR", OCF root directory - specified by the OCF standard) OCF_RA_DIR="${OCF_ROOT_DIR}/resource.d/" AC_SUBST(OCF_RA_DIR) AC_DEFINE_UNQUOTED(OCF_RA_DIR,"$OCF_RA_DIR", Location for OCF RAs) LSB_RA_DIR="${INITDIR}" AC_SUBST(LSB_RA_DIR) AC_DEFINE_UNQUOTED(LSB_RA_DIR,"$LSB_RA_DIR", Location for LSB RAs) STONITH_RA_DIR="${hb_libdir}/stonith.d/" AC_SUBST(STONITH_RA_DIR) AC_DEFINE_UNQUOTED(STONITH_RA_DIR,"$STONITH_RA_DIR", Location for STONITH RAs) AC_ARG_ENABLE([valgrind], [ --enable-valgrind "Run selected heartbeat components using Valgrind." [default=no]], [], [enable_valgrind=no]) AC_ARG_WITH(valgrind-log, [ --with-valgrind-log=options Logging options to pass to valgrind], [ VALGRIND_LOG="$withval" ], []) AC_ARG_WITH(valgrind-suppress, [ --with-valgrind-suppress=file Name of a suppression file to pass to Valgrind [default=/dev/null]], [ VALGRIND_SUPP="$withval" ], [ VALGRIND_SUPP="/dev/null" ]) if test "x" = "x$VALGRIND_LOG"; then VALGRIND_LOG="--log-socket=127.0.0.1:1234" AC_MSG_NOTICE(Set default Valgrind options to: $VALGRIND_OPTS) AC_MSG_NOTICE(Remember to start a receiver on localhost:1234) fi AC_PATH_PROG(VALGRIND_BIN, valgrind) AC_DEFINE_UNQUOTED(VALGRIND_BIN, "$VALGRIND_BIN", Valgrind command) AC_DEFINE_UNQUOTED(VALGRIND_LOG, "$VALGRIND_LOG", Valgrind logging options) AC_DEFINE_UNQUOTED(VALGRIND_SUPP, "$VALGRIND_SUPP", Name of a suppression file to pass to Valgrind) dnl ********************************************************************** dnl 'AWK' had been determined via 'aclocal.m4' as the simple name, using dnl the current PATH (i.e. in the context of 'configure'). dnl dnl Things within heartbeat will use 'AWK', but from a different context, dnl so we should determine, and substitute, the full path. dnl dnl Note: Even that may have a flaw, e.g. if 'configure' finds (say) 'gawk', dnl which we here convert to '/path/to/gawk', but the run-time machine lacks it. dnl We won't worry about that for now. dnl (David Lee; March 2007) AC_PATH_PROGS([AWK], $AWK) dnl ********************************************************************** dnl Enable optional, experimental directories here... dnl XPERIMENTALDIRS="" AC_SUBST(XPERIMENTALDIRS) CheckMissingThings dnl Options for cleaning up the compiler output dnl In 'buildtools' build a front-end 'ccdv' to the C compiler. PRETTY_CC="" REAL_CC="${CC}" QUIET_LIBTOOL_OPTS="" QUIET_MAKE_OPTS="" if test x"${enable_pretty}" = "xyes"; then enable_quiet="yes" echo "install_sh: ${install_sh}" PRETTY_CC="`pwd`/buildtools/ccdv" CC="\$(PRETTY_CC) ${CC}" fi if test "x${enable_quiet}" = "xyes"; then QUIET_LIBTOOL_OPTS="--quiet" QUIET_MAKE_OPTS="--quiet" fi AC_MSG_RESULT(Supressing make details: ${enable_quiet}) AC_MSG_RESULT(Pretty printing of compiler output: ${enable_pretty}) dnl Put the above variables to use LIBTOOL="${LIBTOOL} --tag=CC \$(QUIET_LIBTOOL_OPTS)" MAKE="${MAKE} \$(QUIET_MAKE_OPTS)" AC_SUBST(CC) AC_SUBST(MAKE) AC_SUBST(LIBTOOL) AC_SUBST(PRETTY_CC) AC_SUBST(REAL_CC) AC_SUBST(QUIET_MAKE_OPTS) AC_SUBST(QUIET_LIBTOOL_OPTS) dnl *** "echo" adjustments (begin) *** dnl Some run-time scripts require options to "echo". dnl This configure is already determining and using "ac_n" and "ac_c" dnl for internal use, so make available externally. dnl (Not sure how "future proof" this is, but it at least seems clean.) dnl dnl This must be close to the end of "configure.in" otherwise it interferes dnl with output from the AC_MSG_*() macros. ECHO_N="$ac_n" ECHO_C="$ac_c" case $ac_n in -n) ECHO_E="-e";; *) ECHO_E="";; esac ECHO_CMD="echo" if test -x /usr/linux/bin/echo then # This is for AIX. I'm not sure it's necessary... ECHO_CMD="/usr/linux/bin/echo" ECHO_N="-n" ECHO_E="-e" fi AC_SUBST(ECHO_N) AC_SUBST(ECHO_C) AC_SUBST(ECHO_E) AC_SUBST(ECHO_CMD) dnl *** "echo" adjustments (end) *** dnl The Makefiles and shell scripts we output AC_CONFIG_FILES(Makefile \ README \ logd/Makefile \ buildtools/Makefile \ config/Makefile \ cts/Makefile \ cts/CM_fs.py \ cts/CM_hb.py \ cts/CTS.py \ cts/CTSaudits.py \ cts/CTSlab.py \ cts/CTStests.py \ cts/CM_LinuxHAv2.py \ cts/CTSproxy.py \ cts/extracttests.py \ cts/getpeinputs.sh \ cts/OCFIPraTest.py \ cts/CIB.py \ cts/LSBDummy \ debian/Makefile \ doc/Makefile \ doc/startstop \ contrib/Makefile \ contrib/ipfail/Makefile \ contrib/mlock/Makefile \ contrib/drbd-outdate-peer/Makefile \ include/Makefile \ include/clplumbing/Makefile \ include/lrm/Makefile \ include/ocf/Makefile \ include/pils/Makefile \ include/pils/plugin.h \ include/saf/Makefile \ include/stonith/Makefile \ replace/Makefile \ lib/Makefile \ lib/apphb/Makefile \ lib/clplumbing/Makefile \ lib/hbclient/Makefile \ lib/lrm/Makefile \ lib/pils/Makefile \ lib/plugins/Makefile \ lib/plugins/InterfaceMgr/Makefile \ lib/plugins/HBauth/Makefile \ lib/plugins/HBcomm/Makefile \ lib/plugins/lrm/Makefile \ lib/plugins/stonith/Makefile \ lib/plugins/stonith/ribcl.py \ lib/plugins/stonith/external/Makefile \ lib/plugins/stonith/external/ibmrsa \ lib/plugins/stonith/external/riloe \ lib/plugins/stonith/external/ssh \ lib/plugins/stonith/external/hmchttp \ lib/plugins/stonith/external/kdumpcheck \ lib/plugins/stonith/external/xen0-ha \ lib/plugins/stonith/external/drac5 \ lib/plugins/HBcompress/Makefile \ lib/plugins/quorum/Makefile \ lib/plugins/quorumd/Makefile \ lib/plugins/tiebreaker/Makefile \ lib/stonith/Makefile \ lrm/Makefile \ lrm/lrmd/Makefile \ lrm/admin/Makefile \ lrm/test/regression.sh \ lrm/test/LRMBasicSanityCheck \ lrm/test/Makefile \ lrm/test/lrmregtest \ lrm/test/lrmregtest-lsb \ lrm/test/lrmregtest-heartbeat \ lrm/test/testcases/Makefile \ heartbeat/Makefile \ heartbeat/shellfuncs \ heartbeat/rc.d/Makefile \ heartbeat/rc.d/ask_resources \ heartbeat/rc.d/hb_takeover \ heartbeat/init.d/Makefile \ heartbeat/init.d/heartbeat \ heartbeat/init.d/logd \ heartbeat/lib/Makefile \ heartbeat/lib/BasicSanityCheck \ heartbeat/lib/ha_config \ heartbeat/lib/ha_propagate \ heartbeat/lib/hb_standby \ heartbeat/lib/mach_down \ heartbeat/lib/req_resource \ heartbeat/lib/ResourceManager \ heartbeat/lib/TestHeartbeatComm \ heartbeat/lib/hb_takeover \ heartbeat/lib/hb_addnode \ heartbeat/lib/hb_delnode \ heartbeat/lib/hb_setweight \ heartbeat/lib/hb_setsite \ heartbeat/logrotate.d/Makefile \ ldirectord/Makefile \ ldirectord/ldirectord \ ldirectord/init.d/Makefile \ ldirectord/init.d/ldirectord \ ldirectord/init.d/ldirectord.debian \ ldirectord/init.d/ldirectord.debian.default \ ldirectord/logrotate.d/Makefile \ ldirectord/OCF/Makefile \ ldirectord/OCF/ldirectord \ membership/Makefile \ membership/ccm/Makefile \ membership/quorumd/Makefile \ pkg/Makefile \ pkg/InfoFiles/pkginfo \ pkg/InfoFiles/preinstall \ pkg/InfoFiles/postinstall \ port/Makefile \ port/portMakefile \ port/heartbeat/pkg-deinstall \ port/heartbeat/pkg-descr \ port/heartbeat/pkg-install \ port/heartbeat/pkg-plist \ telecom/Makefile \ telecom/apphbd/Makefile \ tools/Makefile \ tools/hb_report \ tools/ocf-tester \ resources/Makefile \ resources/OCF/Makefile \ resources/OCF/.ocf-binaries \ resources/OCF/.ocf-directories \ resources/OCF/.ocf-shellfuncs \ resources/OCF/ocf-returncodes \ resources/OCF/ocf-shellfuncs \ resources/heartbeat/Makefile \ resources/heartbeat/apache \ resources/heartbeat/AudibleAlarm \ resources/heartbeat/Delay \ resources/heartbeat/db2 \ resources/heartbeat/Filesystem \ resources/heartbeat/hto-mapfuncs \ resources/heartbeat/ICP \ resources/heartbeat/ids \ resources/heartbeat/IPaddr \ resources/heartbeat/IPaddr2 \ resources/heartbeat/IPsrcaddr \ resources/heartbeat/IPv6addr \ resources/heartbeat/LinuxSCSI \ resources/heartbeat/LVM \ resources/heartbeat/LVSSyncDaemonSwap \ resources/heartbeat/MailTo \ resources/heartbeat/OCF \ resources/heartbeat/portblock \ resources/heartbeat/Raid1 \ resources/heartbeat/ServeRAID \ resources/heartbeat/SendArp \ resources/heartbeat/WAS \ resources/heartbeat/WinPopup \ resources/heartbeat/Xinetd \ ) dnl Now process the entire list of files added by previous dnl calls to AC_CONFIG_FILES() AC_OUTPUT() dnl subpackages configuration - perhaps configure it properly some other time dnl when it has been discussed at linux-ha-dev dnl AC_CONFIG_SUBDIRS(stonith heartbeat) dnl ***************** dnl Configure summary dnl ***************** eval my_datadir="`eval echo ${datadir}`" eval my_includedir="`eval echo ${includedir}`" eval my_initdir="${INITDIR}" eval my_libdir="`eval echo ${libdir}`" eval my_localstatedir="`eval echo ${localstatedir}`" eval my_mandir="`eval echo ${mandir}`" eval my_sbindir="`eval echo ${sbindir}`" eval my_sysconfdir="`eval echo ${sysconfdir}`" eval my_initdefdir="`eval echo ${INITDEFDIR}`" AC_MSG_RESULT([]) AC_MSG_RESULT([$PACKAGE configuration:]) AC_MSG_RESULT([ Version = "$VERSION"]) AC_MSG_RESULT([ Executables = "$my_sbindir"]) AC_MSG_RESULT([ Man pages = "$my_mandir"]) AC_MSG_RESULT([ Libraries = "$my_libdir"]) AC_MSG_RESULT([ Header files = "$my_includedir"]) AC_MSG_RESULT([ Arch-independent files = "$my_datadir"]) AC_MSG_RESULT([ State information = "$my_localstatedir"]) AC_MSG_RESULT([ System configuration = "$my_sysconfdir"]) AC_MSG_RESULT([ Init (rc) scripts = "$my_initdir"]) AC_MSG_RESULT([ Init (rc) defaults = "$my_initdefdir"]) AC_MSG_RESULT([ Use system LTDL = "${ac_cv_lib_ltdl_lt_dlopen}"]) AC_MSG_RESULT([ HA group name = "${HA_APIGROUP}"]) AC_MSG_RESULT([ HA group id = "${HA_APIGID}"]) AC_MSG_RESULT([ HA user name = "${HA_CCMUSER}"]) AC_MSG_RESULT([ HA user user id = "${HA_CCMUID}"]) AC_MSG_RESULT([ SNMP libraries = "${SNMPLIB}"]) AC_MSG_RESULT([ Build CRM = "${enable_crm}"]) AC_MSG_RESULT([ Build LRM = "${enable_lrm}"]) AC_MSG_RESULT([ Build Ldirectord = "${enable_ldirectord}"]) AC_MSG_RESULT([ Build IPMILan Plugin = "${enable_ipmilan}"]) AC_MSG_RESULT([ Build dopd plugin = "${enable_dopd}"]) AC_MSG_RESULT([ Enable times kludge = "${enable_times_kludge}"]) AC_SUBST(DISABLE_TIMES_KLUDGE) AC_MSG_RESULT([ CC_WARNINGS = "${CC_WARNINGS}"]) AC_MSG_RESULT([ Mangled CFLAGS = "${CFLAGS}"]) AC_MSG_RESULT([ Libraries = "${LIBS}"]) AC_MSG_RESULT([ RPATH enabled = "${enable_rpath}"]) AC_MSG_RESULT([ Distro-style RPMs = "${enable_distro_rpm}"]) AC_MSG_RESULT([ ]) AC_MSG_RESULT([Note: If you use the 'make install' method for installation you]) AC_MSG_RESULT([also need to adjust '/etc/passwd' and '/etc/group' manually.]) AC_MSG_RESULT([ ]) diff --git a/heartbeat/AoEtarget b/heartbeat/AoEtarget new file mode 100644 index 000000000..7cddea639 --- /dev/null +++ b/heartbeat/AoEtarget @@ -0,0 +1,246 @@ +#!/bin/bash +# +# +# AoEtarget OCF RA. +# Manages an ATA-over-Ethernet (AoE) target utilizing the vblade utility. +# +# Copyright (c) 2009 LINBIT HA-Solutions GmbH, Florian Haas +# 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_ROOT}/resource.d/heartbeat/.ocf-shellfuncs +LC_ALL="C" +LANG="C" + +# 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. + + ATA-over-Ethernet (AoE) target agent + + + +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_RUNNING +} + +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/AudibleAlarm b/heartbeat/AudibleAlarm index 2a0484f10..83310ed36 100644 --- a/heartbeat/AudibleAlarm +++ b/heartbeat/AudibleAlarm @@ -1,186 +1,186 @@ #!/bin/sh # # Startup script for the Audible Alarm # # author: Kirk Lawson # Horms # # description: sets an audible alarm running by beeping at a set interval # processname: alarm # config: /etc/AudibleAlarm/AudibleAlarm.conf - not yet implemented # # OCF parameters are as below: # OCF_RESKEY_nodelist # # License: GNU General Public License (GPL) ####################################################################### # Source function library. . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### PIDFILE=${HA_VARRUN}/heartbeat-bell #For testing #PIDFILE=/tmp/heartbeat-bell # What host are we running on? us=`uname -n` usage() { echo "Usage: $0 {start|stop|restart|status|monitor|meta-data|validate-all}" echo " The node list is an optional space delimited" echo " list of hosts that should never sound the alarm." } meta_data() { cat < 1.0 Resource script for AudibleAlarm. It sets an audible alarm running by beeping at a set interval. AudibleAlarm resource agent The node list that should never sound the alarm. Node list - - + + END } audiblealarm_start () { ocf_log info "$0: Starting" if [ -f $PIDFILE ]; then PID=`head -n 1 $PIDFILE` if [ -n "$PID" ]; then ocf_log info "$0: Appears to already be running, killing [$PID]" kill $PID > /dev/null fi fi # Use () to create a subshell to make the redirection be synchronized. ( while [ 1 ]; do sleep 1 #Sleep first, incase we bail out echo -ne "\a" > /dev/console # Uncomment this line to cause floppy drive light # to flash (requires fdutils package). # /usr/bin/floppycontrol --pollstate > /dev/null # # To avoid issues when called by lrmd, redirect stdout->stderr. done & if echo $! > $PIDFILE; then : else ocf_log info "$0: Could not write to pid file \"$PIDFILE\", bailing" kill $! return $OCF_ERR_GENERIC fi) >&2 return $? } audiblealarm_stop () { ocf_log info "$0: Shutting down" if [ -f $PIDFILE ]; then PID=`head -n 1 $PIDFILE` # ocf_log info "$0: Appears to already be running, killing [$PID]" # commented by Phost, since the confusion in the log. if [ -n "$PID" ]; then # Donnot remove PIDFILE in case the `kill` fails. kill $PID > /dev/null && rm -f $PIDFILE fi fi return $? } audiblealarm_restart () { audiblealarm_stop audiblealarm_start return $? } audiblealarm_status () { if [ -f $PIDFILE ]; then PID=`head -n 1 $PIDFILE` if [ -n "$PID" ]; then echo running return $OCF_SUCCESS fi fi echo stopped return $OCF_NOT_RUNNING } audiblealarm_validate_all () { # Is there anything to check? echo "Validate OK" return $OCF_SUCCESS } if [ $# -ne 1 ]; then usage exit $OCF_ERR_ARGS fi case "$1" in meta-data) meta_data exit $OCF_SUCCESS ;; start) for arg in $OCF_RESKEY_nodelist do if [ "$us" = "$arg" ]; then # We should not start because we are on a host # listed in our argument list. exit $OCF_SUCCESS fi done audiblealarm_start ;; stop) audiblealarm_stop ;; restart) audiblealarm_restart ;; status|monitor) audiblealarm_status ;; validate-all) audiblealarm_validate_all ;; usage) usage exit $OCF_SUCCESS ;; *) usage exit $OCF_ERR_ARGS ;; esac exit $? diff --git a/heartbeat/ClusterMon b/heartbeat/ClusterMon index 7814a19b0..b76d63ac4 100644 --- a/heartbeat/ClusterMon +++ b/heartbeat/ClusterMon @@ -1,267 +1,267 @@ #!/bin/sh # # # ClusterMon OCF RA. Does nothing but wait a few seconds, can be # configured to fail occassionally. # # Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Brée # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Further, this software is distributed without any warranty that it is # free of the rightful claim of any third person regarding infringement # or the like. Any license provided herein, whether implied or # otherwise, applies only to this software file. Patent licenses, if # any, provided herein do not apply to combinations of this program with # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # # OCF instance parameters: # OCF_RESKEY_user # OCF_RESKEY_pidfile # OCF_RESKEY_update # OCF_RESKEY_extra_options # OCF_RESKEY_htmlfile ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### meta_data() { cat < 1.0 This is a ClusterMon Resource Agent. It outputs current cluster status to the html. ClusterMon resource agent The user we want to run crm_mon as The user we want to run crm_mon as How frequently should we update the cluster status Update interval Additional options to pass to crm_mon. Eg. -n -r Extra options PID file location to ensure only one instance is running PID file Location to write HTML output to. HTML output - + END } ####################################################################### ClusterMon_usage() { cat </dev/null if [ $? -eq 0 ]; then : Yes, user exists. We can further check his permission on crm_mon if necessary else ocf_log err "The user $OCF_RESKEY_user does not exist!" exit $OCF_ERR_ARGS fi fi # Pidfile better be an absolute path case $OCF_RESKEY_pidfile in /*) ;; *) ocf_log warn "You should have pidfile($OCF_RESKEY_pidfile) of absolute path!" ;; esac # Check the update interval if ocf_is_decimal "$OCF_RESKEY_update" && [ $OCF_RESKEY_update -gt 0 ]; then : else ocf_log err "Invalid update interval $OCF_RESKEY_update. It should be positive integer!" exit $OCF_ERR_ARGS fi if CheckOptions $OCF_RESKEY_extra_options; then : else ocf_log err "Invalid options $OCF_RESKEY_extra_options!" exit $OCF_ERR_ARGS fi # Htmlfile better be an absolute path case $OCF_RESKEY_htmlfile in /*) ;; *) ocf_log warn "You should have htmlfile($OCF_RESKEY_htmlfile) of absolute path!" ;; esac echo "Validate OK" return $OCF_SUCCESS } if [ $# -ne 1 ]; then ClusterMon_usage exit $OCF_ERR_ARGS fi : ${OCF_RESKEY_update:="15000"} : ${OCF_RESKEY_pidfile:="/tmp/ClusterMon_${OCF_RESOURCE_INSTANCE}.pid"} : ${OCF_RESKEY_htmlfile:="/tmp/ClusterMon_${OCF_RESOURCE_INSTANCE}.html"} OCF_RESKEY_update=`expr $OCF_RESKEY_update / 1000` case $__OCF_ACTION in meta-data) meta_data exit $OCF_SUCCESS ;; start) ClusterMon_start ;; stop) ClusterMon_stop ;; monitor) ClusterMon_monitor ;; validate-all) ClusterMon_validate ;; usage|help) ClusterMon_usage exit $OCF_SUCCESS ;; *) ClusterMon_usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $? diff --git a/heartbeat/Delay b/heartbeat/Delay index 1617f2f64..6b169438e 100644 --- a/heartbeat/Delay +++ b/heartbeat/Delay @@ -1,222 +1,222 @@ #!/bin/sh # # # Support: linux-ha@lists.linux-ha.org # License: GNU General Public License (GPL) # # This script is a test resource for introducing delay. # # usage: $0 {start|stop|status|monitor|meta-data} # # OCF parameters are as below: # OCF_RESKEY_startdelay # OCF_RESKEY_stopdelay # OCF_RESKEY_mondelay # # # OCF_RESKEY_startdelay defaults to 30 (seconds) # OCF_RESKEY_stopdelay defaults to $OCF_RESKEY_startdelay # OCF_RESKEY_mondelay defaults to $OCF_RESKEY_startdelay # # # This is really a test resource script. # ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### usage() { cat <<-! usage: $0 {start|stop|status|monitor|meta-data|validate-all} ! } meta_data() { cat < 1.0 This script is a test resource for introducing delay. Delay resource agent How long in seconds to delay on start operation. Start delay How long in seconds to delay on stop operation. Defaults to "startdelay" if unspecified. Stop delay How long in seconds to delay on monitor operation. Defaults to "startdelay" if unspecified. Monitor delay - - + + END } Delay_stat() { ha_pseudo_resource Delay_${OCF_RESOURCE_INSTANCE} monitor } Delay_Status() { if Delay_stat then ocf_log info "Delay is running OK" return $OCF_SUCCESS else ocf_log info "Delay is stopped" return $OCF_NOT_RUNNING fi } Delay_Monitor() { Delay_Validate_All -q sleep $OCF_RESKEY_mondelay Delay_Status } Delay_Start() { if Delay_stat then ocf_log info "Delay already running." return $OCF_SUCCESS else Delay_Validate_All -q ha_pseudo_resource Delay_${OCF_RESOURCE_INSTANCE} start rc=$? sleep $OCF_RESKEY_startdelay if [ $rc -ne 0 ] then return $OCF_ERR_PERM fi return $OCF_SUCCESS fi } Delay_Stop() { if Delay_stat then Delay_Validate_All -q ha_pseudo_resource Delay_${OCF_RESOURCE_INSTANCE} stop rc=$? sleep $OCF_RESKEY_stopdelay if [ $rc -ne 0 ] then return $OCF_ERR_PERM fi return $OCF_SUCCESS else ocf_log info "Delay already stopped." return $OCF_SUCCESS fi } # Check if all the arguments are valid numbers, a string is considered valid if: # 1. It does not contain any character but digits and period "."; # 2. The period "." does not occur more than once Are_Valid_Numbers() { for i in "$@"; do echo $i |grep -v [^0-9.] |grep -q -v [.].*[.] if test $? -ne 0; then return $OCF_ERR_ARGS fi done return $OCF_SUCCESS } Delay_Validate_All() { # Be quiet when specified -q option _and_ validation succeded getopts "q" option if test $option = "q"; then quiet=yes else quiet=no fi shift $(($OPTIND -1)) if Are_Valid_Numbers $OCF_RESKEY_startdelay $OCF_RESKEY_stopdelay \ $OCF_RESKEY_mondelay; then if test $quiet = "no"; then echo "Validate OK" fi # _Return_ on validation success return $OCF_SUCCESS else echo "Some of the instance parameters are invalid" # _Exit_ on validation failure exit $OCF_ERR_ARGS fi } if [ $# -ne 1 ]; then usage exit $OCF_ERR_ARGS fi : ${OCF_RESKEY_startdelay=30} : ${OCF_RESKEY_stopdelay=$OCF_RESKEY_startdelay} : ${OCF_RESKEY_mondelay=$OCF_RESKEY_startdelay} case $1 in meta-data) meta_data exit $OCF_SUCCESS ;; start) Delay_Start ;; stop) Delay_Stop ;; monitor) Delay_Monitor ;; status) Delay_Status ;; validate-all) Delay_Validate_All ;; usage) usage exit $OCF_SUCCESS ;; *) usage exit $OCF_ERR_ARGS ;; esac exit $? diff --git a/heartbeat/Dummy b/heartbeat/Dummy index 65f335058..2b6dec261 100644 --- a/heartbeat/Dummy +++ b/heartbeat/Dummy @@ -1,165 +1,158 @@ #!/bin/sh # # # Dummy OCF RA. Does nothing but wait a few seconds, can be # configured to fail occassionally. # # Copyright (c) 2004 SUSE LINUX AG, Lars Marowsky-Bré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_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### meta_data() { cat < 1.0 This is a Dummy Resource Agent. It does absolutely nothing except keep track of whether its running or not. Its purpose in life is for testing and to serve as a template for RA writers. Dummy resource agent Location to store the resource state in. State file END } ####################################################################### -# don't exit on TERM, to test that lrmd makes sure that we do exit -trap sigterm_handler TERM -sigterm_handler() { - ocf_log info "They use TERM to bring us down. No such luck." - return -} - dummy_usage() { cat < 1.0 Resource script for Filesystem. It manages a Filesystem on a shared storage medium. Filesystem resource agent The name of block device for the filesystem, or -U, -L options for mount, or NFS mount specification. block device The mount point for the filesystem. mount point The optional type of filesystem to be mounted. filesystem type Any extra options to be given as -o options to mount. For bind mounts, add "bind" here and set fstype to "none". We will do the right thing for options such as "bind,ro". options - + END } # # Make sure the kernel does the right thing with the FS buffers # This function should be called after unmounting and before mounting # It may not be necessary in 2.4 and later kernels, but it shouldn't hurt # anything either... # # It's really a bug that you have to do this at all... # flushbufs() { if have_binary $BLOCKDEV ; then if [ "$blockdevice" = "yes" ] ; then $BLOCKDEV --flushbufs $1 return $? fi fi return 0 } # Take advantage of /etc/mtab if present, use portable mount command # otherwise. Normalize format to "dev mountpoint fstype". list_mounts() { if [ -f "/etc/mtab" -a -r "/etc/mtab" ]; then cut -d' ' -f1,2,3 /dev/null fi } ocfs2_cleanup() { # We'll never see the post-stop notification. We're gone now, # have unmounted, and thus should remove the membership. # # (Do so regardless of whether we were unmounted already, # because the admin might have manually unmounted but not # cleared up the membership directory. Bad admin, no cookie.) # if [ ! -d "$OCFS2_FS_ROOT" ]; then ocf_log info "$OCFS2_FS_ROOT: Filesystem membership already gone." else ocf_log info "$OCFS2_FS_ROOT: Removing membership directory." rm -rf $OCFS2_FS_ROOT/ fi ocfs2_del_cache } ocfs2_fetch_uuid() { mounted.ocfs2 -d $DEVICE|tail -1|awk '{print $3}'|tr -d -- -|tr '[a-z]' '[A-Z]' } ocfs2_set_uuid() { _OCFS2_uuid_cache="$HA_RSCTMP/Filesystem.ocfs2_uuid.$(echo $DEVICE|tr / .)" if [ "$OP" != "start" -a -e "$_OCFS2_uuid_cache" ]; then # Trust the cache. OCFS2_UUID=$(cat $_OCFS2_uuid_cache 2>/dev/null) return 0 fi OCFS2_UUID=$(ocfs2_fetch_uuid) if [ -n "$OCFS2_UUID" -a "$OCFS2_UUID" != "UUID" ]; then # UUID valid: echo $OCFS2_UUID > $_OCFS2_uuid_cache return 0 fi # Ok, no UUID still, but that's alright for stop, because it # very likely means we never got started - if [ "$OP" = "stop" ]; then ocf_log warn "$DEVICE: No UUID; assuming never started!" OCFS2_UUID="UUID_NOT_SET" return 0 fi # Everything else - wrong: ocf_log err "$DEVICE: Could not determine ocfs2 UUID for device." exit $OCF_ERR_GENERIC } ocfs2_init() { # Check & initialize the OCFS2 specific variables. # This check detects whether the special/legacy hooks to # integrate OCFS2 with user-space clustering on SLES10 need to # be activated. # Newer kernels >= 2.6.28, with OCFS2+openAIS+Pacemaker, do # not need this: OCFS2_SLES10="" if [ "X$HA_cluster_type" != "Xopenais" ]; then if grep -q "SUSE Linux Enterprise Server 10" /etc/SuSE-release >/dev/null 2>&1 ; then OCFS2_SLES10="yes" ocf_log info "$DEVICE: Enabling SLES10 compatibility mode for OCFS2." else ocf_log err "$DEVICE: ocfs2 is not compatible with your environment." exit $OCF_ERR_CONFIGURED fi else return fi if [ $OP != "stop" ]; then if [ -z "$OCF_RESKEY_CRM_meta_clone" ]; then ocf_log err "ocfs2 must be run as a clone." exit $OCF_ERR_GENERIC fi fi if [ $blockdevice = "no" ]; then ocf_log err "$DEVICE: ocfs2 needs a block device instead." exit $OCF_ERR_GENERIC fi for f in "$OCF_RESKEY_ocfs2_configfs" /sys/kernel/config/cluster /configfs/cluster ; do if [ -n "$f" -a -d "$f" ]; then OCFS2_CONFIGFS="$f" break fi done if [ ! -d "$OCFS2_CONFIGFS" ]; then ocf_log err "ocfs2 needs configfs mounted." exit $OCF_ERR_GENERIC fi ocfs2_set_uuid if [ -n "$OCF_RESKEY_ocfs2_cluster" ]; then OCFS2_CLUSTER=$(echo $OCF_RESKEY_ocfs2_cluster) else OCFS2_CLUSTER=$(find "$OCFS2_CONFIGFS" -maxdepth 1 -mindepth 1 -type d -printf %f 2>/dev/null) set -- $OCFS2_CLUSTER local n; n="$#" if [ $n -gt 1 ]; then ocf_log err "$OCFS2_CLUSTER: several clusters found." exit $OCF_ERR_GENERIC fi if [ $n -eq 0 ]; then ocf_log err "$OCFS2_CONFIGFS: no clusters found." exit $OCF_ERR_GENERIC fi fi OCFS2_CLUSTER_ROOT="$OCFS2_CONFIGFS/$OCFS2_CLUSTER" if [ ! -d "$OCFS2_CLUSTER_ROOT" ]; then ocf_log err "$OCFS2_CLUSTER: Cluster doesn't exist. Maybe o2cb hasn't been run?" exit $OCF_ERR_GENERIC fi OCFS2_FS_ROOT=$OCFS2_CLUSTER_ROOT/heartbeat/$OCFS2_UUID } # kernels < 2.6.26 can't handle bind remounts bind_kernel_check() { echo "$options" | grep -w ro >/dev/null 2>&1 || return uname -r | awk -F. ' $1==2 && $2==6 { sub("[^0-9].*","",$3); if ($3<26) exit(1); }' [ $? -ne 0 ] && ocf_log warn "kernel `uname -r` cannot handle read only bind mounts" } bind_mount() { if echo "$options" | grep -w bind >/dev/null 2>&1 && [ "$options" != "-o bind" ] then bind_kernel_check bind_opts=`echo $options | sed 's/bind/remount/'` $MOUNT $bind_opts $MOUNTPOINT else true # make sure to return OK fi } # # START: Start up the filesystem # Filesystem_start() { if [ -n "$OCFS2_SLES10" ]; then # "start" now has the notification data available; that # we're being started means we didn't get the # pre-notification, because we weren't running, so # process the information now first. ocf_log info "$OCFS2_UUID: Faking pre-notification on start." OCF_RESKEY_CRM_meta_notify_type="pre" OCF_RESKEY_CRM_meta_notify_operation="start" Filesystem_notify fi # See if the device is already mounted. if Filesystem_status >/dev/null 2>&1 ; then ocf_log info "Filesystem $MOUNTPOINT is already mounted." return $OCF_SUCCESS fi if [ "X${HOSTOS}" != "XOpenBSD" ];then # Insert SCSI module # TODO: This probably should go away. Why should the filesystem # RA magically load a kernel module? $MODPROBE scsi_hostadapter >/dev/null 2>&1 if [ -z "$FSTYPE" -o "$FSTYPE" = none ]; then : No FSTYPE specified, rely on the system has the right file-system support already else # Insert Filesystem module $MODPROBE $FSTYPE >/dev/null 2>&1 grep -e "$FSTYPE"'$' /proc/filesystems >/dev/null if [ $? -ne 0 ] ; then ocf_log err "Couldn't find filesystem $FSTYPE in /proc/filesystems" return $OCF_ERR_ARGS fi fi fi # Check the filesystem & auto repair. # NOTE: Some filesystem types don't need this step... Please modify # accordingly if [ $blockdevice = "yes" ]; then if [ "$DEVICE" != "/dev/null" -a ! -b "$DEVICE" ] ; then ocf_log err "Couldn't find device [$DEVICE]. Expected /dev/??? to exist" exit $OCF_ERR_INSTALLED fi if case $FSTYPE in ext3|reiserfs|reiser4|nss|xfs|jfs|vfat|fat|nfs|cifs|smbfs|ocfs2|gfs2|none|lustre) false;; *) true;; esac then ocf_log info "Starting filesystem check on $DEVICE" if [ -z "$FSTYPE" ]; then $FSCK -p $DEVICE else $FSCK -t $FSTYPE -p $DEVICE fi # NOTE: if any errors at all are detected, it returns non-zero # if the error is >= 4 then there is a big problem if [ $? -ge 4 ]; then ocf_log err "Couldn't sucessfully fsck filesystem for $DEVICE" return $OCF_ERR_GENERIC fi fi fi if [ ! -d "$MOUNTPOINT" ] ; then ocf_log err "Couldn't find directory [$MOUNTPOINT] to use as a mount point" exit $OCF_ERR_INSTALLED fi flushbufs $DEVICE # Mount the filesystem. case "$FSTYPE" in none) $MOUNT $options $DEVICE $MOUNTPOINT && bind_mount ;; "") $MOUNT $options $DEVICE $MOUNTPOINT ;; *) $MOUNT -t $FSTYPE $options $DEVICE $MOUNTPOINT ;; esac if [ $? -ne 0 ]; then ocf_log err "Couldn't mount filesystem $DEVICE on $MOUNTPOINT" if [ -n "$OCFS2_SLES10" ]; then ocfs2_cleanup fi return $OCF_ERR_GENERIC fi return 0 } # end of Filesystem_start Filesystem_notify() { # Process notifications; this is the essential glue level for # giving user-space membership events to a cluster-aware # filesystem. Right now, only OCFS2 is supported. # # When we get a pre-start notification, we set up all the nodes # which will be active in our membership for the filesystem. # (For the resource to be started, this happens at the time of # the actual 'start' operation.) # # At a post-start, actually there's nothing to do for us really, # but no harm done in re-syncing either. # # pre-stop is meaningless; we can't remove any node yet, it # first needs to unmount. # # post-stop: the node is removed from the membership of the # other nodes. # # Note that this expects that the base cluster is already # active; ie o2cb has been started and populated # $OCFS2_CLUSTER_ROOT/node/ already. This can be achieved by # simply having o2cb run on all nodes by the CRM too. This # probably ought to be mentioned somewhere in the to be written # documentation. ;-) # if [ -z "$OCFS2_SLES10" ]; then # One of the cases which shouldn't occur; it should have # been caught much earlier. Still, you know ... ocf_log err "$DEVICE: Please only enable notifications for SLES10 OCFS2 mounts." # Yes, in theory this is a configuration error, but # simply discarding them allows users to switch from the # SLES10 stack to the new one w/o downtime. # Ignoring the notifications is harmless, afterall, and # they can simply disable them in their own time. return $OCF_SUCCESS fi local n_type; n_type="$OCF_RESKEY_CRM_meta_notify_type" local n_op; n_op="$OCF_RESKEY_CRM_meta_notify_operation" local n_active; n_active="$OCF_RESKEY_CRM_meta_notify_active_uname" local n_stop; n_stop="$OCF_RESKEY_CRM_meta_notify_stop_uname" local n_start; n_start="$OCF_RESKEY_CRM_meta_notify_start_uname" ocf_log info "$OCFS2_UUID: notify: $n_type for $n_op" ocf_log info "$OCFS2_UUID: notify active: $n_active" ocf_log info "$OCFS2_UUID: notify stop: $n_stop" ocf_log info "$OCFS2_UUID: notify start: $n_start" case "$n_type" in pre) case "$n_op" in stop) ocf_log info "$OCFS2_UUID: ignoring pre-notify for stop." return $OCF_SUCCESS ;; start) # These are about to become active; prepare to # communicate with them. # Duplicate removal - start can contain nodes # already on the active list, confusing the # script later on: for UNAME in $n_active; do n_start=`echo ${n_start} | sed s/$UNAME//` done # Merge pruned lists again: n_active="$n_active $n_start" ;; esac ;; post) case "$n_op" in stop) # remove unames from notify_stop_uname; these have been # stopped and can no longer be considered active. for UNAME in $n_stop; do n_active=`echo ${n_active} | sed s/$UNAME//` done ;; start) if [ "$n_op" = "start" ]; then ocf_log info "$OCFS2_UUID: ignoring post-notify for start." return $OCF_SUCCESS fi ;; esac ;; esac ocf_log info "$OCFS2_UUID: post-processed active: $n_active" local n_myself; n_myself=${HA_CURHOST:-$(uname -n | tr '[A-Z]' '[a-z]')} ocf_log info "$OCFS2_UUID: I am node $n_myself." case " $n_active " in *" $n_myself "*) ;; *) ocf_log err "$OCFS2_UUID: $n_myself (local) not on active list!" return $OCF_ERR_GENERIC ;; esac if [ -d "$OCFS2_FS_ROOT" ]; then entry_prefix=$OCFS2_FS_ROOT/ for entry in $OCFS2_FS_ROOT/* ; do n_fs="${entry##$entry_prefix}" # ocf_log info "$OCFS2_UUID: Found current node $n_fs" case " $n_active " in *" $n_fs "*) # Construct a list of nodes which are present # already in the membership. n_exists="$n_exists $n_fs" ocf_log info "$OCFS2_UUID: Keeping node: $n_fs" ;; *) # Node is in the membership currently, but not on our # active list. Must be removed. if [ "$n_op" = "start" ]; then ocf_log warn "$OCFS2_UUID: Removing nodes on start" fi ocf_log info "$OCFS2_UUID: Removing dead node: $n_fs" if ! rm -f $entry ; then ocf_log err "$OCFS2_UUID: Removal of $n_fs failed!" fi ;; esac done else ocf_log info "$OCFS2_UUID: heartbeat directory doesn't exist yet, creating." mkdir -p $OCFS2_FS_ROOT fi ocf_log info "$OCFS2_UUID: Existing node list: $n_exists" # (2) for entry in $n_active ; do # ocf_log info "$OCFS2_UUID: Expected active node: $entry" case " $n_exists " in *" $entry "*) ocf_log info "$OCFS2_UUID: Already active: $entry" ;; *) if [ "$n_op" = "stop" ]; then ocf_log warn "$OCFS2_UUID: Adding nodes on stop" fi ocf_log info "$OCFS2_UUID: Activating node: $entry" if ! ln -s $OCFS2_CLUSTER_ROOT/node/$entry $OCFS2_FS_ROOT/$entry ; then ocf_log err "$OCFS2_CLUSTER_ROOT/node/$entry: failed to link" fi ;; esac done } # # STOP: Unmount the filesystem # Filesystem_stop() { # See if the device is currently mounted Filesystem_status >/dev/null 2>&1 if [ $? -eq $OCF_NOT_RUNNING ]; then # Already unmounted, wonderful. rc=$OCF_SUCCESS else # Determine the real blockdevice this is mounted on (if # possible) prior to unmounting. determine_blockdevice # For networked filesystems, there's merit in trying -f: case "$FSTYPE" in nfs|cifs|smbfs) umount_force="-f" ;; esac # Umount all sub-filesystems mounted under $MOUNTPOINT/ too. for SUB in `list_submounts $MOUNTPOINT` $MOUNTPOINT; do ocf_log info "Trying to unmount $MOUNTPOINT" for sig in SIGTERM SIGTERM SIGTERM SIGKILL SIGKILL SIGKILL; do $UMOUNT $umount_force $SUB if list_mounts | grep -q " $SUB " >/dev/null 2>&1; then rc=$OCF_ERR_GENERIC ocf_log err "Couldn't unmount $SUB; trying cleanup with $sig" # fuser returns a non-zero return code if none of the # specified files is accessed or in case of a fatal # error. if [ "X${HOSTOS}" = "XOpenBSD" ];then PIDS=`fstat | grep ${SUB} | awk '{print $3}'` for PID in ${PIDS};do kill -s 9 ${PID} ocf_log info "Sent kill -9 to ${PID}" done else if $FUSER -$sig -m -k $SUB ; then ocf_log info "Some processes on $SUB were signalled" else ocf_log info "No processes on $SUB were signalled" fi fi sleep 1 else rc=$OCF_SUCCESS ocf_log info "unmounted $SUB successfully" break fi done if [ $rc -ne $OCF_SUCCESS ]; then ocf_log err "Couldn't unmount $SUB, giving up!" fi done fi flushbufs $DEVICE # Yes I know the next blob is ugly, sorry. if [ $rc -eq $OCF_SUCCESS ]; then if [ "$FSTYPE" = "ocfs2" ]; then ocfs2_init if [ -n "$OCFS2_SLES10" ]; then ocfs2_cleanup fi fi fi return $rc } # end of Filesystem_stop # # STATUS: is the filesystem mounted or not? # Filesystem_status() { if list_mounts | grep -q " $MOUNTPOINT " >/dev/null 2>&1; then rc=$OCF_SUCCESS msg="$MOUNTPOINT is mounted (running)" else rc=$OCF_NOT_RUNNING msg="$MOUNTPOINT is unmounted (stopped)" fi # TODO: For ocfs2, or other cluster filesystems, should we be # checking connectivity to other nodes here, or the IO path to # the storage? # Special case "monitor" to check whether the UUID cached and # on-disk still match? case "$OP" in status) ocf_log info "$msg";; esac return $rc } # end of Filesystem_status # # VALIDATE_ALL: Are the instance parameters valid? # FIXME!! The only part that's useful is the return code. # This code always returns $OCF_SUCCESS (!) # Filesystem_validate_all() { if [ -n $MOUNTPOINT -a ! -d $MOUNTPOINT ]; then ocf_log warn "Mountpoint $MOUNTPOINT does not exist" fi # Check if the $FSTYPE is workable # NOTE: Without inserting the $FSTYPE module, this step may be imprecise # TODO: This is Linux specific crap. if [ ! -z "$FSTYPE" -a "$FSTYPE" != none ]; then cut -f2 /proc/filesystems |grep -q ^$FSTYPE$ if [ $? -ne 0 ]; then modpath=/lib/modules/`uname -r` moddep=$modpath/modules.dep # Do we have $FSTYPE in modules.dep? cut -d' ' -f1 $moddep |grep -q "^$modpath.*$FSTYPE\.k\?o:$" if [ $? -ne 0 ]; then ocf_log info "It seems we do not have $FSTYPE support" fi fi fi #TODO: How to check the $options ? return $OCF_SUCCESS } # Check the arguments passed to this script if [ $# -ne 1 ]; then usage exit $OCF_ERR_ARGS fi # Check the OCF_RESKEY_ environment variables... DEVICE=$OCF_RESKEY_device FSTYPE=$OCF_RESKEY_fstype if [ ! -z "$OCF_RESKEY_options" ]; then options="-o $OCF_RESKEY_options" fi OP=$1 # These operations do not require instance parameters case $OP in meta-data) meta_data exit $OCF_SUCCESS ;; usage) usage exit $OCF_SUCCESS ;; esac blockdevice=no case $DEVICE in "") ocf_log err "Please set OCF_RESKEY_device to the device to be managed" exit $OCF_ERR_ARGS ;; -*) # Oh... An option to mount instead... Typically -U or -L ;; [!/]*:/*) # An NFS filesystem specification... ;; //[!/]*/*) # An SMB filesystem specification... ;; /dev/null) # Special case for BSC blockdevice=yes ;; *) if [ ! -b "$DEVICE" -a ! -d "$DEVICE" -a "X$OP" != Xstart ] ; then ocf_log warn "Couldn't find device [$DEVICE]. Expected /dev/??? to exist" fi if [ ! -d "$DEVICE" ];then blockdevice=yes fi ;; esac # Normalize instance parameters: # It is possible that OCF_RESKEY_directory has one or even multiple trailing "/". # But the output of `mount` and /proc/mounts do not. if [ -z "$OCF_RESKEY_directory" ]; then if [ X$OP = "Xstart" -o $blockdevice = "no" ]; then ocf_log err "Please specify the directory" exit $OCF_ERR_ARGS fi else MOUNTPOINT=$(echo $OCF_RESKEY_directory | sed 's/\/*$//') : ${MOUNTPOINT:=/} # At this stage, $MOUNTPOINT does not contain trailing "/" unless it is "/" # TODO: / mounted via Filesystem sounds dangerous. On stop, we'll # kill the whole system. Is that a good idea? fi # Check to make sure the utilites are found if [ "X${HOSTOS}" != "XOpenBSD" ];then check_binary $MODPROBE check_binary $FUSER fi check_binary $FSCK check_binary $MOUNT check_binary $UMOUNT if [ "$OP" != "monitor" ]; then ocf_log info "Running $OP for $DEVICE on $MOUNTPOINT" fi # These operations do not require the clone checking + OCFS2 # initialization. case $OP in status|monitor) Filesystem_status exit $? ;; validate-all) Filesystem_validate_all exit $? ;; stop) Filesystem_stop exit $? ;; esac case $FSTYPE in ocfs2) ocfs2_init ;; nfs|none|gfs2) : # this is kind of safe too ;; *) if [ -n "$OCF_RESKEY_CRM_meta_clone" ]; then ocf_log err "DANGER! $FSTYPE on $DEVICE is NOT cluster-aware!" ocf_log err "DO NOT RUN IT AS A CLONE!" ocf_log err "Politely refusing to proceed to avoid data corruption." exit $OCF_ERR_CONFIGURED fi ;; esac case $OP in start) Filesystem_start ;; notify) Filesystem_notify ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $? diff --git a/heartbeat/ICP b/heartbeat/ICP index 41383f1ae..739a75cee 100644 --- a/heartbeat/ICP +++ b/heartbeat/ICP @@ -1,295 +1,295 @@ #!/bin/sh # # # ICP # # Description: Manages an ICP Vortex clustered host drive as an HA resource # # # Author: Lars Marowsky-Bree # Support: linux-ha@lists.linux-ha.org # License: GNU General Public License (GPL) # Copyright: (C) 2002 SuSE Linux AG # # # An example usage in /etc/ha.d/haresources: # node1 10.0.0.170 LinuxSCSI::0:0 ICP::c0h1::/dev/sdb1 LVM::myvolname # # Notice that you will need to get the utility "icpclucon" from the ICP # support to use this. # # See usage() function below for more details... # # OCF parameters are as below: # OCF_RESKEY_driveid # OCF_RESKEY_device ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### # ICPCLUCON=/usr/sbin/icpclucon # usage() { methods=`ICP_methods | grep -v methods` methods=`echo $methods | tr ' ' '|'` cat <<-! usage: $0 ($methods) $0 manages an ICP Vortex clustered host drive. The 'start' operation reserves the given host drive. The 'stop' operation releses the given host drive. The 'status' operation reports whether the host drive is reserved. The 'monitor' operation reports whether the host drive is reserved. The 'validate-all' operation reports whether OCF instance parameters are valid. The 'methods' operation reports on the methods $0 supports ! } meta_data() { cat < 1.0 Resource script for ICP. It Manages an ICP Vortex clustered host drive as an HA resource. ICP resource agent The ICP cluster drive ID. ICP cluster drive ID The device name. device - - + + END } # # methods: What methods/operations do we support? # ICP_methods() { cat <<-! start stop status monitor methods validate-all meta-data usage ! } ICP_status() { local icp_out icp_out=$($ICPCLUCON -v -status $1) if [ $? -ne 0 ]; then ocf_log "err" "Hostdrive not reserved by us." return $OCF_ERR_GENERIC fi if expr match "$icp_out" \ '.*Drive is reserved by this host.*' >/dev/null 2>&1 ; then ocf_log "info" "Volume $1 is reserved by us." return $OCF_SUCCESS elif expr match "$icp_out" \ '.*Drive is not reserved by any host.*' >/dev/null 2>&1 ; then ocf_log "err" "Volume $1 not reserved by any host." return $OCF_NOT_RUNNING else ocf_log "err" "Unknown output from icpclucon. Assuming we do not have a reservation:" ocf_log "err" "$icp_out" return $OCF_NOT_RUNNING fi } ICP_report_status() { if ICP_status $1 ; then echo "$1: running" return $OCF_SUCCESS else echo "$1: not running" return $OCF_NOT_RUNNING fi } # # Monitor the host drive - does it really seem to be working? # # ICP_monitor() { if ICP_status $1 then return $? else ocf_log "err" "ICP host drive $1 is offline" return $OCF_NOT_RUNNING fi } Clear_bufs() { $BLOCKDEV --flushbufs $1 } # # Enable ICP host drive # ICP_start() { ocf_log "info" "Activating host drive $1" ocf_run $ICPCLUCON -v -reserve $1 if [ $? -ne 0 ]; then ocf_log "info" "Forcing reservation of $1" ocf_run $ICPCLUCON -v -force $1 || return $OCF_ERR_GENERIC fi if ICP_status $1 then : OK # A reservation isn't as prompt as it should be sleep 3 return $OCF_SUCCESS else ocf_log "err" "ICP: $1 was not reserved correctly" return $OCF_ERR_GENERIC fi } # # Release the ICP host drive # ICP_stop() { ocf_log "info" "Releasing ICP host drive $1" ocf_run $ICPCLUCON -v -release $1 || return $OCF_ERR_GENERIC ocf_log "info" "Verifying reservation" if ICP_status $1 ; then ocf_log "err" "ICP: $1 was not released correctly" return $OCF_ERR_GENERIC fi return $OCF_SUCCESS } ICP_validate_all() { check_binary $BLOCKDEV check_binary $ICPCLUCON $ICPCLUCON -v -status $driveid >/dev/null 2>&1 if [ $? -ne 0 ]; then ocf_log err "Invalid driveid $driveid" exit $OCF_ERR_ARGS fi if [ ! -b $device ]; then ocf_log err "Device $device is not a block device" exit $OCF_ERR_ARGS fi # Do not know how to check the association of $device with $driveid. return $OCF_SUCCESS } # # 'main' starts here... # if ( [ $# -ne 1 ] ) then usage exit $OCF_ERR_ARGS fi # These operations do not require OCF instance parameters to be set case "$1" in meta-data) meta_data exit $OCF_SUCCESS;; methods) ICP_methods exit $OCF_SUCCESS;; usage) usage exit $OCF_SUCCESS;; *) ;; esac if [ -z "$OCF_RESKEY_driveid" ] then ocf_log err "Please specify OCF_RESKEY_driveid" exit $OCF_ERR_ARGS fi if [ -z "$OCF_RESKEY_device" ]; then ocf_log err "Please specify OCF_RESKEY_device" exit $OCF_ERR_ARGS fi driveid=$OCF_RESKEY_driveid device=$OCF_RESKEY_device # What kind of method was invoked? case "$1" in start) ICP_validate_all ICP_start $driveid Clear_bufs $device exit $?;; stop) ICP_stop $driveid Clear_bufs $device exit $?;; status) ICP_report_status $driveid exit $?;; monitor) ICP_monitor $driveid exit $?;; validate-all) ICP_validate_all exit $?;; *) usage exit $OCF_ERR_UNIMPLEMENTED;; esac diff --git a/heartbeat/IPaddr b/heartbeat/IPaddr index 8561076ac..5f44fb573 100644 --- a/heartbeat/IPaddr +++ b/heartbeat/IPaddr @@ -1,848 +1,848 @@ #!/bin/sh # # License: GNU General Public License (GPL) # Support: linux-ha@lists.linux-ha.org # # This script manages IP alias IP addresses # # It can add an IP alias, or remove one. # # usage: $0 {start|stop|status|monitor|validate-all|meta-data} # # The "start" arg adds an IP alias. # # Surprisingly, the "stop" arg removes one. :-) # # OCF parameters are as below # OCF_RESKEY_ip # OCF_RESKEY_broadcast # OCF_RESKEY_nic # OCF_RESKEY_cidr_netmask # OCF_RESKEY_lvs_support ( e.g. true, on, 1 ) # OCF_RESKEY_ARP_INTERVAL_MS # OCF_RESKEY_ARP_REPEAT # OCF_RESKEY_ARP_BACKGROUND (e.g. yes ) # OCF_RESKEY_ARP_NETMASK # OCF_RESKEY_local_start_script # OCF_RESKEY_local_stop_script # ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs HA_HBCONF_DIR=${HA_DIR} SENDARP=$HA_BIN/send_arp FINDIF=$HA_BIN/findif VLDIR=$HA_RSCTMP/IPaddr SENDARPPIDDIR=$HA_RSCTMP/send_arp SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$OCF_RESKEY_ip" USAGE="usage: $0 {start|stop|status|monitor|validate-all|meta-data}"; ####################################################################### # Prevent ifconfig localization issues unset LC_ALL; export LC_ALL unset LANGUAGE; export LANGUAGE LC_ALL=C; export LC_ALL LC_MESSAGES=C; export LC_MESSAGES . $HA_HBCONF_DIR/shellfuncs SYSTYPE="`uname -s`" case "$SYSTYPE" in SunOS) # `uname -r` = 5.9 -> SYSVERSION = 9 SYSVERSION="`uname -r | cut -d. -f 2`" ;; Darwin) # Treat Darwin the same as the other BSD variants (matched as *BSD) SYSTYPE="${SYSTYPE}BSD" ;; *) ;; esac meta_data() { cat < 1.0 This script manages IP alias IP addresses It can add an IP alias, or remove one. Manages virtual IPv4 addresses The IPv4 address to be configured in dotted quad notation, for example "192.168.1.1". IPv4 address The base network interface on which the IP address will be brought online. If left empty, the script will try and determine this from the routing table. Do NOT specify an alias interface in the form eth0:1 or anything here; rather, specify the base interface only. Network interface The netmask for the interface in CIDR format. (ie, 24), or in dotted quad notation 255.255.255.0). If unspecified, the script will also try to determine this from the routing table. Netmask Broadcast address associated with the IP. If left empty, the script will determine this from the netmask. Broadcast address You can specify an additional label for your IP address here. Interface label Enable support for LVS Direct Routing configurations. In case a IP address is stopped, only move it to the loopback device to allow the local node to continue to service requests, but no longer advertise it on the network. Enable support for LVS DR Script called when the IP is released Script called when the IP is released Script called when the IP is added Script called when the IP is added milliseconds between ARPs milliseconds between gratuitous ARPs How many gratuitous ARPs to send out when bringing up a new address repeat count run in background (no longer any reason to do this) run in background netmask for ARP - in nonstandard hexadecimal format. netmask for ARP - + END exit $OCF_SUCCESS } # On Linux systems the (hidden) loopback interface may # conflict with the requested IP address. If so, this # unoriginal code will remove the offending loopback address # and save it in VLDIR so it can be added back in later # when the IPaddr is released. # lvs_remove_conflicting_loopback() { ipaddr="$1" ifname="$2" ocf_log info "Removing conflicting loopback $ifname." if echo $ifname > "$VLDIR/$ipaddr" then : Saved loopback information in $VLDIR/$ipaddr else ocf_log err "Could not save conflicting loopback $ifname." \ "it will not be restored." fi delete_interface "$ifname" "$ipaddr" # Forcibly remove the route (if it exists) to the loopback. delete_route "$ipaddr" } # # On Linux systems the (hidden) loopback interface may # need to be restored if it has been taken down previously # by lvs_remove_conflicting_loopback() # lvs_restore_loopback() { ipaddr="$1" if [ ! -s "$VLDIR/$ipaddr" ]; then return fi ifname=`cat "$VLDIR/$ipaddr"` ocf_log info "Restoring loopback IP Address $ipaddr on $ifname." CMD="OCF_RESKEY_cidr_netmask=32 OCF_RESKEY_ip=$1 OCF_RESKEY_nic=$ifname $FINDIF" if NICINFO=`eval $CMD` - NICINFO=`echo $NICINFO | tr -s " "` + NICINFO=`echo $NICINFO | tr " " " " | tr -s " "` then netmask_text=`echo "$NICINFO" | cut -f3 -d " "` broadcast=`echo "$NICINFO" | cut -f5 -d " "` else echo "ERROR: $CMD failed (rc=$rc)" exit $OCF_ERR_GENERIC fi add_interface "$ipaddr" "$ifname" "$ifname" $netmask_text $broadcast rm -f "$VLDIR/$ipaddr" } # # Find out which alias serves the given IP address # The argument is an IP address, and its output # is an aliased interface name (e.g., "eth0:0"). # find_interface_solaris() { ipaddr="$1" $IFCONFIG $IFCONFIG_A_OPT | $AWK '{if ($0 ~ /.*: / && NR > 1) {print "\n"$0} else {print}}' | while read ifname linkstuff do : ifname = $ifname read inet addr junk : inet = $inet addr = $addr while read line && [ "X$line" != "X" ] do : Nothing done case $ifname in *:*) ;; *) continue;; esac # This doesn't look right for a box with multiple NICs. # It looks like it always selects the first interface on # a machine. Yet, we appear to use the results for this case too... ifname=`echo "$ifname" | sed s'%:$%%'` case $addr in addr:$ipaddr) echo $ifname; return $OCF_SUCCESS;; $ipaddr) echo $ifname; return $OCF_SUCCESS;; esac done return $OCF_ERR_GENERIC } find_interface_bsd() { $IFCONFIG $IFCONFIG_A_OPT | awk -v ip_addr="$ipaddr" ' /UP,/ && $0 ~ /^[a-z]+[0-9]:/ { if_name=$1; sub(":$","",if_name); } $1 == "inet" && $2 == ip_addr { print if_name exit(0) }' } # # Find out which alias serves the given IP address # The argument is an IP address, and its output # is an aliased interface name (e.g., "eth0:0"). # find_interface_generic() { ipaddr="$1" $IFCONFIG $IFCONFIG_A_OPT | while read ifname linkstuff do : Read gave us ifname = $ifname read inet addr junk : Read gave us inet = $inet addr = $addr while read line && [ "X$line" != "X" ] do : Nothing done case $ifname in *:*) ;; *) continue;; esac : "comparing $ipaddr to $addr (from ifconfig)" case $addr in addr:$ipaddr) echo $ifname; return $OCF_SUCCESS;; $ipaddr) echo $ifname; return $OCF_SUCCESS;; esac done return $OCF_ERR_GENERIC } # # Find out which alias serves the given IP address # The argument is an IP address, and its output # is an aliased interface name (e.g., "eth0:0"). # find_interface() { ipaddr="$1" case "$SYSTYPE" in SunOS) NIC=`find_interface_solaris $ipaddr`;; *BSD) NIC=`find_interface_bsd $ipaddr`;; *) NIC=`find_interface_generic $ipaddr`;; esac echo $NIC return $OCF_SUCCESS; } # # Find an unused interface/alias name for us to use for new IP alias # The argument is an IP address, and the output # is an aliased interface name (e.g., "eth0:0", "dc0", "le0:0"). # find_free_interface() { NIC="$1" if [ "X$NIC" = "X" ]; then ocf_log err "No free interface found for $OCF_RESKEY_ip" return $OCF_ERR_GENERIC; fi NICBASE="$VLDIR/$NIC" touch "$NICBASE" case "$SYSTYPE" in *BSD) echo $NIC; return $OCF_SUCCESS;; SunOS) j=1 IFLIST=`$IFCONFIG $IFCONFIG_A_OPT | \ grep "^$NIC:[0-9]" | sed 's%: .*%%'`;; *) j=0 IFLIST=`$IFCONFIG $IFCONFIG_A_OPT | \ grep "^$NIC:[0-9]" | sed 's% .*%%'` TRYADRCNT=`ls "${NICBASE}:"* 2>/dev/null | wc -w | tr -d ' '` if [ -f "${NICBASE}:${TRYADRCNT}" ]; then : OK else j="${TRYADRCNT}" fi ;; esac IFLIST=" `echo $IFLIST` " while [ $j -lt 512 ] do case $IFLIST in *" "$NIC:$j" "*) ;; *) NICLINK="$NICBASE:$j" if ln "$NICBASE" "$NICLINK" 2>/dev/null then echo "$NIC:$j" return $OCF_SUCCESS fi ;; esac j=`expr $j + 1` done return $OCF_ERR_GENERIC } delete_route () { ipaddr="$1" case "$SYSTYPE" in SunOS) return 0;; *BSD) CMD="$ROUTE -n delete -host $ipaddr";; *) CMD="$ROUTE -n del -host $ipaddr";; esac $CMD return $? } delete_interface () { ifname="$1" ipaddr="$2" case "$SYSTYPE" in SunOS) if [ "$SYSVERSION" -ge 8 ] ; then CMD="$IFCONFIG $ifname unplumb" else CMD="$IFCONFIG $ifname 0 down" fi;; Darwin*) CMD="$IFCONFIG $ifname $ipaddr delete";; *BSD) CMD="$IFCONFIG $ifname inet $ipaddr delete";; *) CMD="$IFCONFIG $ifname down";; esac ocf_log info "$CMD" $CMD return $? } add_interface () { ipaddr="$1" iface_base="$2" iface="$3" netmask="$4" broadcast="$5" if [ $# != 5 ]; then ocf_log err "Insufficient arguments to add_interface: $*" exit $OCF_ERR_ARGS fi case "$SYSTYPE" in SunOS) if [ "$SYSVERSION" -ge 8 ] ; then $IFCONFIG $iface plumb rc=$? if [ $rc -ne 0 ] ; then echo "ERROR: '$IFCONFIG $iface plumb' failed." return $rc fi fi # At Solaris 10, this single-command version sometimes broke. # Almost certainly an S10 bug. # CMD="$IFCONFIG $iface inet $ipaddr $text up" # So hack the following workaround: CMD="$IFCONFIG $iface inet $ipaddr" CMD="$CMD && $IFCONFIG $iface netmask $netmask" CMD="$CMD && $IFCONFIG $iface up" ;; *BSD) # netmask is always set to 255.255.255.255 for an alias CMD="$IFCONFIG $iface inet $ipaddr netmask 255.255.255.255 alias";; *) CMD="$IFCONFIG $iface $ipaddr netmask $netmask broadcast $broadcast";; esac # Use "eval $CMD" (not "$CMD"): it might be a chain of two or more commands. ocf_log info "eval $CMD" eval $CMD rc=$? if [ $rc != 0 ]; then echo "ERROR: eval $CMD failed (rc=$rc)" fi return $rc } # # Remove the IP alias for the requested IP address... # ip_stop() { echo "In IP Stop" SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$OCF_RESKEY_ip" NIC=`find_interface $OCF_RESKEY_ip` if [ -f "$SENDARPPIDFILE" ]; then cat "$SENDARPPIDFILE" | xargs kill rm -f "$SENDARPPIDFILE" fi if [ -z "$NIC" ]; then : Requested interface not in use return $OCF_SUCCESS fi if [ ${OCF_RESKEY_lvs_support} = 1 ]; then case $NIC in lo*) : Requested interface is on loopback return $OCF_SUCCESS;; esac fi delete_route "$OCF_RESKEY_ip" delete_interface "$NIC" "$OCF_RESKEY_ip" rc=$? if [ ${OCF_RESKEY_lvs_support} = 1 ]; then lvs_restore_loopback "$OCF_RESKEY_ip" fi # remove lock file... rm -f "$VLDIR/$NIC" if [ $rc != 0 ]; then ocf_log warn "IP Address $OCF_RESKEY_ip NOT released" fi return $rc } # # Add an IP alias for the requested IP address... # # It could be that we already have taken it, in which case it should # do nothing. # ip_start() { # # Do we already service this IP address? # ip_status_internal if [ $? = $OCF_SUCCESS ]; then # Nothing to do, the IP is already active return $OCF_SUCCESS; fi NIC_unique=`find_free_interface $OCF_RESKEY_nic` if [ -n "$NIC_unique" ]; then : OK got interface [$NIC_unique] for $OCF_RESKEY_ip else return $OCF_ERR_GENERIC fi # This logic is mostly to support LVS (If I understand it correctly) if [ ${OCF_RESKEY_lvs_support} = 1 ]; then NIC_current=`find_interface $OCF_RESKEY_ip` case $NIC_unique in lo*) if [ x"$NIC_unique" = x"$NIC_current" ]; then # Its already "running" and not moving, nothing to do. ocf_log err "Could not find a non-loopback device to move $OCF_RESKEY_ip to" return $OCF_ERR_GENERIC fi;; *) lvs_remove_conflicting_loopback "$OCF_RESKEY_ip" "$NIC_current";; esac fi add_interface "$OCF_RESKEY_ip" "$OCF_RESKEY_nic" "$NIC_unique" \ "$OCF_RESKEY_cidr_netmask" "$OCF_RESKEY_broadcast" rc=$? if [ $rc != 0 ]; then ocf_log err "Could not add $OCF_RESKEY_ip to $OCF_RESKEY_nic: $rc" return $rc fi # The address is active, now notify others about it using sendarp if [ "$SYSTYPE" = "DarwinBSD" -a "$NIC_unique" = "lo0" ]; then # Darwin can't send ARPs on loopback devices SENDARP="x$SENDARP" # Prevent the binary from being found fi if [ -x $SENDARP ]; then TARGET_INTERFACE=`echo $NIC_unique | sed 's%:.*%%'` SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$OCF_RESKEY_ip" ARGS="-i $OCF_RESKEY_ARP_INTERVAL_MS -r $OCF_RESKEY_ARP_REPEAT" ARGS="$ARGS -p $SENDARPPIDFILE $TARGET_INTERFACE $OCF_RESKEY_ip" ARGS="$ARGS auto $OCF_RESKEY_ip $OCF_RESKEY_ARP_NETMASK" ocf_log debug "Sending Gratuitous Arp for $OCF_RESKEY_ip on $NIC_unique [$TARGET_INTERFACE]" case $OCF_RESKEY_ARP_BACKGROUND in yes) ($SENDARP $ARGS || ocf_log err "Could not send gratuitous arps. rc=$?" & ) >&2 ;; *) $SENDARP $ARGS || ocf_log err "Could not send gratuitous arps. rc=$?";; esac fi ip_status_internal return $? } ip_status_internal() { NIC=`find_interface "$OCF_RESKEY_ip"` if [ "x$NIC" = x ]; then return $OCF_NOT_RUNNING elif [ "${OCF_RESKEY_lvs_support}" = "1" ]; then case $NIC in lo*) return $OCF_NOT_RUNNING;; *) return $OCF_SUCCESS;; esac else if [ x$OCF_RESKEY_nic != x ]; then simple_OCF_NIC=`echo $OCF_RESKEY_nic | awk -F: '{print $1}'` simple_NIC=`echo $NIC | awk -F: '{print $1}'` if [ $simple_OCF_NIC != $simple_NIC ]; then ocf_log err "$OCF_RESKEY_ip is running an interface ($simple_NIC) instead of the configured one ($simple_OCF_NIC)" return $OCF_ERR_GENERIC fi fi return $OCF_SUCCESS fi } ip_status() { ip_status_internal rc=$? if [ $rc = $OCF_SUCCESS ]; then echo "running" elif [ $rc = $OCF_NOT_RUNNING ]; then echo "stopped" else echo "unknown" fi return $rc; } # # Determine if this IP address is really being served, or not. # Note that we must distinguish if *we're* serving it locally... # ip_monitor() { ip_status_internal rc=$? if [ $OCF_CHECK_LEVEL = 0 -o $rc != 0 ]; then return $rc fi ocf_log info "Checking IP stack" PINGARGS="`pingargs $OCF_RESKEY_ip`" for j in 1 2 3 4 5 6 7 8 9 10; do if $PING $PINGARGS >/dev/null 2>&1 ; then return $OCF_SUCCESS fi done return $OCF_ERR_GENERIC } is_positive_integer() { ocf_is_decimal $1 && [ $1 -ge 1 ] if [ $? = 0 ]; then return 1 fi return 0 } ip_validate_all() { : ${OCF_RESKEY_ARP_BACKGROUND=yes} : ${OCF_RESKEY_ARP_NETMASK=ffffffffffff} : ${OCF_RESKEY_ARP_INTERVAL_MS=500} : ${OCF_RESKEY_ARP_REPEAT=10} check_binary $AWK check_binary $IFCONFIG check_binary $ROUTE check_binary $PING if [ -d "$VLDIR/" ] || mkdir -p "$VLDIR/" then : Directory $VLDIR now exists else ocf_log err "Could not create \"$VLDIR/\"." return $OCF_ERR_GENERIC fi if is_positive_integer $OCF_RESKEY_ARP_INTERVAL_MS then ocf_log err "Invalid parameter value: ARP_INTERVAL_MS [$OCF_RESKEY_ARP_INTERVAL_MS]" return $OCF_ERR_ARGS fi if is_positive_integer $OCF_RESKEY_ARP_REPEAT then ocf_log err "Invalid parameter value: ARP_REPEAT [$OCF_RESKEY_ARP_REPEAT]" return $OCF_ERR_ARGS fi : ${OCF_RESKEY_lvs_support=0} if [ "$SYSTYPE" = "Linux" -o "$SYSTYPE" = "SunOS" ]; then : else if [ "${OCF_RESKEY_lvs_support}" = "1" ]; then ocf_log err "$SYSTYPE does not support LVS" return $OCF_ERR_GENERIC fi fi case $OCF_RESKEY_ip in "") ocf_log err "Required parameter OCF_RESKEY_ip is missing" return $OCF_ERR_CONFIGURED;; [0-9]*.[0-9]*.[0-9]*.*[0-9]) : OK;; *) ocf_log err "Parameter OCF_RESKEY_ip [$OCF_RESKEY_ip] not an IP address" return $OCF_ERR_CONFIGURED;; esac # Unconditionally do this? case $OCF_RESKEY_nic in *:*) OCF_RESKEY_nic=`echo $OCF_RESKEY_nic | sed 's/:.*//'` ;; esac NICINFO=`$FINDIF` rc=$? if [ $rc != 0 ]; then ocf_log err "$FINDIF failed [rc=$rc]." return $OCF_ERR_GENERIC fi tmp=`echo "$NICINFO" | cut -f1` if [ "x$OCF_RESKEY_nic" = "x" ] then ocf_log info "Using calculated nic for ${OCF_RESKEY_ip}: $tmp" OCF_RESKEY_nic=$tmp elif [ x$tmp != x${OCF_RESKEY_nic} ] then ocf_log err "Invalid parameter value: nic [$OCF_RESKEY_nic] Calculated nic: [$tmp]" return $OCF_ERR_ARGS fi tmp=`echo "$NICINFO" | cut -f2 | cut -d ' ' -f2` if [ "x$OCF_RESKEY_cidr_netmask" != "x$tmp" ] then ocf_log info "Using calculated netmask for ${OCF_RESKEY_ip}: $tmp" fi # Always use the calculated version becuase it might have been specified # using CIDR notation which not every system accepts OCF_RESKEY_netmask=$tmp OCF_RESKEY_cidr_netmask=$tmp; export OCF_RESKEY_cidr_netmask tmp=`echo "$NICINFO" | cut -f3 | cut -d ' ' -f2` if [ "x$OCF_RESKEY_broadcast" = "x" ] then ocf_log debug "Using calculated broadcast for ${OCF_RESKEY_ip}: $tmp" OCF_RESKEY_broadcast=$tmp elif [ x$tmp != x${OCF_RESKEY_broadcast} ]; then ocf_log err "Invalid parameter value: broadcast [$OCF_RESKEY_broadcast] Calculated broadcast: [$tmp]" return $OCF_ERR_ARGS fi return $OCF_SUCCESS } usage() { echo $USAGE >&2 return $1 } if [ $# -ne 1 ]; then usage $OCF_ERR_ARGS fi : ${OCF_RESKEY_lvs_support=0} # Normalize the value of lvs_support if [ "${OCF_RESKEY_lvs_support}" = "true" \ -o "${OCF_RESKEY_lvs_support}" = "on" \ -o "${OCF_RESKEY_lvs_support}" = "yes" \ -o "${OCF_RESKEY_lvs_support}" = "1" ]; then OCF_RESKEY_lvs_support=1 else OCF_RESKEY_lvs_support=0 fi # Note: We had a version out there for a while which used # netmask instead of cidr_netmask. So, don't remove this aliasing code! if [ ! -z "$OCF_RESKEY_netmask" -a -z "$OCF_RESKEY_cidr_netmask" ] then OCF_RESKEY_cidr_netmask=$OCF_RESKEY_netmask export OCF_RESKEY_cidr_netmask fi case $1 in meta-data) meta_data;; start) ip_validate_all && ip_start;; stop) ip_stop;; status) ip_status;; monitor) ip_monitor;; validate-all) ip_validate_all;; usage) usage $OCF_SUCCESS;; *) usage $OCF_ERR_UNIMPLEMENTED;; esac exit $? diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 index bb4eba085..e018fa1bb 100644 --- a/heartbeat/IPaddr2 +++ b/heartbeat/IPaddr2 @@ -1,849 +1,849 @@ #!/bin/sh # # $Id: IPaddr2.in,v 1.24 2006/08/09 13:01:54 lars Exp $ # # OCF Resource Agent compliant IPaddr2 script. # # Based on work by Tuomo Soini, ported to the OCF RA API by Lars # Marowsky-Brée. Implements Cluster Alias IP functionality too. # # Cluster Alias IP cleanup, fixes and testing by Michael Schwartzkopff # # # Copyright (c) 2003 Tuomo Soini # Copyright (c) 2004-2006 SUSE LINUX AG, Lars Marowsky-Brée # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # Further, this software is distributed without any warranty that it is # free of the rightful claim of any third person regarding infringement # or the like. Any license provided herein, whether implied or # otherwise, applies only to this software file. Patent licenses, if # any, provided herein do not apply to combinations of this program with # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. # # # TODO: # - There ought to be an ocf_run_cmd function which does all logging, # timeout handling etc for us # - Make this the standard IP address agent on Linux; the other # platforms simply should ignore the additional parameters OR can use # the legacy heartbeat resource script... # - Check LVS <-> clusterip incompatibilities. # # OCF parameters are as below # OCF_RESKEY_ip # OCF_RESKEY_broadcast # OCF_RESKEY_nic # OCF_RESKEY_cidr_netmask # OCF_RESKEY_iflabel # OCF_RESKEY_mac # OCF_RESKEY_clusterip_hash # OCF_RESKEY_arp_interval # OCF_RESKEY_arp_count # OCF_RESKEY_arp_bg # OCF_RESKEY_arp_mac # # OCF_RESKEY_CRM_meta_clone # OCF_RESKEY_CRM_meta_clone_max ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs SENDARP=$HA_BIN/send_arp FINDIF=$HA_BIN/findif VLDIR=$HA_RSCTMP/IPaddr SENDARPPIDDIR=$HA_RSCTMP/send_arp CIP_lockfile=$HA_RSCTMP/IPaddr2-CIP-${OCF_RESKEY_ip} ####################################################################### meta_data() { cat < 1.0 This Linux-specific resource manages IP alias IP addresses. It can add an IP alias, or remove one. In addition, it can implement Cluster Alias IP functionality if invoked as a clone resource. Manages virtual IPv4 addresses The IPv4 address to be configured in dotted quad notation, for example "192.168.1.1". IPv4 address The base network interface on which the IP address will be brought online. If left empty, the script will try and determine this from the routing table. Do NOT specify an alias interface in the form eth0:1 or anything here; rather, specify the base interface only. Network interface The netmask for the interface in CIDR format (e.g., 24 and not 255.255.255.0) If unspecified, the script will also try to determine this from the routing table. CIDR netmask Broadcast address associated with the IP. If left empty, the script will determine this from the netmask. Broadcast address You can specify an additional label for your IP address here. This label is appended to your interface name. If a label is specified in nic name, this parameter has no effect. Interface label Enable support for LVS Direct Routing configurations. In case a IP address is stopped, only move it to the loopback device to allow the local node to continue to service requests, but no longer advertise it on the network. Enable support for LVS DR Set the interface MAC address explicitly. Currently only used in case of the Cluster IP Alias. Leave empty to chose automatically. Cluster IP MAC address Specify the hashing algorithm used for the Cluster IP functionality. Cluster IP hashing function If true, add the clone ID to the supplied value of ip to create a unique address to manage Create a unique address for cloned instances Specify the interval between unsolicited ARP packets in milliseconds. ARP packet interval in ms Number of unsolicited ARP packets to send. ARP packet count Whether or not to send the arp packets in the background. ARP from background MAC address to send the ARP packets too. You really shouldn't be touching this. ARP MAC - - + + END exit $OCF_SUCCESS } ip_init() { if [ X`uname -s` != "XLinux" ]; then ocf_log err "IPaddr2 only supported Linux." exit $OCF_ERR_INSTALLED fi if case $__OCF_ACTION in start|stop) ocf_is_root;; *) true;; esac then : YAY! else ocf_log err "You must be root for $__OCF_ACTION operation." exit $OCF_ERR_PERM fi BASEIP="$OCF_RESKEY_ip" BRDCAST="$OCF_RESKEY_broadcast" NIC="$OCF_RESKEY_nic" # Note: We had a version out there for a while which used # netmask instead of cidr_netmask. Don't remove this aliasing code! if [ ! -z "$OCF_RESKEY_netmask" -a -z "$OCF_RESKEY_cidr_netmask" ] then OCF_RESKEY_cidr_netmask=$OCF_RESKEY_netmask export OCF_RESKEY_cidr_netmask fi NETMASK="$OCF_RESKEY_cidr_netmask" IFLABEL="$OCF_RESKEY_iflabel" IF_MAC="$OCF_RESKEY_mac" LVS_SUPPORT=0 if [ x"${OCF_RESKEY_lvs_support}" = x"true" \ -o x"${OCF_RESKEY_lvs_support}" = x"on" \ -o x"${OCF_RESKEY_lvs_support}" = x"1" ]; then LVS_SUPPORT=1 fi IP_INC_GLOBAL=${OCF_RESKEY_CRM_meta_clone_max:-1} IP_INC_NO=`expr ${OCF_RESKEY_CRM_meta_clone:-0} + 1` IP_CIP_HASH="${OCF_RESKEY_clusterip_hash:-'sourceip-sourceport'}" if [ $LVS_SUPPORT -gt 0 ] && [ $IP_INC_GLOBAL -gt 1 ]; then ocf_log err "LVS and load sharing do not go together well" - exit OCF_ERR_ARGS + exit $OCF_ERR_ARGS fi ARP_INTERVAL_MS=${OCF_RESKEY_arp_interval:-200} ARP_REPEAT=${OCF_RESKEY_arp_count:-5} ARP_BACKGROUND=${OCF_RESKEY_arp_bg:-yes} ARP_NETMASK=${OCF_RESKEY_arp_mac:-ffffffffffff} if ocf_is_decimal "$IP_INC_GLOBAL" && [ $IP_INC_GLOBAL -gt 0 ]; then : else ocf_log err "Invalid OCF_RESKEY_incarnations_max_global [$IP_INC_GLOBAL], should be positive integer" exit $OCF_ERR_ARGS fi # Validation is performed in ip_validate()... # # $FINDIF now takes its parameters from the environment # if NICINFO=`$FINDIF -C` then NICINFO=`echo $NICINFO | sed -e 's/netmask\ //;s/broadcast\ //'` NIC=`echo "$NICINFO" | cut -d" " -f1` NETMASK=`echo "$NICINFO" | cut -d" " -f2` BRDCAST=`echo "$NICINFO" | cut -d" " -f3` else ocf_log err "[$FINDIF -C] failed" exit $OCF_ERR_ARGS fi SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$BASEIP" case $NIC in *:*) IFLABEL=$NIC NIC=`echo $NIC | sed 's/:.*//'` ;; *) if [ -n "$IFLABEL" ]; then IFLABEL=${NIC}:${IFLABEL} fi ;; esac IP_CIP= if [ "$IP_INC_GLOBAL" -gt 1 ]; then IP_CIP="yes" if [ -z "$IF_MAC" ]; then # Choose a MAC # 1. Concatenate some input together # 2. This doesn't need to be a cryptographically # secure hash. # 3. Drop everything after the first 6 octets (12 chars) # 4. Delimit the octets with ':' # 5. Make sure the first octet is odd, # so the result is a multicast MAC IF_MAC=`echo $BASEIP $NETMASK $BRDCAST | \ md5sum | \ sed -e 's#\(............\).*#\1#' \ -e 's#..#&:#g; s#:$##' \ -e 's#^\(.\)[02468aAcCeE]#\11#'` fi IP_CIP_FILE="/proc/net/ipt_CLUSTERIP/$BASEIP" fi } # # Find out which interface serves the given IP address # The argument is an IP address, and its output # is an interface name (e.g., "eth0"). # find_interface() { # # List interfaces but exclude FreeS/WAN ipsecN virtual interfaces # local iface=`$IP2UTIL -o -f inet addr show | grep "\ $BASEIP/" \ | cut -d ' ' -f2 | grep -v '^ipsec[0-9][0-9]*$'` echo $iface return 0 } # # Delete an interface # delete_interface () { ipaddr="$1" iface="$2" netmask="$3" CMD="$IP2UTIL -f inet addr delete $ipaddr/$netmask dev $iface" ocf_log info "$CMD" $CMD if [ $? -ne 0 ]; then return $OCF_ERR_GENERIC fi CMD="$IP2UTIL -o -f inet addr show $iface" ocf_log info "$CMD" ADDR=`$CMD` if [ $? -ne 0 -o ! -z "$ADDR" ]; then return $? fi CMD="$IP2UTIL link set $iface down" ocf_log info "$CMD" $CMD return $? } # # Add an interface # add_interface () { ipaddr="$1" netmask="$2" broadcast="$3" iface="$4" label="$5" CMD="$IP2UTIL -f inet addr add $ipaddr/$netmask brd $broadcast dev $iface" if [ ! -z "$label" ]; then CMD="$CMD label $label" fi ocf_log info "$CMD" $CMD if [ $? -ne 0 ]; then return $OCF_ERR_GENERIC fi CMD="$IP2UTIL link set $iface up" ocf_log info "$CMD" $CMD return $? } # # Delete a route # delete_route () { prefix="$1" iface="$2" CMD="$IP2UTIL route delete $prefix dev $iface" ocf_log info "$CMD" $CMD return $? } # On Linux systems the (hidden) loopback interface may # conflict with the requested IP address. If so, this # unoriginal code will remove the offending loopback address # and save it in VLDIR so it can be added back in later # when the IPaddr is released. # # TODO: This is very ugly and should be controlled by an additional # instance parameter. Or even: multi-state, with the IP only being # "active" on the master!? # remove_conflicting_loopback() { ipaddr="$1" netmask="$2" broadcast="$3" ifname="$4" ocf_log info "Removing conflicting loopback $ifname." if [ -d "$VLDIR/" ] || mkdir -p "$VLDIR/"; then : Directory $VLDIR now exists else ocf_log err "Could not create \"$VLDIR/\" conflicting" \ " loopback $ifname cannot be restored." fi if echo "$ipaddr $netmask $broadcast $ifname" > "$VLDIR/$ipaddr" then : Saved loopback information in $VLDIR/$ipaddr else ocf_log err "Could not save conflicting loopback $ifname." \ "it will not be restored." fi delete_interface "$ipaddr" "$ifname" "$netmask" # Forcibly remove the route (if it exists) to the loopback. delete_route "$ipaddr" "$ifname" } # # On Linux systems the (hidden) loopback interface may # need to be restored if it has been taken down previously # by remove_conflicting_loopback() # restore_loopback() { ipaddr="$1" if [ -s "$VLDIR/$ipaddr" ]; then ifinfo=`cat "$VLDIR/$ipaddr"` ocf_log info "Restoring loopback IP Address " \ "$ifinfo." add_interface $ifinfo rm -f "$VLDIR/$ipaddr" fi } # # Run send_arp to note peers about new mac address # run_send_arp() { ARGS="-i $ARP_INTERVAL_MS -r $ARP_REPEAT -p $SENDARPPIDFILE $NIC $BASEIP auto not_used not_used" if [ "x$IP_CIP" = "xyes" ] ; then if [ x = "x$IF_MAC" ] ; then MY_MAC=auto else MY_MAC=`echo ${IF_MAC} | sed -e 's/://'` fi ARGS="-i $ARP_INTERVAL_MS -r $ARP_REPEAT -p $SENDARPPIDFILE $NIC $BASEIP $MY_MAC not_used not_used" fi ocf_log info "$SENDARP $ARGS" case $ARP_BACKGROUND in yes) ($SENDARP $ARGS || ocf_log err "Could not send gratuitous arps" &) >&2 ;; *) $SENDARP $ARGS || ocf_log err "Could not send gratuitous arps" ;; esac } # # Run ipoibarping to note peers about new Infiniband address # run_send_ib_arp() { SENDIBARP="/sbin/ipoibarping" if [ ! -x $SENDIBARP ] ; then ocf_log err "Could not send gratuitous Infiniband arps: file not found: $SENDIBPARP" return fi ARGS="-q -c $ARP_REPEAT -U -I $NIC $BASEIP" ocf_log info "$SENDIBARP $ARGS" case $ARP_BACKGROUND in yes) ($SENDIBARP $ARGS || ocf_log err "Could not send gratuitous arps" &) >&2 ;; *) $SENDIBARP $ARGS || ocf_log err "Could not send gratuitous arps" ;; esac } # Do we already serve this IP address? # # returns: # ok = served (for CIP: + hash bucket) # partial = served and no hash bucket (CIP only) # no = nothing # ip_served() { cur_nic="`find_interface $BASEIP`" if [ -z "$cur_nic" ]; then echo "no" return 0 fi if [ -z "$IP_CIP" ]; then case $cur_nic in lo*) if [ "$LVS_SUPPORT" = "1" ]; then echo "no" return 0 fi ;; esac echo "ok" return 0 fi # Special handling for the CIP: if egrep -q "(^|,)${IP_INC_NO}(,|$)" $IP_CIP_FILE ; then echo "ok" return 0 else echo "partial" return 0 fi exit $OCF_ERR_GENERIC } ####################################################################### ip_usage() { cat <$IP_CIP_FILE fi if [ "$ip_status" = "no" ]; then if [ "$LVS_SUPPORT" = "1" ]; then case `find_interface $BASEIP` in lo*) remove_conflicting_loopback $BASEIP 32 255.255.255.255 lo ;; esac fi add_interface $BASEIP $NETMASK $BRDCAST $NIC $IFLABEL if [ $? -ne 0 ]; then ocf_log err "$CMD failed." exit $OCF_ERR_GENERIC fi fi case $NIC in lo*) : no need to run send_arp on loopback ;; ib*) run_send_ib_arp ;; *) if [ -x $SENDARP ]; then run_send_arp fi ;; esac exit $OCF_SUCCESS } ip_stop() { local ip_del_if="yes" if [ -n "$IP_CIP" ]; then # Cluster IPs need special processing when the last bucket # is removed from the node... take a lock to make sure only one # process executes that code ocf_take_lock $CIP_lockfile ocf_release_lock_on_exit $CIP_lockfile fi if [ -f "$SENDARPPIDFILE" ] ; then kill `cat "$SENDARPPIDFILE"` if [ $? -ne 0 ]; then ocf_log warn "Could not kill previously running send_arp for $BASEIP" else ocf_log info "killed previously running send_arp for $BASEIP" rm -f "$SENDARPPIDFILE" fi fi local ip_status=`ip_served` if [ $ip_status = "no" ]; then : Requested interface not in use exit $OCF_SUCCESS fi if [ -n "$IP_CIP" ]; then if [ $ip_status = "partial" ]; then exit $OCF_SUCCESS fi echo "-$IP_INC_NO" >$IP_CIP_FILE if [ "x$(cat $IP_CIP_FILE)" = "x" ]; then ocf_log info $BASEIP, $IP_CIP_HASH i=1 while [ $i -le $IP_INC_GLOBAL ]; do ocf_log info $i $IPTABLES -D INPUT -d $BASEIP -i $NIC -j CLUSTERIP \ --new \ --clustermac $IF_MAC \ --total-nodes $IP_INC_GLOBAL \ --local-node $i \ --hashmode $IP_CIP_HASH i=`expr $i + 1` done else ip_del_if="no" fi fi if [ "$ip_del_if" = "yes" ]; then delete_interface $BASEIP $NIC $NETMASK if [ $? -ne 0 ]; then exit $OCF_ERR_GENERIC fi if [ "$LVS_SUPPORT" = 1 ]; then restore_loopback "$BASEIP" fi fi exit $OCF_SUCCESS } ip_monitor() { # TODO: Implement more elaborate monitoring like checking for # interface health maybe via a daemon like FailSafe etc... local ip_status=`ip_served` case $ip_status in ok) return $OCF_SUCCESS ;; partial|no) exit $OCF_NOT_RUNNING ;; *) # Errors on this interface? return $OCF_ERR_GENERIC ;; esac } ip_validate() { check_binary $IP2UTIL if [ -n "$IP_CIP" ]; then check_binary $IPTABLES check_binary $MODPROBE fi ip_init # $BASEIP, $NETMASK, $NIC , $IP_INC_GLOBAL, and $BRDCAST have been checked within ip_init, # do not bother here. if ocf_is_decimal "$ARP_INTERVAL_MS" && [ $ARP_INTERVAL_MS -gt 0 ]; then : else ocf_log err "Invalid OCF_RESKEY_arp_interval [$ARP_INTERVAL_MS]" exit $OCF_ERR_ARGS fi if ocf_is_decimal "$ARP_REPEAT" && [ $ARP_REPEAT -gt 0 ]; then : else ocf_log err "Invalid OCF_RESKEY_arp_count [$ARP_REPEAT]" exit $OCF_ERR_ARGS fi if [ -n "$IP_CIP" ]; then local valid=1 case $IP_CIP_HASH in sourceip|sourceip-sourceport|sourceip-sourceport-destport) ;; *) ocf_log err "Invalid OCF_RESKEY_clusterip_hash [$IP_CIP_HASH]" exit $OCF_ERR_ARGS ;; esac if [ "$LVS_SUPPORT" = 1 ]; then ecf_log err "LVS and load sharing not advised to try" exit $OCF_ERR_ARGS fi case $IF_MAC in [0-9a-zA-Z][1379bBdDfF][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z][!0-9a-zA-Z][0-9a-zA-Z][0-9a-zA-Z]) ;; *) valid=0 ;; esac if [ $valid -eq 0 ]; then ocf_log err "Invalid IF_MAC [$IF_MAC]" exit $OCF_ERR_ARGS fi fi } case "$OCF_RESKEY_unique_clone_address" in true|TRUE|True|yes|YES|Yes|1) prefix=`echo $OCF_RESKEY_ip | awk -F. '{print $1"."$2"."$3}'` suffix=`echo $OCF_RESKEY_ip | awk -F. '{print $4}'` suffix=`expr ${OCF_RESKEY_CRM_meta_clone:-0} + $suffix` OCF_RESKEY_ip="$prefix.$suffix" ;; *) ;; esac case $__OCF_ACTION in meta-data) meta_data ;; usage|help) ip_usage exit $OCF_SUCCESS ;; esac ip_validate case $__OCF_ACTION in start) ip_start ;; stop) ip_stop ;; status) ip_status=`ip_served` if [ $ip_status = "ok" ]; then echo "running" exit $OCF_SUCCESS else echo "stopped" exit $OCF_NOT_RUNNING fi ;; monitor) ip_monitor ;; validate-all) ;; *) ip_usage exit $OCF_ERR_UNIMPLEMENTED ;; esac diff --git a/heartbeat/IPsrcaddr b/heartbeat/IPsrcaddr index cd116d56e..4b0a47144 100644 --- a/heartbeat/IPsrcaddr +++ b/heartbeat/IPsrcaddr @@ -1,466 +1,466 @@ #!/bin/sh # # Description: IPsrcaddr - Preferred source address modification # # Author: John Sutton # Support: linux-ha@lists.linux-ha.org # License: GNU General Public License (GPL) # Copyright: SCL Internet # # Based on the IPaddr script. # # This script manages the preferred source address associated with # packets which originate on the localhost and are routed through the # default route. By default, i.e. without the use of this script or # similar, these packets will carry the IP of the primary i.e. the # non-aliased interface. This can be a nuisance if you need to ensure # that such packets carry the same IP irrespective of which host in # a redundant cluster they actually originate from. # # It can add a preferred source address, or remove one. # # usage: IPsrcaddr {start|stop|status|monitor|validate-all|meta-data} # # The "start" arg adds a preferred source address. # # Surprisingly, the "stop" arg removes it. :-) # # NOTES: # # 1) There must be one and not more than 1 default route! Mainly because # I can't see why you should have more than one. And if there is more # than one, we would have to box clever to find out which one is to be # modified, or we would have to pass its identity as an argument. # # 2) The script depends on Alexey Kuznetsov's ip utility from the # iproute aka iproute2 package. # # 3) No checking is done to see if the passed in IP address can # reasonably be associated with the interface on which the default # route exists. So unless you want to deliberately spoof your source IP, # check it! Normally, I would expect that your haresources looks # something like: # # nodename ip1 ip2 ... ipN IPsrcaddr::ipX # # where ipX is one of the ip1 to ipN. # # OCF parameters are as below: # OCF_RESKEY_ipaddress ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### USAGE="usage: $0 {start|stop|status|monitor|validate-all|meta-data}"; CMDSHOW="$IP2UTIL route show to exact 0/0" CMDCHANGE="$IP2UTIL route change to " SYSTYPE="`uname -s`" usage() { echo $USAGE >&2 } meta_data() { cat < 1.0 Resource script for IPsrcaddr. It manages the preferred source address modification. IPsrcaddr resource agent The IP address. IP address - + END } errorexit() { ocf_log err "$*" exit $OCF_ERR_GENERIC } # # We can distinguish 3 cases: no preferred source address, a # preferred source address exists which matches that specified, and one # exists but doesn't match that specified. srca_read() returns 1,0,2 # respectively. # # The output of route show is something along the lines of: # # default via X.X.X.X dev eth1 src Y.Y.Y.Y # # where the src clause "src Y.Y.Y.Y" may or may not be present WS="[`echo -en ' \t'`]" OCTET="[0-9]\{1,3\}" IPADDR="\($OCTET\.\)\{3\}$OCTET" SRCCLAUSE="src$WS$WS*\($IPADDR\)" MATCHROUTE="\(.*${WS}\)\($SRCCLAUSE\)\($WS.*\|$\)" srca_read() { # Capture the default route - doublequotes prevent word splitting... DEFROUTE="`$CMDSHOW`" || errorexit "command '$CMDSHOW' failed" # ... so we can make sure there is only 1 default route [ 1 -eq `echo "$DEFROUTE" | wc -l` ] || \ errorexit "more than 1 default route exists" # But there might still be no default route [ -z "$DEFROUTE" ] && errorexit "no default route exists" # Sed out the source ip address if it exists SRCIP=`echo $DEFROUTE | sed -n "s/$MATCHROUTE/\3/p"` # and what remains after stripping out the source ip address clause ROUTE_WO_SRC=`echo $DEFROUTE | sed "s/$MATCHROUTE/\1\5/"` [ -z "$SRCIP" ] && return 1 [ $SRCIP = $1 ] && return 0 return 2 } # # Add (or change if it already exists) the preferred source address # The exit code should conform to LSB exit codes. # srca_start() { srca_read $1 $CMDCHANGE $ROUTE_WO_SRC src $1 || \ errorexit "command '$CMDCHANGE $ROUTE_WO_SRC src $1' failed" return $? } # # Remove (if it exists) the preferred source address. # If one exists but it's not the same as the one specified, that's # an error. Maybe that's the wrong behaviour because if this fails # then when IPaddr releases the associated interface (if there is one) # your default route will also get dropped ;-( # The exit code should conform to LSB exit codes. # srca_stop() { srca_read $1 rc=$? if [ $rc = 1 ]; then # We do not have a preferred source address for now ocf_log info "No preferred source address defined, nothing to stop" exit $OCF_SUCCESS fi [ $rc = 2 ] && errorexit "The address you specified to stop does not match the preferred source address" $CMDCHANGE $ROUTE_WO_SRC || \ errorexit "command '$CMDCHANGE $ROUTE_WO_SRC' failed" return $? } srca_status() { srca_read $1 case $? in 0) echo "OK" return $OCF_SUCCESS;; 1) echo "No preferred source address defined" return $OCF_NOT_RUNNING;; 2) echo "Preferred source address has incorrect value" return $OCF_ERR_GENERIC;; esac } # A not reliable IP address checking function, which only picks up those _obvious_ violations... # # It accepts IPv4 address in dotted quad notation, for example "192.168.1.1" # # 100% confidence whenever it reports "negative", # but may get false "positive" answer. # CheckIP() { ip="$1" case $ip in *[!0-9.]*) #got invalid char false;; .*|*.) #begin or end by ".", which is invalid false;; *..*) #consecutive ".", which is invalid false;; *.*.*.*.*) #four decimal dots, which is too many false;; *.*.*.*) #exactly three decimal dots, candidate, evaluate each field local IFS=. set -- $ip if ( [ $1 -le 254 ] && [ $2 -le 254 ] && [ $3 -le 254 ] && [ $4 -le 254 ] ) then if [ $1 -eq 127 ]; then ocf_log err "IP address [$ip] is a loopback address, thus can not be preferred source address" exit $OCF_ERR_ARGS fi else true fi # return $OCF_SUCCESS ;; *) #less than three decimal dots false;; esac return $? # This return is unnecessary, this comment too :) } # # Find out which interface or alias serves the given IP address # The argument is an IP address, and its output # is an (aliased) interface name (e.g., "eth0" and "eth0:0"). # find_interface_solaris() { $IFCONFIG $IFCONFIG_A_OPT | $AWK '{if ($0 ~ /.*: / && NR > 1) {print "\n"$0} else {print}}' | while read ifname linkstuff do : ifname = $ifname read inet addr junk : inet = $inet addr = $addr while read line && [ "X$line" != "X" ] do : Nothing done # This doesn't look right for a box with multiple NICs. # It looks like it always selects the first interface on # a machine. Yet, we appear to use the results for this case too... ifname=`echo "$ifname" | sed s'%:*$%%'` case $addr in addr:$BASEIP) echo $ifname; return $OCF_SUCCESS;; $BASEIP) echo $ifname; return $OCF_SUCCESS;; esac done return $OCF_ERR_GENERIC } # # Find out which interface or alias serves the given IP address # The argument is an IP address, and its output # is an (aliased) interface name (e.g., "eth0" and "eth0:0"). # find_interface_generic() { $IFCONFIG $IFCONFIG_A_OPT | while read ifname linkstuff do : Read gave us ifname = $ifname read inet addr junk : Read gave us inet = $inet addr = $addr while read line && [ "X$line" != "X" ] do : Nothing done case "$SYSTYPE" in *BSD) $IFCONFIG | grep "$BASEIP" -B`$IFCONFIG | grep -c inet` | grep "UP," | cut -d ":" -f 1 return 0;; *) : "comparing $BASEIP to $addr (from ifconfig)" case $addr in addr:$BASEIP) echo $ifname; return $OCF_SUCCESS;; $BASEIP) echo $ifname; return $OCF_SUCCESS;; esac continue;; esac done return $OCF_ERR_GENERIC } # # Find out which interface or alias serves the given IP address # The argument is an IP address, and its output # is an (aliased) interface name (e.g., "eth0" and "eth0:0"). # find_interface() { case "$SYSTYPE" in SunOS) IF=`find_interface_solaris $BASEIP` ;; *) IF=`find_interface_generic $BASEIP` ;; esac echo $IF return $OCF_SUCCESS; } ip_status() { BASEIP="$1" case "$SYSTYPE" in Darwin) # Treat Darwin the same as the other BSD variants (matched as *BSD) SYSTYPE="${SYSTYPE}BSD" ;; *) ;; esac case "$SYSTYPE" in *BSD) $IFCONFIG $IFCONFIG_A_OPT | grep "inet.*[: ]$BASEIP " >/dev/null 2>&1 if [ $? = 0 ]; then return $OCF_SUCCESS else return $OCF_NOT_RUNNING fi;; Linux|SunOS) IF=`find_interface "$BASEIP"` # echo $IF if [ -z "$IF" ]; then return $OCF_NOT_RUNNING fi case $IF in lo*) ocf_log err "IP address [$BASEIP] is served by loopback, thus can not be preferred source address" exit $OCF_ERR_ARGS ;; *)return $OCF_SUCCESS;; esac ;; *) if [ -z "$IF" ]; then return $OCF_NOT_RUNNING else return $OCF_SUCCESS fi;; esac } srca_validate_all() { check_binary $AWK check_binary $IPROUTE check_binary $IFCONFIG # The IP address should be in good shape if CheckIP "$ipaddress"; then : else ocf_log err "Invalid IP address [$ipaddress]" exit $OCF_ERR_ARGS fi # We should serve this IP address of course if ip_status "$ipaddress"; then : else ocf_log err "We are not serving [$ipaddress], hence can not make it a preferred source address" exit $OCF_ERR_ARGS fi } if ( [ $# -ne 1 ] ) then usage exit $OCF_ERR_ARGS fi # These operations do not require the OCF instance parameters to be set case $1 in meta-data) meta_data exit $OCF_SUCCESS ;; usage) usage exit $OCF_SUCCESS ;; *) ;; esac if [ -z "$OCF_RESKEY_ipaddress" ] then # usage ocf_log err "Please set OCF_RESKEY_ipaddress to the preferred source IP address!" exit $OCF_ERR_ARGS fi ipaddress="$OCF_RESKEY_ipaddress" case $1 in start) srca_start $ipaddress ;; stop) srca_stop $ipaddress ;; status) srca_status $ipaddress ;; monitor) srca_status $ipaddress ;; validate-all) srca_validate_all ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $? # # Version 0.3 2002/11/04 17:00:00 John Sutton # Name changed from IPsrcroute to IPsrcaddr and now reports errors # using ha_log rather than on stderr. # # Version 0.2 2002/11/02 17:00:00 John Sutton # Changed status output to "OK" to satisfy ResourceManager's # we_own_resource() function. # # Version 0.1 2002/11/01 17:00:00 John Sutton # First effort but does the job? # diff --git a/heartbeat/IPv6addr.c b/heartbeat/IPv6addr.c index eb03b8932..e8f444421 100644 --- a/heartbeat/IPv6addr.c +++ b/heartbeat/IPv6addr.c @@ -1,866 +1,866 @@ /* * This program manages IPv6 address with OCF Resource Agent standard. * * Author: Huang Zhen * Copyright (c) 2004 International Business Machines * * This library 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 library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU 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. */ /* * It can add an IPv6 address, or remove one. * * Usage: IPv6addr {start|stop|status|monitor|meta-data} * * The "start" arg adds an IPv6 address. * The "stop" arg removes one. * The "status" arg shows whether the IPv6 address exists * The "monitor" arg shows whether the IPv6 address can be pinged (ICMPv6 ECHO) * The "meta_data" arg shows the meta data(XML) */ /* * ipv6-address: * * currently the following forms are legal: * address * address/prefix * * E.g. * 3ffe:ffff:0:f101::3 * 3ffe:ffff:0:f101::3/64 * * It should be passed by environment variant: * OCF_RESKEY_ipv6addr=3ffe:ffff:0:f101::3 * */ /* * start: * 1.IPv6addr will choice a proper interface for the new address. * 2.Then assign the new address to the interface. * 3.Wait until the new address is available (reply ICMPv6 ECHO packet) * 4.Send out the unsolicited advertisements. * * return 0(OCF_SUCCESS) for success * return 1(OCF_ERR_GENERIC) for failure * return 2(OCF_ERR_ARGS) for invalid or excess argument(s) * * * stop: * remove the address from the inferface. * * return 0(OCF_SUCCESS) for success * return 1(OCF_ERR_GENERIC) for failure * return 2(OCF_ERR_ARGS) for invalid or excess argument(s) * * status: * return the status of the address. only check whether it exists. * * return 0(OCF_SUCCESS) for existing * return 1(OCF_NOT_RUNNING) for not existing * return 2(OCF_ERR_ARGS) for invalid or excess argument(s) * * * monitor: * ping the address by ICMPv6 ECHO request. * * return 0(OCF_SUCCESS) for response correctly. * return 1(OCF_NOT_RUNNING) for no response. * return 2(OCF_ERR_ARGS) for invalid or excess argument(s) */ #include #include #include #include #include #include #include #include #define PIDFILE_BASE HA_VARRUNDIR "/IPv6addr-" /* 0 No error, action succeeded completely 1 generic or unspecified error (current practice) The "monitor" operation shall return this for a crashed, hung or otherwise non-functional resource. 2 invalid or excess argument(s) Likely error code for validate-all, if the instance parameters do not validate. Any other action is free to also return this exit status code for this case. 3 unimplemented feature (for example, "reload") 4 user had insufficient privilege 5 program is not installed 6 program is not configured 7 program is not running 8 resource is running in "master" mode and fully operational 9 resource is in "master" mode but in a failed state */ #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 const char* IF_INET6 = "/proc/net/if_inet6"; const char* APP_NAME = "IPv6addr"; const char* START_CMD = "start"; const char* STOP_CMD = "stop"; const char* STATUS_CMD = "status"; const char* MONITOR_CMD = "monitor"; const char* ADVT_CMD = "advt"; const char* RECOVER_CMD = "recover"; const char* RELOAD_CMD = "reload"; const char* META_DATA_CMD = "meta-data"; const char* VALIDATE_CMD = "validate-all"; char BCAST_ADDR[] = "ff02::1"; const int UA_REPEAT_COUNT = 5; const int QUERY_COUNT = 5; struct in6_ifreq { struct in6_addr ifr6_addr; uint32_t ifr6_prefixlen; unsigned int ifr6_ifindex; }; static int start_addr6(struct in6_addr* addr6, int prefix_len); static int stop_addr6(struct in6_addr* addr6, int prefix_len); static int status_addr6(struct in6_addr* addr6, int prefix_len); static int monitor_addr6(struct in6_addr* addr6, int prefix_len); static int advt_addr6(struct in6_addr* addr6, int prefix_len); static int meta_data_addr6(void); static void usage(const char* self); int write_pid_file(const char *pid_file); int create_pid_directory(const char *pid_file); static void byebye(int nsig); static char* scan_if(struct in6_addr* addr_target, int* plen_target, int use_mask); static char* find_if(struct in6_addr* addr_target, int* plen_target); static char* get_if(struct in6_addr* addr_target, int* plen_target); static int assign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name); static int unassign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name); int is_addr6_available(struct in6_addr* addr6); static int send_ua(struct in6_addr* src_ip, char* if_name); int main(int argc, char* argv[]) { char pid_file[256]; char* ipv6addr; int ret; char* cp; int prefix_len; struct in6_addr addr6; /* Check the count of parameters first */ if (argc < 2) { usage(argv[0]); return OCF_ERR_ARGS; } /* set termination signal */ siginterrupt(SIGTERM, 1); signal(SIGTERM, byebye); /* open system log */ cl_log_set_entity(APP_NAME); cl_log_set_facility(HA_LOG_FACILITY); /* the meta-data dont need any parameter */ if (0 == strncmp(META_DATA_CMD, argv[1], strlen(META_DATA_CMD))) { ret = meta_data_addr6(); return OCF_SUCCESS; } /* check the OCF_RESKEY_ipv6addr parameter, should be an IPv6 address */ ipv6addr = getenv("OCF_RESKEY_ipv6addr"); if (ipv6addr == NULL) { cl_log(LOG_ERR, "Please set OCF_RESKEY_ipv6addr to the IPv6 address you want to manage."); usage(argv[0]); return OCF_ERR_ARGS; } if ((cp = strchr(ipv6addr, '/'))) { prefix_len = atol(cp + 1); if ((prefix_len < 0) || (prefix_len > 128)) { cl_log(LOG_ERR, "Invalid prefix_len [%s], should be an integer in [0, 128]", cp+1); usage(argv[0]); return OCF_ERR_ARGS; } *cp=0; } else { prefix_len = 0; } if (inet_pton(AF_INET6, ipv6addr, &addr6) <= 0) { cl_log(LOG_ERR, "Invalid IPv6 address [%s]", ipv6addr); usage(argv[0]); return OCF_ERR_ARGS; } /* Check whether this system supports IPv6 */ if (access(IF_INET6, R_OK)) { cl_log(LOG_ERR, "No support for INET6 on this system."); return OCF_ERR_GENERIC; } /* create the pid file so we can make sure that only one IPv6addr * for this address is running */ if (snprintf(pid_file, sizeof(pid_file), "%s%s", PIDFILE_BASE, ipv6addr) >= (int)sizeof(pid_file)) { cl_log(LOG_ERR, "Pid file truncated"); return OCF_ERR_GENERIC; } if (write_pid_file(pid_file) < 0) { return OCF_ERR_GENERIC; } /* switch the command */ if (0 == strncmp(START_CMD,argv[1], strlen(START_CMD))) { ret = start_addr6(&addr6, prefix_len); }else if (0 == strncmp(STOP_CMD,argv[1], strlen(STOP_CMD))) { ret = stop_addr6(&addr6, prefix_len); }else if (0 == strncmp(STATUS_CMD,argv[1], strlen(STATUS_CMD))) { ret = status_addr6(&addr6, prefix_len); }else if (0 ==strncmp(MONITOR_CMD,argv[1], strlen(MONITOR_CMD))) { ret = monitor_addr6(&addr6, prefix_len); }else if (0 ==strncmp(RELOAD_CMD,argv[1], strlen(RELOAD_CMD))) { ret = OCF_ERR_UNIMPLEMENTED; }else if (0 ==strncmp(RECOVER_CMD,argv[1], strlen(RECOVER_CMD))) { ret = OCF_ERR_UNIMPLEMENTED; }else if (0 ==strncmp(VALIDATE_CMD,argv[1], strlen(VALIDATE_CMD))) { /* ipv6addr has been validated by inet_pton, hence a valid IPv6 address */ ret = OCF_SUCCESS; }else if (0 ==strncmp(ADVT_CMD,argv[1], strlen(MONITOR_CMD))) { ret = advt_addr6(&addr6, prefix_len); }else{ usage(argv[0]); ret = OCF_ERR_ARGS; } /* release the pid file */ unlink(pid_file); return ret; } int start_addr6(struct in6_addr* addr6, int prefix_len) { int i; char* if_name; if(OCF_SUCCESS == status_addr6(addr6,prefix_len)) { return OCF_SUCCESS; } /* we need to find a proper device to assign the address */ if_name = find_if(addr6, &prefix_len); if (NULL == if_name) { cl_log(LOG_ERR, "no valid mecahnisms"); return OCF_ERR_GENERIC; } /* Assign the address */ if (0 != assign_addr6(addr6, prefix_len, if_name)) { cl_log(LOG_ERR, "failed to assign the address to %s", if_name); return OCF_ERR_GENERIC; } /* Check whether the address available */ for (i = 0; i < QUERY_COUNT; i++) { if (0 == is_addr6_available(addr6)) { break; } sleep(1); } if (i == QUERY_COUNT) { cl_log(LOG_ERR, "failed to ping the address"); return OCF_ERR_GENERIC; } /* Send unsolicited advertisement packet to neighbor */ for (i = 0; i < UA_REPEAT_COUNT; i++) { send_ua(addr6, if_name); sleep(1); } return OCF_SUCCESS; } int advt_addr6(struct in6_addr* addr6, int prefix_len) { /* First, we need to find a proper device to assign the address */ char* if_name = get_if(addr6, &prefix_len); int i; if (NULL == if_name) { cl_log(LOG_ERR, "no valid mecahnisms"); return OCF_ERR_GENERIC; } /* Send unsolicited advertisement packet to neighbor */ for (i = 0; i < UA_REPEAT_COUNT; i++) { send_ua(addr6, if_name); sleep(1); } return OCF_SUCCESS; } int stop_addr6(struct in6_addr* addr6, int prefix_len) { char* if_name; if(OCF_NOT_RUNNING == status_addr6(addr6,prefix_len)) { return OCF_SUCCESS; } if_name = get_if(addr6, &prefix_len); if (NULL == if_name) { cl_log(LOG_ERR, "no valid mechanisms."); /* I think this should be a success exit according to LSB. */ return OCF_ERR_GENERIC; } /* Unassign the address */ if (0 != unassign_addr6(addr6, prefix_len, if_name)) { cl_log(LOG_ERR, "failed to assign the address to %s", if_name); return OCF_ERR_GENERIC; } return OCF_SUCCESS; } int status_addr6(struct in6_addr* addr6, int prefix_len) { char* if_name = get_if(addr6, &prefix_len); if (NULL == if_name) { return OCF_NOT_RUNNING; } return OCF_SUCCESS; } int monitor_addr6(struct in6_addr* addr6, int prefix_len) { if(0 == is_addr6_available(addr6)) { return OCF_SUCCESS; } return OCF_NOT_RUNNING; } /* Send an unsolicited advertisement packet * Please refer to rfc2461 */ int send_ua(struct in6_addr* src_ip, char* if_name) { int status = -1; libnet_t *l; char errbuf[LIBNET_ERRBUF_SIZE]; struct libnet_in6_addr dst_ip; struct libnet_ether_addr *mac_address; char payload[24]; int ifindex; if ((l=libnet_init(LIBNET_RAW6, if_name, errbuf)) == NULL) { cl_log(LOG_ERR, "libnet_init failure on %s", if_name); goto err; } /* set the outgoing interface */ ifindex = if_nametoindex(if_name); if (setsockopt(libnet_getfd(l), IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) { cl_log(LOG_ERR, "setsockopt(IPV6_MULTICAST_IF): %s", strerror(errno)); goto err; } mac_address = libnet_get_hwaddr(l); if (!mac_address) { cl_log(LOG_ERR, "libnet_get_hwaddr: %s", errbuf); goto err; } dst_ip = libnet_name2addr6(l, BCAST_ADDR, LIBNET_DONT_RESOLVE); memcpy(payload,src_ip->s6_addr,16); payload[16] = 2; /* 2 for Target Link-layer Address */ payload[17] = 1; /* The length of the option */ memcpy(payload+18,mac_address->ether_addr_octet, 6); libnet_seed_prand(l); /* 0x2000: RSO */ libnet_build_icmpv4_echo(136,0,0,0x2000,0,(u_int8_t *)payload ,sizeof(payload), l, LIBNET_PTAG_INITIALIZER); libnet_build_ipv6(0,0,LIBNET_ICMPV6_H + sizeof(payload),IPPROTO_ICMP6, 255,*(struct libnet_in6_addr*)src_ip, dst_ip,NULL,0,l,0); /* Hack: adjust the correct checksum offset. see LF #2034 */ libnet_pblock_record_ip_offset(l, l->total_size); if (libnet_write(l) == -1) { cl_log(LOG_ERR, "libnet_write: %s", libnet_geterror(l)); goto err; } status = 0; err: libnet_destroy(l); return status; } /* find the network interface associated with an address */ char* scan_if(struct in6_addr* addr_target, int* plen_target, int use_mask) { FILE *f; static char devname[21]=""; struct in6_addr addr; struct in6_addr mask; unsigned int plen, scope, dad_status, if_idx; unsigned int addr6p[4]; /* open /proc/net/if_inet6 file */ if ((f = fopen(IF_INET6, "r")) == NULL) { return NULL; } /* Loop for each entry */ while (1) { int i; int n; int s; gboolean same = TRUE; i = fscanf(f, "%08x%08x%08x%08x %02x %02x %02x %02x %20s\n", &addr6p[0], &addr6p[1], &addr6p[2], &addr6p[3], &if_idx, &plen, &scope, &dad_status, devname); if (i == EOF) { break; } else if (i != 9) { cl_log(LOG_INFO, "Error parsing %s, " "perhaps the format has changed\n", IF_INET6); break; } /* Only Global address entry would be considered. * maybe change? */ if (0 != scope) { continue; } /* If specified prefix, only same prefix entry * would be considered. */ if (*plen_target!=0 && plen != *plen_target) { continue; } *plen_target = plen; for (i = 0; i< 4; i++) { addr.s6_addr32[i] = htonl(addr6p[i]); } /* Make the mask based on prefix length */ memset(mask.s6_addr, 0xff, 16); if (use_mask && plen < 128) { n = plen / 32; memset(mask.s6_addr32 + n + 1, 0, (3 - n) * 4); s = 32 - plen % 32; if (s == 32) mask.s6_addr32[n] = 0x0; else mask.s6_addr32[n] = 0xffffffff << s; mask.s6_addr32[n] = htonl(mask.s6_addr32[n]); } /* compare addr and addr_target */ same = TRUE; for (i = 0; i < 4; i++) { if ((addr.s6_addr32[i]&mask.s6_addr32[i]) != (addr_target->s6_addr32[i]&mask.s6_addr32[i])) { same = FALSE; break; } } /* We found it! */ if (same) { fclose(f); return devname; } } fclose(f); return NULL; } /* find a proper network interface to assign the address */ char* find_if(struct in6_addr* addr_target, int* plen_target) { return scan_if(addr_target, plen_target, 1); } /* get the device name and the plen_target of a special address */ char* get_if(struct in6_addr* addr_target, int* plen_target) { return scan_if(addr_target, plen_target, 0); } int assign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name) { struct in6_ifreq ifr6; /* Get socket first */ int fd; struct ifreq ifr; fd = socket(AF_INET6, SOCK_DGRAM, 0); if (fd < 0) { return 1; } /* Query the index of the if */ strcpy(ifr.ifr_name, if_name); if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) { return -1; } /* Assign the address to the if */ ifr6.ifr6_addr = *addr6; ifr6.ifr6_ifindex = ifr.ifr_ifindex; ifr6.ifr6_prefixlen = prefix_len; if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) { return -1; } close (fd); return 0; } int unassign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name) { int fd; struct ifreq ifr; struct in6_ifreq ifr6; /* Get socket first */ fd = socket(AF_INET6, SOCK_DGRAM, 0); if (fd < 0) { return 1; } /* Query the index of the if */ strcpy(ifr.ifr_name, if_name); if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) { return -1; } /* Unassign the address to the if */ ifr6.ifr6_addr = *addr6; ifr6.ifr6_ifindex = ifr.ifr_ifindex; ifr6.ifr6_prefixlen = prefix_len; if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) { return -1; } close (fd); return 0; } #define MINPACKSIZE 64 int is_addr6_available(struct in6_addr* addr6) { struct sockaddr_in6 addr; struct libnet_icmpv6_hdr icmph; u_char outpack[MINPACKSIZE]; int icmp_sock; int ret; struct iovec iov; u_char packet[MINPACKSIZE]; struct msghdr msg; icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); memset(&icmph, 0, sizeof(icmph)); icmph.icmp_type = ICMP6_ECHO; icmph.icmp_code = 0; icmph.icmp_sum = 0; icmph.seq = htons(0); icmph.id = 0; memset(&outpack, 0, sizeof(outpack)); memcpy(&outpack, &icmph, sizeof(icmph)); memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_family = AF_INET6; addr.sin6_port = htons(IPPROTO_ICMPV6); memcpy(&addr.sin6_addr,addr6,sizeof(struct in6_addr)); /* Only the first 8 bytes of outpack are meaningful... */ ret = sendto(icmp_sock, (char *)outpack, sizeof(outpack), 0, (struct sockaddr *) &addr, sizeof(struct sockaddr_in6)); if (0 >= ret) { return -1; } iov.iov_base = (char *)packet; iov.iov_len = sizeof(packet); msg.msg_name = &addr; msg.msg_namelen = sizeof(addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; ret = recvmsg(icmp_sock, &msg, MSG_DONTWAIT); if (0 >= ret) { return -1; } return 0; } static void usage(const char* self) { printf("usage: %s {start|stop|status|monitor|validate-all|meta-data}\n",self); return; } /* Following code is copied from send_arp.c, linux-HA project. */ void byebye(int nsig) { (void)nsig; /* Avoid an "error exit" log message if we're killed */ exit(0); } int create_pid_directory(const char *pid_file) { int status; int return_status = -1; struct stat stat_buf; char* dir; dir = strdup(pid_file); if (!dir) { cl_log(LOG_INFO, "Memory allocation failure: %s", strerror(errno)); return -1; } dirname(dir); status = stat(dir, &stat_buf); if (status < 0 && errno != ENOENT && errno != ENOTDIR) { cl_log(LOG_INFO, "Could not stat pid-file directory " "[%s]: %s", dir, strerror(errno)); goto err; } if (!status) { if (S_ISDIR(stat_buf.st_mode)) { goto out; } cl_log(LOG_INFO, "Pid-File directory exists but is " "not a directory [%s]", dir); goto err; } if (mkdir(dir, S_IRUSR|S_IWUSR|S_IXUSR | S_IRGRP|S_IXGRP) < 0) { cl_log(LOG_INFO, "Could not create pid-file directory " "[%s]: %s", dir, strerror(errno)); goto err; } out: return_status = 0; err: free(dir); return return_status; } int write_pid_file(const char *pid_file) { int pidfilefd; char pidbuf[11]; unsigned long pid; ssize_t bytes; if (*pid_file != '/') { cl_log(LOG_INFO, "Invalid pid-file name, must begin with a " "'/' [%s]\n", pid_file); return -1; } if (create_pid_directory(pid_file) < 0) { return -1; } while (1) { pidfilefd = open(pid_file, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); if (pidfilefd < 0) { if (errno != EEXIST) { /* Old PID file */ cl_log(LOG_INFO, "Could not open pid-file " "[%s]: %s", pid_file, strerror(errno)); return -1; } } else { break; } pidfilefd = open(pid_file, O_RDONLY, S_IRUSR|S_IWUSR); if (pidfilefd < 0) { cl_log(LOG_INFO, "Could not open pid-file " "[%s]: %s", pid_file, strerror(errno)); return -1; } while (1) { bytes = read(pidfilefd, pidbuf, sizeof(pidbuf)-1); if (bytes < 0) { if (errno == EINTR) { continue; } cl_log(LOG_INFO, "Could not read pid-file " "[%s]: %s", pid_file, strerror(errno)); return -1; } pidbuf[bytes] = '\0'; break; } if(unlink(pid_file) < 0) { cl_log(LOG_INFO, "Could not delete pid-file " "[%s]: %s", pid_file, strerror(errno)); return -1; } if (!bytes) { cl_log(LOG_INFO, "Invalid pid in pid-file " "[%s]: %s", pid_file, strerror(errno)); return -1; } close(pidfilefd); pid = strtoul(pidbuf, NULL, 10); if (pid == ULONG_MAX && errno == ERANGE) { cl_log(LOG_INFO, "Invalid pid in pid-file " "[%s]: %s", pid_file, strerror(errno)); return -1; } if (kill(pid, SIGKILL) < 0 && errno != ESRCH) { cl_log(LOG_INFO, "Error killing old proccess [%lu] " "from pid-file [%s]: %s", pid, pid_file, strerror(errno)); return -1; } cl_log(LOG_INFO, "Killed old send_arp process [%lu]", pid); } if (snprintf(pidbuf, sizeof(pidbuf), "%u" , getpid()) >= (int)sizeof(pidbuf)) { cl_log(LOG_INFO, "Pid too long for buffer [%u]", getpid()); return -1; } while (1) { bytes = write(pidfilefd, pidbuf, strlen(pidbuf)); if (bytes != strlen(pidbuf)) { if (bytes < 0 && errno == EINTR) { continue; } cl_log(LOG_INFO, "Could not write pid-file " "[%s]: %s", pid_file, strerror(errno)); return -1; } break; } close(pidfilefd); return 0; } static int meta_data_addr6(void) { const char* meta_data= "\n" "\n" "\n" " 1.0\n" " \n" " This script manages IPv6 alias IPv6 addresses,It can add an IP6\n" " alias, or remove one.\n" " \n" " manages IPv6 alias\n" " \n" " \n" " \n" " The IPv6 address this RA will manage \n" " \n" " IPv6 address\n" " \n" " \n" " \n" " \n" " \n" " \n" - " \n" - " \n" + " \n" + " \n" " \n" " \n" " \n" "\n"; printf("%s\n",meta_data); return OCF_SUCCESS; } diff --git a/heartbeat/LVM b/heartbeat/LVM index 1daabe89f..1a82ac66a 100644 --- a/heartbeat/LVM +++ b/heartbeat/LVM @@ -1,353 +1,353 @@ #!/bin/sh # # # LVM # # Description: Manages an LVM volume as an HA resource # # # Author: Alan Robertson # Support: linux-ha@lists.linux-ha.org # License: GNU General Public License (GPL) # Copyright: (C) 2002 - 2005 International Business Machines, Inc. # # This code significantly inspired by the LVM resource # in FailSafe by Lars Marowsky-Bree # # # An example usage in /etc/ha.d/haresources: # node1 10.0.0.170 ServeRAID::1::1 LVM::myvolname # # See usage() function below for more details... # # OCF parameters are as below: # OCF_RESKEY_volgrpname # ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### usage() { methods=`LVM_methods` methods=`echo $methods | tr ' ' '|'` cat <<-! usage: $0 $methods $0 manages an Linux Volume Manager volume (LVM) as an HA resource The 'start' operation brings the given volume online The 'stop' operation takes the given volume offline The 'status' operation reports whether the volume is available The 'monitor' operation reports whether the volume seems present The 'validate-all' operation checks whether the OCF parameters are valid The 'methods' operation reports on the methods $0 supports ! exit $OCF_ERR_GENERIC } meta_data() { cat < 1.0 Resource script for LVM. It manages an Linux Volume Manager volume (LVM) as an HA resource. LVM resource agent The name of volume group. Volume group name If set, the volume group will be activated exclusively. Exclusive activation - + END } # # methods: What methods/operations do we support? # LVM_methods() { cat <<-! start stop status monitor methods validate-all usage ! } # # Return LVM status (silently) # LVM_status() { if [ "$LVM_MAJOR" -eq "1" ] then vgdisplay $1 | grep -i 'Status.*available' >/dev/null return $? else vgdisplay -v $1 | grep -i 'Status[ \t]*available' >/dev/null return $? fi } # # Report on LVM volume status to stdout... # LVM_report_status() { if [ "$LVM_MAJOR" -eq "1" ] then VGOUT=`vgdisplay $1 2>&1` echo "$VGOUT" | grep -i 'Status.*available' >/dev/null rc=$? else VGOUT=`vgdisplay -v $1 2>&1` echo "$VGOUT" | grep -i 'Status[ \t]*available' >/dev/null rc=$? fi if [ $rc -eq 0 ] then : Volume $1 is available else ocf_log debug "LVM Volume $1 is not available (stopped)" return $OCF_NOT_RUNNING fi if echo "$VGOUT" | grep -i 'Access.*read/write' >/dev/null then ocf_log debug "Volume $1 is available read/write (running)" else ocf_log debug "Volume $1 is available read-only (running)" fi return $OCF_SUCCESS } # # Monitor the volume - does it really seem to be working? # # LVM_monitor() { if LVM_status $1 then : OK else ocf_log info "LVM Volume $1 is offline" return $OCF_NOT_RUNNING fi ocf_run vgck $1 return $? } # # Enable LVM volume # LVM_start() { # TODO: This MUST run vgimport as well ocf_log info "Activating volume group $1" if [ "$LVM_MAJOR" -eq "1" ]; then ocf_run vgscan $1 else ocf_run vgscan fi active_mode="ly" if ocf_is_true "$OCF_RESKEY_exclusive" ; then active_mode="ey" fi ocf_run vgchange -a $active_mode $1 || return $OCF_ERR_GENERIC if LVM_status $1; then : OK Volume $1 activated just fine! return $OCF_SUCCESS else ocf_log err "LVM: $1 did not activate correctly" return $OCF_NOT_RUNNING fi } # # Disable the LVM volume # LVM_stop() { vgdisplay "$1" 2>&1 | grep 'Volume group .* not found' >/dev/null && { ocf_log info "Volume group $1 not found" return 0 } ocf_log info "Deactivating volume group $1" ocf_run vgchange -a ln $1 || return 1 if LVM_status $1 then ocf_log err "LVM: $1 did not stop correctly" return $OCF_ERR_GENERIC fi # TODO: This MUST run vgexport as well return $OCF_SUCCESS } # # Check whether the OCF instance parameters are valid # LVM_validate_all() { check_binary $AWK # Off-the-shelf tests... vgck "$VOLUME" >/dev/null 2>&1 if [ $? -ne 0 ]; then ocf_log err "Volume group [$VOLUME] does not exist or contains error!" exit $OCF_ERR_GENERIC fi # Double-check if [ "$LVM_MAJOR" -eq "1" ] then vgdisplay "$VOLUME" >/dev/null 2>&1 else vgdisplay -v "$VOLUME" >/dev/null 2>&1 fi if [ $? -ne 0 ]; then ocf_log err "Volume group [$VOLUME] does not exist or contains error!" exit $OCF_ERR_GENERIC fi return $OCF_SUCCESS } # # 'main' starts here... # if ( [ $# -ne 1 ] ) then usage exit $OCF_ERR_ARGS fi case $1 in meta-data) meta_data exit $OCF_SUCCESS;; methods) LVM_methods exit $?;; usage) usage exit $OCF_SUCCESS;; *) ;; esac if [ -z "$OCF_RESKEY_volgrpname" ] then # echo "You must identify the volume group name!" ocf_log err "You must identify the volume group name!" # usage exit $OCF_ERR_ARGS fi # Get the LVM version number, for this to work we assume(thanks to panjiam): # # LVM1 outputs like this # # # vgchange --version # vgchange: Logical Volume Manager 1.0.3 # Heinz Mauelshagen, Sistina Software 19/02/2002 (IOP 10) # # LVM2 and higher versions output in this format # # # vgchange --version # LVM version: 2.00.15 (2004-04-19) # Library version: 1.00.09-ioctl (2004-03-31) # Driver version: 4.1.0 LVM_VERSION=`vgchange --version 2>&1 | \ $AWK '/Logical Volume Manager/ {print $5"\n"; exit; } /LVM version:/ {printf $3"\n"; exit;}'` rc=$? if ( [ $rc -ne 0 ] || [ -z "$LVM_VERSION" ] ) then ocf_log err "LVM: $1 could not determine LVM version. Try 'vgchange --version' manually and modify $0 ?" exit $OCF_ERR_INSTALLED fi LVM_MAJOR="${LVM_VERSION%%.*}" VOLUME=$OCF_RESKEY_volgrpname # What kind of method was invoked? case "$1" in start) LVM_start $VOLUME exit $?;; stop) LVM_stop $VOLUME exit $?;; status) LVM_report_status $VOLUME exit $?;; monitor) LVM_monitor $VOLUME exit $?;; validate-all) LVM_validate_all ;; *) usage exit $OCF_ERR_AEGS;; esac diff --git a/heartbeat/LinuxSCSI b/heartbeat/LinuxSCSI index da9e8232e..182cd457b 100644 --- a/heartbeat/LinuxSCSI +++ b/heartbeat/LinuxSCSI @@ -1,295 +1,295 @@ #!/bin/sh # # # LinuxSCSI # # Description: Enables/Disables SCSI devices to protect them from being # used by mistake # # # Author: Alan Robertson # Support: linux-ha@lists.linux-ha.org # License: GNU General Public License (GPL) # Copyright: (C) 2002 - 2005 IBM # # CAVEATS: See the usage message for some important warnings # # usage: ./LinuxSCSI (start|stop|status|monitor|meta-data|validate-all|methods) # # OCF parameters are as below: # OCF_RESKEY_scsi # # An example usage in /etc/ha.d/haresources: # node1 10.0.0.170 LinuxSCSI:0:0:11 # ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### zeropat="[ 0]0" PROCSCSI=/proc/scsi/scsi usage() { cat <<-! usage: $0 (start|stop|status|monitor|meta-data|validate-all|methods) $0 manages the availability of a SCSI device from the point of view of the linux kernel. It make Linux believe the device has gone away, and it can make it come back again. The purpose of this resource script is to keep admins from accidentally messing with a shared disk that is managed by the HA subsystem and is currently owned by the other side. To get maximum benefit from this feature, you should (manually) disable the resources on boot, and let your HA software enable them when it wants to acquire the disk. The kernel code says this is potentially dangerous. DO NOT USE IT ON AN ACTIVE DEVICE. If the device is inactive, this script will make it stay inactive, when given "off". If you inactivate the wrong device, you may have to reboot your machine, and your data may take a hit. On the other hand, at least one RAID controller requires the use of this technique for it to work correctly in a failover environment - so it is believed that it is more stable in this usage than the comments in the code imply. Here are the warnings from the kernel source about the "stop" operation as of 2.4.10: ------------------------------ Consider this feature pre-BETA. CAUTION: This is not for hotplugging your peripherals. As SCSI was not designed for this, you could damage your hardware and thoroughly confuse the SCSI subsystem. Similar warnings apply to the "start" operation... Consider this feature BETA. CAUTION: This is not for hotplugging your peripherals. As SCSI was not designed for this you could damage your hardware ! However perhaps it is legal to switch on an already connected device. It is perhaps not guaranteed this device doesn't corrupt an ongoing data transfer. ------------------------- So, Caveat Emptor, and test this feature thoroughly on your kernel and your configuration with real load on the SCSI bus before using it in production! Another potential trouble spot... The order in which you bring up LinuxSCSI resources determines which SCSI device they show up as on Linux. If you have two SCSI devices in different resource groups they will be brought up asyncronously resulting in indeterminate device name assignments. This usually happens in an active-active configuration. To solve this you probably should use LVM or EVMS to manage these volumes. LVM and EVMS solve this problem for you by labels they keep in the volumes. If you don't use a reasonable volume manager, then you'll have to mount by UUID. ! } meta_data() { cat < 1.0 This is a resource agent for LinuxSCSI. It manages the availability of a SCSI device from the point of view of the linux kernel. It make Linux believe the device has gone away, and it can make it come back again. LinuxSCSI resource agent The SCSI instance to be managed. SCSI instance - - + + END } scsi_methods() { cat <<-! start stop status monitor validate-all methods ! } parseinst() { lun=0 case "$1" in [0-9]*:[0-9]*:[0-9]*);; [0-9]*:[0-9]*:[0-9]*:[0-9]*) lun=`echo "$1" | cut -d: -f4`;; *) #host=error #channel=error #target=error #lun=error ocf_log err "Invalid SCSI instance $1" exit $OCF_ERR_ARGS esac host=`echo "$1" | cut -d: -f1` channel=`echo "$1" | cut -d: -f2` target=`echo "$1" | cut -d: -f3` } # # start: Enable the given SCSI device in the kernel # scsi_start() { parseinst "$1" # [ $target = error ] && exit 1 # echo "scsi-add-single-device $host $channel $target $lun" >>$PROCSCSI echo "scsi add-single-device $host $channel $target $lun" >>$PROCSCSI if scsi_status "$1" then return $OCF_SUCCESS else ocf_log err "SCSI device $1 not active!" return $OCF_ERR_GENERIC fi } # # stop: Disable the given SCSI device in the kernel # scsi_stop() { parseinst "$1" # [ $target = error ] && exit 1 echo "scsi remove-single-device $host $channel $target $lun" >>$PROCSCSI if scsi_status "$1" then ocf_log err "SCSI device $1 still active!" return $OCF_ERR_GENERIC else return $OCF_SUCCESS fi } # # status: is the given device now available? # scsi_status() { parseinst "$1" # [ $target = error ] && exit 1 [ $channel -eq 0 ] && channel=$zeropat [ $target -eq 0 ] && target=$zeropat [ $lun -eq 0 ] && lun=$zeropat greppat="Host: *scsi$host *Channel: *$channel *Id: *$target *Lun: *$lun" grep -i "$greppat" $PROCSCSI >/dev/null if [ $? -eq 0 ]; then return $OCF_SUCCESS else return $OCF_NOT_RUNNING fi } # # validate_all: Check the OCF instance parameters # scsi_validate_all() { parseinst $instance return $OCF_SUCCESS } if ( [ $# -ne 1 ] ) then ocf_log err "Parameter number error." usage exit $OCF_ERR_GENERIC fi #if # [ -z "$OCF_RESKEY_scsi" ] && [ "X$1" = "Xmethods" ] #then # scsi_methods # exit #? #fi case $1 in methods) scsi_methods exit $OCF_SUCCESS ;; meta-data) meta_data exit $OCF_SUCCESS ;; usage) usage exit $OCF_SUCCESS ;; *) ;; esac if [ -z "$OCF_RESKEY_scsi" ] then ocf_log err "You have to set a valid scsi id at least!" # usage exit $OCF_ERR_GENERIC fi instance=$OCF_RESKEY_scsi case $1 in start) scsi_start $instance ;; stop) scsi_stop $instance ;; status|monitor) if scsi_status $instance then ocf_log info "SCSI device $instance is running" return $OCF_SUCCESS else ocf_log info "SCSI device $instance is stopped" exit $OCF_NOT_RUNNING fi ;; validate-all) scsi_validate_all ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $? diff --git a/heartbeat/MailTo b/heartbeat/MailTo index cea6dd9ce..8c1c81d37 100644 --- a/heartbeat/MailTo +++ b/heartbeat/MailTo @@ -1,215 +1,215 @@ #!/bin/sh # # Resource script for MailTo # # Author: Alan Robertson # # Description: sends email to a sysadmin whenever a takeover occurs. # # Note: This command requires an argument, unlike normal init scripts. # # This can be given in the haresources file as: # # You can also give a mail subject line or even multiple addresses # MailTo::alanr@unix.sh::BigImportantWebServer # MailTo::alanr@unix.sh,spoppi@gmx.de::BigImportantWebServer # # This will then be put into the message subject and body. # # OCF parameters are as below: # OCF_RESKEY_email # OCF_RESKEY_subject # # License: GNU General Public License (GPL) # # Copyright: (C) 2005 International Business Machines ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### ARGS="$0 $*" us=`uname -n` usage() { echo "Usage: $0 {start|stop|status|monitor|meta-data|validate-all}" } meta_data() { cat < 1.0 This is a resource agent for MailTo. It sends email to a sysadmin whenever a takeover occurs. MailTo resource agent The email address of sysadmin. Email address The subject of the email. Subject - - + + END } MailProgram() { $MAILCMD -s "$1" "$email" </dev/null if [ $? -eq 0 ]; then : OK, mail to $item@localhost.localdomain else ocf_log err "Invalid email address [$email]" exit $OCF_ERR_ARGS fi ;; esac done # Any subject is OK return $OCF_SUCCESS } # # See how we were called. # # The order in which heartbeat provides arguments to resource # scripts is broken. It should be fixed. # if ( [ $# -ne 1 ] ) then usage exit $OCF_ERR_GENERIC fi case $1 in meta-data) meta_data exit $OCF_SUCCESS ;; status|monitor) MailToStatus exit $? ;; usage) usage exit $OCF_SUCCESS ;; *) ;; esac if [ -z "$OCF_RESKEY_email" ] then ocf_log err "At least 1 Email address has to be given!" # usage exit $OCF_ERR_GENERIC fi email=$OCF_RESKEY_email subject=$OCF_RESKEY_subject MailToValidateAll case $1 in start) MailToStart ;; stop) MailToStop ;; validate-all) ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $? diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am index c01488e74..238b1fe3b 100644 --- a/heartbeat/Makefile.am +++ b/heartbeat/Makefile.am @@ -1,107 +1,109 @@ # Makefile.am for OCF RAs # # Author: Sun Jing Dong # Copyright (C) 2004 IBM # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # MAINTAINERCLEANFILES = Makefile.in EXTRA_DIST = $(ocf_SCRIPTS) ra-api-1.dtd INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/linux-ha dtddir = $(HA_NOARCHDATAHBDIR) ocfdir = @OCF_RA_DIR@/heartbeat dtd_SCRIPTS = ra-api-1.dtd gliblib = @GLIBLIB@ if USE_IPV6ADDR ocf_PROGRAMS = IPv6addr else ocf_PROGRAMS = endif IPv6addr_SOURCES = IPv6addr.c IPv6addr_LDADD = $(top_builddir)/lib/clplumbing/libplumb.la \ $(gliblib) @LIBNETLIBS@ ocf_SCRIPTS = ClusterMon \ Dummy \ IPaddr \ IPaddr2 \ drbd \ anything \ + AoEtarget \ apache \ AudibleAlarm \ db2 \ Delay \ drbd \ eDir88 \ EvmsSCC \ Evmsd \ Filesystem \ ids \ iscsi \ ICP \ IPsrcaddr \ LinuxSCSI \ LVM \ MailTo \ ManageRAID \ ManageVE \ mysql \ + mysql-proxy \ nfsserver \ oracle \ oralsnr \ pingd \ portblock \ pgsql \ Pure-FTPd \ Raid1 \ Route \ rsyncd \ SAPDatabase \ SAPInstance \ SendArp \ ServeRAID \ SphinxSearchDaemon \ Squid \ Stateful \ SysInfo \ scsi2reservation \ sfex \ tomcat \ VIPArip \ VirtualDomain \ vmware \ WAS \ WAS6 \ WinPopup \ Xen \ Xinetd \ .ocf-shellfuncs \ .ocf-binaries \ .ocf-directories \ .ocf-returncodes commondir = @HA_LIBHBDIR@ # Legacy locations common_SCRIPTS = ocf-shellfuncs ocf-returncodes diff --git a/heartbeat/ManageRAID b/heartbeat/ManageRAID index 3fdfcbf23..ba7990288 100644 --- a/heartbeat/ManageRAID +++ b/heartbeat/ManageRAID @@ -1,383 +1,383 @@ #!/bin/sh # # 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_ROOT}/resource.d/heartbeat/.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 [[ $? != 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 > 3 ]]; then ocf_log err "mdadm returned error code $retcode_raidcheck while checking ${!RAID_DEV}." return $OCF_ERR_GENERIC elif [[ $retcode_raidcheck == 3 ]]; then ocf_log err "${!RAID_DEV} has failed." return $OCF_ERR_GENERIC elif [[ $retcode_raidcheck < 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[@]} < 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 index 19d599814..ec0ad38d3 100644 --- a/heartbeat/ManageVE +++ b/heartbeat/ManageVE @@ -1,294 +1,294 @@ #!/bin/sh # # Name ManageVE # 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 # # This OCF complaint resource agent manages OpenVZ VEs and thus requires # a proper OpenVZ installation including a recent vzctl util. # # # Created 07. Sep 2006 # Updated 18. Sep 2006 # # rev. 1.00.3 # # Changelog # # 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_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ### # required utilities VZCTL=/usr/sbin/vzctl # # usage() # # taken from Raid1 Heartbeat2 OCF resource agent usage() { cat <<-EOT usage: $0 {start|stop|status|monitor|validate-all|usage|meta-data} EOT } # # meta_data() # meta_data() { cat < 1.00.3 This OCF complaint resource agent manages OpenVZ VEs and thus requires a proper OpenVZ installation including a recent vzctl util. OpenVZ VE resource agent OpenVZ ID of virtual environment (see output of vzlist -a for all assigned IDs) OpenVZ ID of VE - - + + END } # # start_ve() # # ATTENTION: The following code relies on vzctl's exit codes, especially: # # 0 : success # 32 : VE already running # # In case any of those exit codes change, this function will need fixing. # start_ve() { declare -i retcode veexists=`$VZCTL status $VEID 2>/dev/null | $AWK '{print $3}'` if [[ $veexists != "exist" ]]; then ocf_log err "vzctl status $VEID returned: $VEID does not exist." return $OCF_ERR_INSTALLED fi status_ve retcode=$? if [[ $retcode == $OCF_SUCCESS ]]; then return $OCF_SUCCESS elif [[ $retcode != $OCF_NOT_RUNNING ]]; then return $retcode fi $VZCTL start $VEID >& /dev/null retcode=$? if [[ $retcode != 0 && $retcode != 32 ]]; then ocf_log err "vzctl start $VEID returned: $retcode" return $OCF_ERR_GENERIC fi 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() { declare -i retcode $VZCTL stop $VEID >& /dev/null retcode=$? if [[ $retcode != 0 ]]; then ocf_log err "vzctl stop $VEID returned: $retcode" return $OCF_ERR_GENERIC fi 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 ocf_log err "vzctl status $VEID returned: $retcode" return $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)" return $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 ;; validate-all) validate_all_ve ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $? diff --git a/heartbeat/Pure-FTPd b/heartbeat/Pure-FTPd index 2870fb769..bce8990f9 100755 --- a/heartbeat/Pure-FTPd +++ b/heartbeat/Pure-FTPd @@ -1,244 +1,244 @@ #!/bin/sh # # Resource script for Pure-FTPd # # Description: Manages Pure-FTPd as an OCF resource in # an Active-Passive High Availability setup. # # Author: Rajat Upadhyaya : Pure-FTPd script # Author: Raoul Bhatia : Minor Cleanup. Added Debian GNU/Linux Support # License: GNU General Public License (GPL) # # # usage: $0 {start|stop|status|monitor|validate-all|meta-data} # # The "start" arg starts Pure-FTPd. # # The "stop" arg stops it. # # OCF parameters: # OCF_RESKEY_script # OCF_RESKEY_conffile # OCF_RESKEY_daemon_type # OCF_RESKEY_pidfile # ########################################################################## # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs : ${OCF_RESKEY_script="/sbin/pure-config.pl"} script_basename=`basename $OCF_RESKEY_script` : ${OCF_RESKEY_conffile="/etc/pure-ftpd/pure-ftpd.conf"} : ${OCF_RESKEY_daemon_type=""} : ${OCF_RESKEY_pidfile="${HA_RSCTMP}/pure-ftpd-${OCF_RESOURCE_INSTANCE}.pid"} USAGE="Usage: $0 {start|stop|status|monitor|validate-all|meta-data}"; ########################################################################## usage() { echo $USAGE >&2 } meta_data() { cat < 1.0 This script manages Pure-FTPd in an Active-Passive setup OCF Resource Agent compliant FTP script. The full path to the Pure-FTPd startup script. For example, "/sbin/pure-config.pl" Script name with full path The Pure-FTPd configuration file name with full path. For example, "/etc/pure-ftpd/pure-ftpd.conf" Configuration file name with full path The Pure-FTPd daemon to be called by pure-ftpd-wrapper. Valid options are "" for pure-ftpd, "mysql" for pure-ftpd-mysql, "postgresql" for pure-ftpd-postgresql and "ldap" for pure-ftpd-ldap Configuration file name with full path PID file PID file - + END exit $OCF_SUCCESS } isRunning() { kill -0 "$1" > /dev/null } PureFTPd_status() { if [ -f $OCF_RESKEY_pidfile ] then # Pure-FTPd is probably running PID=`head -n 1 $OCF_RESKEY_pidfile` if [ ! -z $PID ] ; then isRunning "$PID" && [ `ps -p $PID | grep pure-ftpd | wc -l` -eq 1 ] return $? fi fi # Pure-FTPd is not running false } PureFTPd_start() { # # make a few checks and start Pure-FTPd # if ocf_is_root ; then : ; else ocf_log err "You must be root." exit $OCF_ERR_PERM fi # if Pure-FTPd is running return success if PureFTPd_status ; then exit $OCF_SUCCESS fi # check that the Pure-FTPd script exists and can be executed if [ ! -x "$OCF_RESKEY_script" ]; then ocf_log err "Pure-FTPd script '$OCF_RESKEY_script' does not exist or cannot be executed" exit $OCF_ERR_GENERIC fi # test for pure-ftpd-wrapper (e.g. Debian GNU/Linux Systems) if [ "$script_basename" = "pure-ftpd-wrapper" ]; then # pure-ftpd-wrapper expects STANDALONE_OR_INETD to be set to standalone STANDALONE_OR_INETD=standalone $OCF_RESKEY_script $OCF_RESKEY_daemon_type else # check that the Pure-FTPd config file exist if [ ! -f "$OCF_RESKEY_conffile" ]; then ocf_log err "Pure_FTPd config file '$OCF_RESKEY_conffile' does not exist" exit $OCF_ERR_GENERIC fi $OCF_RESKEY_script $OCF_RESKEY_conffile -g $OCF_RESKEY_pidfile fi if [ $? -ne 0 ]; then ocf_log info "Pure-FTPd returned error" $? exit $OCF_ERR_GENERIC fi exit $OCF_SUCCESS } PureFTPd_stop() { if PureFTPd_status ; then PID=`head -n 1 $OCF_RESKEY_pidfile` if [ ! -z $PID ] ; then kill $PID fi fi exit $OCF_SUCCESS } PureFTPd_monitor() { if PureFTPd_status ; then return $OCF_SUCCESS fi return $OCF_NOT_RUNNING } PureFTPd_validate_all() { return $OCF_SUCCESS } # # Main # if [ $# -ne 1 ] then usage exit $OCF_ERR_ARGS fi case $1 in start) PureFTPd_start ;; stop) PureFTPd_stop ;; status) if PureFTPd_status then ocf_log info "Pure-FTPd is running" exit $OCF_SUCCESS else ocf_log info "Pure-FTPd is stopped" exit $OCF_NOT_RUNNING fi ;; monitor) PureFTPd_monitor exit $? ;; validate-all) PureFTPd_validate_all exit $? ;; meta-data) meta_data ;; usage) usage exit $OCF_SUCCESS ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac diff --git a/heartbeat/Raid1 b/heartbeat/Raid1 index f92ac31d9..300c81366 100644 --- a/heartbeat/Raid1 +++ b/heartbeat/Raid1 @@ -1,409 +1,420 @@ #!/bin/sh # # # License: GNU General Public License (GPL) # Support: linux-ha@lists.linux-ha.org # # Raid1 # Description: Manages a software Raid1 device on a shared storage medium. # Original Author: Eric Z. Ayers (eric.ayers@compgen.com) # Original Release: 25 Oct 2000 # RAID patches: http://people.redhat.com/mingo/raid-patches/ # Word to the Wise: http://lwn.net/2000/0810/a/raid-faq.php3 # Sympathetic Ear: mailto:linux-raid@vger.kernel.org # # usage: $0 {start|stop|status|monitor|validate-all|usage|meta-data} # # OCF parameters are as below: # OCF_RESKEY_raidconf # (name of MD configuration file. e.g. /etc/raidtab or /etc/mdadm.conf) # OCF_RESKEY_raiddev # (of the form /dev/md* the block device to use) # # in /etc/ha.d/haresources, use a line such as: # nodea 10.0.0.170 Raid1::/etc/raidtab.md0::/dev/md0 Filesystem::/dev/md0::/data1::ext2 # (for systems with raidtools) # or # nodea 10.0.0.170 Raid1::/etc/mdadm.conf::/dev/md0 Filesystem::/dev/md0::/data1::ext2 # (for systems with mdadm) # # The "start" arg starts up the raid device # The "stop" arg stops it. NOTE: all filesystems must be unmounted # and no processes should be accessing the device. # The "status" arg just prints out whether the device is running or not # # # DISCLAIMER: Use at your own risk! # # Besides all of the usual legalese that accompanies free software, # I will warn you that I do not yet use this kind of setup (software RAID # over shared storage) in production, and I have reservations about doing so. # # The linux md driver/scsi drivers under Raid 0.90 and kernel version 2.2 # do not behave well when a drive is in the process of going bad. # The kernel slows down, but doesn't completely crash. This is about the # worst possible thing that could happen in an un-attended HA type # environment. (Once the system is rebooted, the sofware raid stuff works # like a champ.) # My other reservation has to do with the interation of RAID recovery with # journaling filesystems and other parts of the kernel. Subscribe to # linux-raid@vger.kernel.org for other opinions and possible solutions. # # -EZA 25 Oct 2000 # # SETUP: # # You might need to pass the command line parameter: raid=noautodetect # in an HA environment so that the kernel doesn't automatically start # up your raid partitions when you boot the node. This means that it isn't # going to work to use RAID for the system disks and the shared disks. # # 0) partition the disks to use for RAID. Use normal Linux partition # types, not the RAID autodetect type for your partitions. # 1) Create /etc/raidtab.md? on both systems (see example file below) # or for systems with mdadm tools create /etc/mdadm.conf (see example below) # 2) Initialize your raid partition with # /sbin/mkraid --configfile /etc/raidtab.md? /dev/md? # or create mirror raid with the following command # mdadm --create /dev/md? -l 1 -n 2 /dev/sdb? /dev/sdb? # 3) Format your filesystem # mke2fs /dev/md0 # for ext2fs... a journaling filesystem would be nice # 3) Create the mount point on both systems. # DO NOT add your raid filesystem to /etc/fstab # 4) copy this script (to /etc/rc.d/init.d if you wish) and edit it to # reflect your desired settings. # 5) Modify the heartbeat 'haresources' (for non-crm heartbeat) or 'cib.xml' (for crm heartbeat) setup file # 6) unmount the filesystem and stop the raid device with 'raidstop' or 'mdadm -S' # 7) fire up heartbeat! # # # EXAMPLE config file /etc/raidtab.md0 # This file must exist on both machines! # # raiddev /dev/md0 # raid-level 1 # nr-raid-disks 2 # chunk-size 64k # persistent-superblock 1 # #nr-spare-disks 0 # device /dev/sda1 # raid-disk 0 # device /dev/sdb1 # raid-disk 1 # # EXAMPLE config file /etc/mdadm.conf (for more info:man mdadm.conf) # # DEVICE /dev/sdb1 /dev/sdb2 # ARRAY /dev/md0 level=raid1 UUID=4a865b55:ba27ef8d:29cd5701:6fb42799 ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### usage() { cat <<-EOT usage: $0 {start|stop|status|monitor|validate-all|usage|meta-data} EOT } meta_data() { cat < 1.0 Resource script for RAID1. It manages a software Raid1 device on a shared storage medium. RAID1 resource agent The RAID configuration file. e.g. /etc/raidtab or /etc/mdadm.conf. RAID config file The block device to use. block device The value for the homehost directive; this is an mdadm feature to protect RAIDs against being activated by accident. It is recommended to create RAIDs managed by the cluster with "homehost" set to a special value, so they are not accidentially auto-assembled by nodes not supposed to own them. Homehost for mdadm - - + + END } # # START: Start up the RAID device # raid1_start() { # See if the md device is already mounted. $MOUNT | grep -e "^$MDDEV\>" >/dev/null if [ $? -ne 1 ] ; then ocf_log err "Device $MDDEV is already mounted!" return $OCF_ERR_GENERIC fi if [ "running" = `raid1_status` ]; then # We are already online, do not bother return $OCF_SUCCESS fi # Insert SCSI module $MODPROBE scsi_hostadapter if [ $? -ne 0 ] ; then ocf_log warn "Couldn't insert SCSI module." fi # Insert raid personality module $MODPROBE raid1 if [ $? -ne 0 ] ; then # It is not fatal, chance is that we have raid1 builtin... ocf_log warn "Couldn't insert RAID1 module" fi grep -q "^Personalities.*\[raid1\]" /proc/mdstat 2>/dev/null if [ $? -ne 0 ] ; then ocf_log err "We don't have RAID1 support! Exiting" return $OCF_ERR_GENERIC fi if [ $HAVE_RAIDTOOLS = "true" ]; then # Run raidstart to start up the RAID array $RAIDSTART --configfile $RAIDCONF $MDDEV else # Run mdadm $MDADM --assemble $MDDEV --config=$RAIDCONF $MDADM_HOMEHOST fi if [ "running" = `raid1_status` ]; then return $OCF_SUCCESS else ocf_log err "Couldn't start RAID for $MDDEV" return $OCF_ERR_GENERIC fi } # # STOP: stop the RAID device # raid1_stop() { # See if the MD device is online if [ "stopped" = `raid1_status` ]; then return $OCF_SUCCESS fi # See if the MD device is mounted $MOUNT | grep -e "^$MDDEV\>" >/dev/null if [ $? -ne 1 ] ; then # Kill all processes open on filesystem $FUSER -m -k $MDDEV # the return from fuser doesn't tell us much #if [ $? -ne 0 ] ; then # ocf_log "err" "Couldn't kill processes on $MOUNTPOINT" # return 1; #fi # Unmount the filesystem $UMOUNT $MDDEV $MOUNT | grep -e "^$MDDEV\>" >/dev/null if [ $? -ne 1 ] ; then ocf_log err "filesystem for $MDDEV still mounted" return $OCF_ERR_GENERIC fi fi # Turn off raid if [ $HAVE_RAIDTOOLS = "true" ]; then $RAIDSTOP --configfile $RAIDCONF $MDDEV else $MDADM --stop $MDDEV --config=$RAIDCONF $MDADM_HOMEHOST fi if [ $? -ne 0 ] ; then ocf_log err "Couldn't stop RAID for $MDDEV" return $OCF_ERR_GENERIC fi return $OCF_SUCCESS } # -# STATUS: is the raid device online or offline? +# monitor: a less noisy status # -raid1_status() { +raid1_monitor() { + # check if the md device exists first + [ -b $MDDEV ] && + grep -e "^$MD[ \t:]" /proc/mdstat >/dev/null && + return $OCF_SUCCESS + return $OCF_NOT_RUNNING +} +# +# STATUS: is the raid device online or offline? +# +raid1_status() { # See if the MD device is online - grep -e "^$MD[ \t:]" /proc/mdstat >/dev/null - if [ $? -ne 0 ] ; then + raid1_monitor + rc=$? + if [ $rc -ne $OCF_SUCCESS ]; then echo "stopped" - return $OCF_NOT_RUNNING else echo "running" - return $OCF_SUCCESS fi - -} + return $rc +} raid1_validate_all() { # Utilities used by this script check_binary $MODPROBE check_binary $FSCK check_binary $FUSER check_binary $MOUNT check_binary $UMOUNT if [ $HAVE_RAIDTOOLS = "true" ]; then # $MDDEV should be an md device lsraid -a $MDDEV 2>&1 | grep -q -i "is not an md device" if [ $? -eq 0 ]; then ocf_log err "$MDDEV is not an md device!" exit $OCF_ERR_ARGS fi COMMENT="\(#.*\)" grep -q "^[[:space:]]*raiddev[[:space:]]\+$MDDEV[[:space:]]*$COMMENT\?$" $RAIDCONF 2>/dev/null if [ $? -ne 0 ]; then ocf_log err "Raid device $MDDEV does not appear in $RAIDCONF" exit $OCF_ERR_GENERIC fi else error=`$MDADM --query $MDDEV $MDADM_HOMEHOST 2>&1` if [ $? -ne 0 ]; then ocf_log err "$error" exit $OCF_ERR_GENERIC fi echo $error | grep -q -i "^$MDDEV[ \t:].*is not an md array" if [ $? -eq 0 ]; then ocf_log err "$MDDEV is not an md array!" exit $OCF_ERR_ARGS fi 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 # # Check the necessary enviroment virable's setting # RAIDCONF=$OCF_RESKEY_raidconf MDDEV=$OCF_RESKEY_raiddev if [ -z "$RAIDCONF" ] ; then ocf_log err "Please set OCF_RESKEY_raidconf!" exit $OCF_ERR_ARGS fi if [ ! -r "$RAIDCONF" ] ; then ocf_log err "Configuration file [$RAIDCONF] does not exist, or can not be opend!" exit $OCF_ERR_ARGS fi if [ -z "$MDDEV" ] ; then ocf_log err "Please set OCF_RESKEY_raiddev to the Raid device you want to control!" exit $OCF_ERR_ARGS fi -if [ ! -b "$MDDEV" ] ; then +if [ -e "$MDDEV" -a ! -b "$MDDEV" ] ; then ocf_log err "$MDDEV is not a block device!" exit $OCF_ERR_ARGS fi # strip off the /dev/ prefix to get the name of the MD device MD=`echo $MDDEV | sed -e 's/\/dev\///'` HAVE_RAIDTOOLS=false if - have_binary $RAIDSTART + have_binary $RAIDSTART >/dev/null 2>&1 then - check_binary $RAIDSTOP HAVE_RAIDTOOLS=true else check_binary $MDADM if [ -n "$OCF_RESKEY_homehost" ]; then MDADM_HOMEHOST="--homehost=${OCF_RESKEY_homehost}" else MDADM_HOMEHOST="" fi fi # At this stage, # [ $HAVE_RAIDTOOLS = false ] <=> we have $MDADM, # otherwise we have raidtools (raidstart and raidstop) # Look for how we are called case "$1" in start) raid1_start ;; stop) raid1_stop ;; - status|monitor) + status) raid1_status ;; + monitor) + raid1_monitor + ;; validate-all) raid1_validate_all ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $? diff --git a/heartbeat/SAPDatabase b/heartbeat/SAPDatabase index 0bcec9e0e..334c9ee71 100644 --- a/heartbeat/SAPDatabase +++ b/heartbeat/SAPDatabase @@ -1,998 +1,998 @@ #!/bin/sh # # SAPDatabase # # Description: Manages any type of SAP supported database instance # as a High-Availability OCF compliant resource. # # Author: Alexander Krauth, October 2006 # Support: linux@sap.com # License: GNU General Public License (GPL) # Copyright: (c) 2006, 2007 Alexander Krauth # # An example usage: # See usage() function below for more details... # # OCF instance parameters: # OCF_RESKEY_SID # OCF_RESKEY_DIR_EXECUTABLE (optional, well known directories will be searched by default) # OCF_RESKEY_DBTYPE # OCF_RESKEY_NETSERVICENAME (optional, non standard name of Oracle Listener) # OCF_RESKEY_DBJ2EE_ONLY (optional, default is false) # OCF_RESKEY_JAVA_HOME (optional, only needed if DBJ2EE_ONLY is true and JAVA_HOME enviroment variable is not set) # OCF_RESKEY_STRICT_MONITORING (optional, activate application level monitoring - with Oracle a failover will occur in case of an archiver stuck) # OCF_RESKEY_AUTOMATIC_RECOVER (optional, automatic startup recovery, default is false) # OCF_RESKEY_DIR_BOOTSTRAP (optional, if non standard J2EE server directory) # OCF_RESKEY_DIR_SECSTORE (optional, if non standard J2EE secure store directory) # OCF_RESKEY_DB_JARS (optional, if maintained in bootstrap.properties, mandatory for WebAS Java 7.10) # OCF_RESKEY_PRE_START_USEREXIT (optional, lists a script which can be executed before the resource is started) # OCF_RESKEY_POST_START_USEREXIT (optional, lists a script which can be executed after the resource is started) # OCF_RESKEY_PRE_STOP_USEREXIT (optional, lists a script which can be executed before the resource is stopped) # OCF_RESKEY_POST_STOP_USEREXIT (optional, lists a script which can be executed after the resource is stopped) # # ToDo: # Remove all the database dependend stuff from the agent and use # saphostcontrol daemon as soon as SAP will release it. # ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### SH=/bin/sh usage() { methods=`sapdatabase_methods` methods=`echo $methods | tr ' ' '|'` cat <<-! usage: $0 ($methods) $0 manages a SAP database of any type as an HA resource. Currently Oracle, MaxDB and DB/2 UDB are supported. ABAP databases as well as JAVA only databases are supported. The 'start' operation starts the instance. The 'stop' operation stops the instance. The 'status' operation reports whether the instance is running The 'monitor' operation reports whether the instance seems to be working The 'recover' operation tries to recover the instance after a crash (instance will be stopped first!) The 'validate-all' operation reports whether the parameters are valid The 'methods' operation reports on the methods $0 supports ! } meta_data() { cat < 1.92 Resource script for SAP databases. It manages a SAP database of any type as an HA resource. SAP database resource agent The unique SAP system identifier. e.g. P01 SAP system ID The full qualified path where to find sapstartsrv and sapcontrol. path of sapstartsrv and sapcontrol The name of the database vendor you use. Set either: ORA,DB6,ADA database vendor The Oracle TNS listener name. listener name If you do not have a ABAP stack installed in the SAP database, set this to TRUE only JAVA stack installed This is only needed if the DBJ2EE_ONLY parameter is set to true. Enter the path to the Java SDK which is used by the SAP WebAS Java Path to Java SDK This controls how the resource agent monitors the database. If set to true, it will use SAP tools to test the connect to the database. Do not use with Oracle, because it will result in unwanted failovers in case of an archiver stuck Activates application level monitoring The SAPDatabase resource agent tries to recover a failed start attempt automaticaly one time. This is done by running a forced abort of the RDBMS and/or executing recovery commands. Enable or disable automatic startup recovery The full qualified path where to find the J2EE instance bootstrap directory. e.g. /usr/sap/P01/J00/j2ee/cluster/bootstrap path to j2ee bootstrap directory The full qualified path where to find the J2EE security store directory. e.g. /usr/sap/P01/SYS/global/security/lib/tools path to j2ee secure store directory The full qualified filename of the jdbc driver for the database connection test. It will be automaticaly read from the bootstrap.properties file in Java engine 6.40 and 7.00. For Java engine 7.10 the parameter is mandatory. file name of the jdbc driver The full qualified path where to find a script or program which should be executed before this resource gets started. path to a pre-start script The full qualified path where to find a script or program which should be executed after this resource got started. path to a post-start script The full qualified path where to find a script or program which should be executed before this resource gets stopped. path to a pre-start script The full qualified path where to find a script or program which should be executed after this resource got stopped. path to a post-start script - + END } trap_handler() { rm -f $TEMPFILE exit $OCF_ERR_GENERIC } # # listener_start: Start the given listener # listener_start() { orasid="ora`echo $SID | tr [:upper:] [:lower:]`" rc=$OCF_SUCCESS output=`echo "lsnrctl start $NETSERVICENAME" | su - $orasid 2>&1` if [ $? -eq 0 ] then ocf_log info "Oracle Listener $NETSERVICENAME started: $output" rc=$OCF_SUCCESS else ocf_log err "Oracle Listener $NETSERVICENAME start failed: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # listener_stop: Stop the given listener # listener_stop() { orasid="ora`echo $SID | tr [:upper:] [:lower:]`" rc=$OCF_SUCCESS if listener_status then : listener is running, trying to stop it later... else return $OCF_SUCCESS fi output=`echo "lsnrctl stop $NETSERVICENAME" | su - $orasid 2>&1` if [ $? -eq 0 ] then ocf_log info "Oracle Listener $NETSERVICENAME stopped: $output" else ocf_log err "Oracle Listener $NETSERVICENAME stop failed: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # listener_status: is the given listener running? # listener_status() { orasid="ora`echo $SID | tr [:upper:] [:lower:]`" # Note: ps cuts off it's output at column $COLUMNS, so "ps -ef" can not be used here # as the output might be to long. cnt=`ps efo args --user $orasid | grep $NETSERVICENAME | grep -c tnslsnr` if [ $cnt -eq 1 ] then rc=$OCF_SUCCESS else ocf_log info "listener process not running for $NETSERVICENAME for $SID" rc=$OCF_ERR_GENERIC fi return $rc } # # x_server_start: Start the given x_server # x_server_start() { rc=$OCF_SUCCESS output=`echo "x_server start" | su - $sidadm 2>&1` if [ $? -eq 0 ] then ocf_log info "MaxDB x_server start: $output" rc=$OCF_SUCCESS else ocf_log err "MaxDB x_server start failed: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # x_server_stop: Stop the x_server # x_server_stop() { rc=$OCF_SUCCESS output=`echo "x_server stop" | su - $sidadm 2>&1` if [ $? -eq 0 ] then ocf_log info "MaxDB x_server stop: $output" else ocf_log err "MaxDB x_server stop failed: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # x_server_status: is the x_server running? # x_server_status() { sdbuser=`grep "^SdbOwner" /etc/opt/sdb | awk -F'=' '{print $2}'` # Note: ps cuts off it's output at column $COLUMNS, so "ps -ef" can not be used here # as the output might be to long. cnt=`ps efo args --user $sdbuser | grep -c vserver` if [ $cnt -ge 1 ] then rc=$OCF_SUCCESS else ocf_log info "x_server process not running" rc=$OCF_ERR_GENERIC fi return $rc } # # oracle_stop: Stop the Oracle database without any condition # oracle_stop() { echo '#!/bin/sh LOG=$HOME/stopdb.log date > $LOG if [ -x "${ORACLE_HOME}/bin/sqlplus" ] then SRVMGRDBA_EXE="${ORACLE_HOME}/bin/sqlplus" else echo "Can not find executable sqlplus" >> $LOG exit 1 fi $SRVMGRDBA_EXE /NOLOG >> $LOG << ! connect / as sysdba shutdown immediate exit ! rc=$? cat $LOG exit $rc' > $TEMPFILE chmod 700 $TEMPFILE chown $sidadm $TEMPFILE su - $sidadm -c $TEMPFILE retcode=$? rm -f $TEMPFILE if [ $retcode -eq 0 ]; then sapdatabase_status if [ $? -ne $OCF_NOT_RUNNING ]; then retcode=1 fi fi return $retcode } # # maxdb_stop: Stop the MaxDB database without any condition # maxdb_stop() { # x_Server must be running to stop database x_server_status if [ $? -ne $OCF_SUCCESS ]; then x_server_start; fi if [ $DBJ2EE_ONLY -eq 1 ]; then userkey=c_J2EE else userkey=c fi echo "#!/bin/sh LOG=\$HOME/stopdb.log date > \$LOG echo \"Stop database with xuserkey >$userkey<\" >> \$LOG dbmcli -U ${userkey} db_offline >> \$LOG 2>&1 exit \$?" > $TEMPFILE chmod 700 $TEMPFILE chown $sidadm $TEMPFILE su - $sidadm -c $TEMPFILE retcode=$? rm -f $TEMPFILE if [ $retcode -eq 0 ]; then sapdatabase_status if [ $? -ne $OCF_NOT_RUNNING ]; then retcode=1 fi fi return $retcode } # # db6udb_stop: Stop the DB2/UDB database without any condition # db6udb_stop() { echo '#!/bin/sh LOG=$HOME/stopdb.log date > $LOG echo "Shut down the database" >> $LOG $INSTHOME/sqllib/bin/db2 deactivate database $DB2DBDFT |tee -a $LOG 2>&1 $INSTHOME/sqllib/adm/db2stop force |tee -a $LOG 2>&1 exit $?' > $TEMPFILE chmod 700 $TEMPFILE chown $sidadm $TEMPFILE su - $sidadm -c $TEMPFILE retcode=$? rm -f $TEMPFILE if [ $retcode -eq 0 ]; then sapdatabase_status if [ $? -ne $OCF_NOT_RUNNING ]; then retcode=1 fi fi return $retcode } # # oracle_recover: try to clean up oracle after a crash # oracle_recover() { echo '#!/bin/sh LOG=$HOME/recover.log date > $LOG echo "Logfile written by heartbeat SAPDatabase resource agent" >> $LOG if [ -x "${ORACLE_HOME}/bin/sqlplus" ] then SRVMGRDBA_EXE="${ORACLE_HOME}/bin/sqlplus" else echo "Can not find executable sqlplus" >> $LOG exit 1 fi $SRVMGRDBA_EXE /NOLOG >> $LOG << ! connect / as sysdba shutdown abort startup mount WHENEVER SQLERROR EXIT SQL.SQLCODE WHENEVER OSERROR EXIT FAILURE alter database recover automatic database; alter database open; exit ! rc=$? cat $LOG exit $rc' > $TEMPFILE chmod 700 $TEMPFILE chown $sidadm $TEMPFILE su - $sidadm -c $TEMPFILE retcode=$? rm -f $TEMPFILE return $retcode } # # maxdb_recover: try to clean up MaxDB after a crash # maxdb_recover() { # x_Server must be running to stop database x_server_status if [ $? -ne $OCF_SUCCESS ]; then x_server_start; fi if [ $DBJ2EE_ONLY -eq 1 ]; then userkey=c_J2EE else userkey=c fi echo "#!/bin/sh LOG=\$HOME/recover.log date > \$LOG echo \"Logfile written by heartbeat SAPDatabase resource agent\" >> \$LOG echo \"Cleanup database with xuserkey >$userkey<\" >> \$LOG echo \"db_stop\" >> \$LOG 2>&1 dbmcli -U ${userkey} db_stop >> \$LOG 2>&1 echo \"db_clear\" >> \$LOG 2>&1 dbmcli -U ${userkey} db_clear >> \$LOG 2>&1 echo \"db_online\" >> \$LOG 2>&1 dbmcli -U ${userkey} db_online >> \$LOG 2>&1 rc=\$? cat \$LOG exit \$rc" > $TEMPFILE chmod 700 $TEMPFILE chown $sidadm $TEMPFILE su - $sidadm -c $TEMPFILE retcode=$? rm -f $TEMPFILE return $retcode } # # db6udb_recover: try to recover DB/2 after a crash # db6udb_recover() { db2sid="db2`echo $SID | tr [:upper:] [:lower:]`" echo '#!/bin/sh LOG=$HOME/recover.log date > $LOG echo "Logfile written by heartbeat SAPDatabase resource agent" >> $LOG $INSTHOME/sqllib/bin/db2_kill >> $LOG 2>&1 $INSTHOME/sqllib/adm/db2start >> $LOG 2>&1 $INSTHOME/sqllib/bin/db2 activate database $DB2DBDFT >> $LOG 2>&1 rc=$? cat $LOG exit $rc' > $TEMPFILE chmod 700 $TEMPFILE chown $db2sid $TEMPFILE su - $db2sid -c $TEMPFILE retcode=$? rm -f $TEMPFILE return $retcode } # # methods: What methods/operations do we support? # sapdatabase_methods() { cat <<-! start stop status monitor recover validate-all methods meta-data usage ! } # # sapuserexit : Many SAP customers need some additional processes/tools to run their SAP systems. # This specialties do not allow a totally generic SAP cluster resource agent. # Someone should write a resource agent for each additional process you need, if it # is required to monitor that process within the cluster manager. To enable # you to extent this resource agent without developing a new one, this user exit # was introduced. # sapuserexit() { NAME="$1" VALUE="$2" if [ -n "$VALUE" ] then if [ -x "$VALUE" ] then ocf_log info "Calling userexit ${NAME} with customer script file ${VALUE}" eval "$VALUE" >& /dev/null ocf_log info "Exiting userexit ${NAME} with customer script file ${VALUE}, returncode: $?" else ocf_log warn "Attribute ${NAME} is set to ${VALUE}, but this file is not executable" fi fi return 0 } # # sapdatabase_start : Start the SAP database # sapdatabase_start() { sapuserexit PRE_START_USEREXIT "$OCF_RESKEY_PRE_START_USEREXIT" case $DBTYPE in ADA) x_server_start ;; ORA) listener_start ;; esac output=`su - $sidadm -c $SAPSTARTDB` rc=$? if [ $DBJ2EE_ONLY -eq 1 ] then sapdatabase_monitor 1 rc=$? fi if [ $rc -ne 0 -a $OCF_RESKEY_AUTOMATIC_RECOVER -eq 1 ] then ocf_log warn "SAP database $SID start failed: $output" ocf_log warn "Try to recover database $SID" output='' sapdatabase_recover rc=$? fi if [ $rc -eq 0 ] then ocf_log info "SAP database $SID started: $output" rc=$OCF_SUCCESS sapuserexit POST_START_USEREXIT "$OCF_RESKEY_POST_START_USEREXIT" else ocf_log err "SAP database $SID start failed: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # sapdatabase_stop: Stop the SAP database # sapdatabase_stop() { sapuserexit PRE_STOP_USEREXIT "$OCF_RESKEY_PRE_STOP_USEREXIT" # use of the stopdb kernel script is not possible, because there are to may checks in that # script. We want to stop the database regardless of anything. #output=`su - $sidadm -c $SAPSTOPDB` case $DBTYPE in ORA) output=`oracle_stop` ;; ADA) output=`maxdb_stop` ;; DB6) output=`db6udb_stop` ;; esac if [ $? -eq 0 ] then ocf_log info "SAP database $SID stopped: $output" rc=$OCF_SUCCESS else ocf_log err "SAP database $SID stop failed: $output" rc=$OCF_ERR_GENERIC fi case $DBTYPE in ORA) listener_stop ;; ADA) x_server_stop ;; esac sapuserexit POST_STOP_USEREXIT "$OCF_RESKEY_POST_STOP_USEREXIT" return $rc } # # sapdatabase_monitor: Can the given database instance do anything useful? # sapdatabase_monitor() { strict=$1 rc=$OCF_SUCCESS case $DBTYPE in ADA) x_server_status if [ $? -ne $OCF_SUCCESS ]; then x_server_start; fi ;; ORA) listener_status if [ $? -ne $OCF_SUCCESS ]; then listener_start; fi ;; esac if [ $strict -eq 0 ] then sapdatabase_status rc=$? else if [ $DBJ2EE_ONLY -eq 0 ] then output=`echo "$SAPDBCONNECT -d -w /dev/null" | su $sidadm 2>&1` if [ $? -le 4 ] then rc=$OCF_SUCCESS else rc=$OCF_NOT_RUNNING fi else MYCP="" EXECMD="" # WebAS Java 6.40+7.00 IAIK_JCE="$SECSTORE"/iaik_jce.jar IAIK_JCE_EXPORT="$SECSTORE"/iaik_jce_export.jar EXCEPTION="$BOOTSTRAP"/exception.jar LOGGING="$BOOTSTRAP"/logging.jar OPENSQLSTA="$BOOTSTRAP"/opensqlsta.jar TC_SEC_SECSTOREFS="$BOOTSTRAP"/tc_sec_secstorefs.jar JDDI="$BOOTSTRAP"/../server0/bin/ext/jdbdictionary/jddi.jar ANTLR="$BOOTSTRAP"/../server0/bin/ext/antlr/antlr.jar FRAME="$BOOTSTRAP"/../server0/bin/system/frame.jar # only start jdbcconnect when all jars available if [ -f "$EXCEPTION" -a -f "$LOGGING" -a -f "$OPENSQLSTA" -a -f "$TC_SEC_SECSTOREFS" -a -f "$JDDI" -a -f "$ANTLR" -a -f "$FRAME" -a -f "$SAPDBCONNECT" ] then MYCP=".:$FRAME:$ANTLR:$JDDI:$IAIK_JCE_EXPORT:$IAIK_JCE:$EXCEPTION:$LOGGING:$OPENSQLSTA:$TC_SEC_SECSTOREFS:$DB_JARS:$SAPDBCONNECT" EXECMD="com.sap.inst.jdbc.connect.JdbcCon -sec $SID:$SID" else # WebAS Java 7.10 LAUNCHER=${BOOTSTRAP}/sap.com~tc~bl~offline_launcher~impl.jar if [ -f "$DB_JARS" -a -f "$SAPDBCONNECT" -a -f "$LAUNCHER" ] then MYCP="$LAUNCHER" EXECMD="com.sap.engine.offline.OfflineToolStart com.sap.inst.jdbc.connect.JdbcCon ${SAPDBCONNECT}:${SECSTORE}:${DB_JARS}:${BOOTSTRAP} -sec $SID:$SID" fi fi if [ -n "$EXECMD" ] then output=`eval ${JAVA_HOME}/bin/java -cp $MYCP $EXECMD` if [ $? -le 0 ] then rc=$OCF_SUCCESS else rc=$OCF_NOT_RUNNING fi else output="Cannot find all jar files needed for database monitoring." rc=$OCF_ERR_GENERIC fi fi fi if [ $rc -ne $OCF_SUCCESS ] then ocf_log err "The SAP database $SID ist not running: $output" fi return $rc } # # sapdatabase_status: Are there any database processes on this host ? # sapdatabase_status() { case $DBTYPE in ADA) SEARCH="$SID/db/pgm/kernel" SUSER=`grep "^SdbOwner" /etc/opt/sdb | awk -F'=' '{print $2}'` SNUM=2 ;; ORA) SEARCH="ora_[a-z][a-z][a-z][a-z]_" SUSER="ora`echo $SID | tr [:upper:] [:lower:]`" SNUM=4 ;; DB6) SEARCH="db2[a-z][a-z][a-z][a-z][a-z]" SUSER="db2`echo $SID | tr [:upper:] [:lower:]`" SNUM=5 ;; esac # Note: ps cuts off it's output at column $COLUMNS, so "ps -ef" can not be used here # as the output might be to long. cnt=`ps efo args --user $SUSER 2> /dev/null | grep -c "$SEARCH"` if [ $cnt -ge $SNUM ] then rc=$OCF_SUCCESS else # ocf_log info "Database Instance $SID is not running on `hostname`" rc=$OCF_NOT_RUNNING fi return $rc } # # sapdatabase_recover: # sapdatabase_recover() { case $DBTYPE in ORA) recoutput=`oracle_recover` ;; ADA) recoutput=`maxdb_recover` ;; DB6) recoutput=`db6udb_recover` ;; esac sapdatabase_monitor 1 retcode=$? if [ $retcode -eq $OCF_SUCCESS ] then ocf_log info "Recover of SAP database $SID was successful: $recoutput" else ocf_log err "Recover of SAP database $SID failed: $recoutput" fi return $retcode } # # sapdatabase_validate: Check the symantic of the input parameters # sapdatabase_validate() { rc=$OCF_SUCCESS if [ `echo "$SID" | grep -c '^[A-Z][A-Z0-9][A-Z0-9]$'` -ne 1 ] then ocf_log err "Parsing parameter SID: '$SID' is not a valid system ID!" rc=$OCF_ERR_ARGS fi case "$DBTYPE" in ORA|ADA|DB6) ;; *) ocf_log err "Parsing parameter DBTYPE: '$DBTYPE' is not a supported database type!" rc=$OCF_ERR_ARGS ;; esac return $rc } # # 'main' starts here... # if ( [ $# -ne 1 ] ) then usage exit $OCF_ERR_ARGS fi # Set a tempfile and make sure to clean it up again TEMPFILE="/tmp/SAPDatabase.$$.tmp" trap trap_handler INT TERM # These operations don't require OCF instance parameters to be set case "$1" in meta-data) meta_data exit $OCF_SUCCESS;; usage) usage exit $OCF_SUCCESS;; methods) sapdatabase_methods exit $?;; *);; esac US=`id -u -n` US=`echo $US` if [ $US != root ] then ocf_log err "$0 must be run as root" exit $OCF_ERR_PERM fi # mandatory parameter check if [ -z "$OCF_RESKEY_SID" ]; then ocf_log err "Please set OCF_RESKEY_SID to the SAP system id!" exit $OCF_ERR_ARGS fi SID=`echo "$OCF_RESKEY_SID"` if [ -z "$OCF_RESKEY_DBTYPE" ]; then ocf_log err "Please set OCF_RESKEY_DBTYPE to the database vendor specific tag (ORA,ADA,DB6)!" exit $OCF_ERR_ARGS fi DBTYPE=`echo "$OCF_RESKEY_DBTYPE" | tr "[a-z]" "[A-Z]"` # optional OCF parameters, we try to guess which directories are correct EXESTARTDB="startdb" EXESTOPDB="stopdb" EXEDBCONNECT="R3trans" if [ -z "$OCF_RESKEY_DBJ2EE_ONLY" ]; then DBJ2EE_ONLY=0 else case "$OCF_RESKEY_DBJ2EE_ONLY" in 1|true|TRUE|yes|YES) DBJ2EE_ONLY=1 EXESTARTDB="startj2eedb" EXESTOPDB="stopj2eedb" EXEDBCONNECT="jdbcconnect.jar" ;; 0|false|FALSE|no|NO) DBJ2EE_ONLY=0;; *) ocf_log err "Parsing parameter DBJ2EE_ONLY: '$DBJ2EE_ONLY' is not a boolean value!" exit $OCF_ERR_ARGS ;; esac fi if [ -z "$OCF_RESKEY_NETSERVICENAME" ]; then case "$DBTYPE" in ORA|ora) NETSERVICENAME="LISTENER";; *) NETSERVICENAME="";; esac else NETSERVICENAME="$OCF_RESKEY_NETSERVICENAME" fi if [ -z "$OCF_RESKEY_STRICT_MONITORING" ]; then OCF_RESKEY_STRICT_MONITORING=0 else case "$OCF_RESKEY_STRICT_MONITORING" in 1|true|TRUE|yes|YES) OCF_RESKEY_STRICT_MONITORING=1;; 0|false|FALSE|no|NO) OCF_RESKEY_STRICT_MONITORING=0;; *) ocf_log err "Parsing parameter STRICT_MONITORING: '$OCF_RESKEY_STRICT_MONITORING' is not a boolean value!" exit $OCF_ERR_ARGS ;; esac fi PATHLIST=" $OCF_RESKEY_DIR_EXECUTABLE /usr/sap/$SID/*/exe /usr/sap/$SID/SYS/exe/run /sapmnt/$SID/exe " DIR_EXECUTABLE="" for EXEPATH in $PATHLIST do if [ -x $EXEPATH/$EXESTARTDB -a -x $EXEPATH/$EXESTOPDB -a -x $EXEPATH/$EXEDBCONNECT ] then DIR_EXECUTABLE=$EXEPATH SAPSTARTDB=$EXEPATH/$EXESTARTDB SAPSTOPDB=$EXEPATH/$EXESTOPDB SAPDBCONNECT=$EXEPATH/$EXEDBCONNECT break fi done if [ -z "$DIR_EXECUTABLE" ] then ocf_log warn "Cannot find $EXESTARTDB,$EXESTOPDB and $EXEDBCONNECT executable, please set DIR_EXECUTABLE parameter!" exit $OCF_NOT_RUNNING fi if [ $DBJ2EE_ONLY -eq 1 ] then if [ -n "$OCF_RESKEY_DIR_BOOTSTRAP" ] then BOOTSTRAP="$OCF_RESKEY_DIR_BOOTSTRAP" else BOOTSTRAP=`echo /usr/sap/$SID/*/j2ee/cluster/bootstrap | head -1` fi if [ -n "$OCF_RESKEY_DIR_SECSTORE" ] then SECSTORE="$OCF_RESKEY_DIR_SECSTORE" else SECSTORE=/usr/sap/$SID/SYS/global/security/lib/tools fi if [ -n "$OCF_RESKEY_JAVA_HOME" ] then JAVA_HOME="$OCF_RESKEY_JAVA_HOME" PATH=$JAVA_HOME/bin:$PATH else if [ -n "$JAVA_HOME" ] then PATH=$JAVA_HOME/bin:$PATH else ocf_log err "Cannot find JAVA_HOME directory, please set JAVA_HOME parameter!" exit $OCF_NOT_RUNNING fi fi if [ -n "$OCF_RESKEY_DB_JARS" ] then DB_JARS=$OCF_RESKEY_DB_JARS else if [ -f "$BOOTSTRAP"/bootstrap.properties ]; then DB_JARS=`cat $BOOTSTRAP/bootstrap.properties | grep -i rdbms.driverLocation | sed -e 's/\\\:/:/g' | awk -F= '{print $2}'` fi fi fi if [ -z "$OCF_RESKEY_AUTOMATIC_RECOVER" ] then OCF_RESKEY_AUTOMATIC_RECOVER=0 else case "$OCF_RESKEY_AUTOMATIC_RECOVER" in 1|true|TRUE|yes|YES) OCF_RESKEY_AUTOMATIC_RECOVER=1;; 0|false|FALSE|no|NO) OCF_RESKEY_AUTOMATIC_RECOVER=0;; esac fi # as root user we need the library path to the SAP kernel to be able to call executables if [ `echo $LD_LIBRARY_PATH | grep -c "^$DIR_EXECUTABLE\>"` -eq 0 ]; then LD_LIBRARY_PATH=$DIR_EXECUTABLE:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH fi sidadm="`echo $SID | tr [:upper:] [:lower:]`adm" # What kind of method was invoked? case "$1" in start) sapdatabase_start exit $?;; stop) sapdatabase_stop exit $?;; monitor) sapdatabase_monitor $OCF_RESKEY_STRICT_MONITORING exit $?;; status) sapdatabase_status exit $?;; recover) sapdatabase_recover exit $?;; validate-all) sapdatabase_validate exit $?;; *) sapdatabase_methods exit $OCF_ERR_UNIMPLEMENTED;; esac diff --git a/heartbeat/SAPInstance b/heartbeat/SAPInstance index db790e707..582cf1f87 100644 --- a/heartbeat/SAPInstance +++ b/heartbeat/SAPInstance @@ -1,771 +1,771 @@ #!/bin/sh # # SAPInstance # # Description: Manages a single SAP Instance as a High-Availability # resource. One SAP Instance is defined by one # SAP Instance-Profile. start/stop handels all services # of the START-Profile, status and monitor care only # about essential services. # # Author: Alexander Krauth, June 2006 # Support: linux@sap.com # License: GNU General Public License (GPL) # Copyright: (c) 2006-2008 Alexander Krauth # # An example usage: # See usage() function below for more details... # # OCF instance parameters: # OCF_RESKEY_InstanceName # OCF_RESKEY_DIR_EXECUTABLE (optional, well known directories will be searched by default) # OCF_RESKEY_DIR_PROFILE (optional, well known directories will be searched by default) # OCF_RESKEY_START_PROFILE (optional, well known directories will be searched by default) # OCF_RESKEY_START_WAITTIME (optional, to solve timing problems during J2EE-Addin start) # OCF_RESKEY_AUTOMATIC_RECOVER (optional, automatic startup recovery using cleanipc, default is false) # OCF_RESKEY_MONITOR_SERVICES (optional, default is to monitor critical services only) # OCF_RESKEY_ERS_InstanceName (optional, InstanceName of the ERS instance in a Master/Slave configuration) # OCF_RESKEY_ERS_START_PROFILE (optional, START_PROFILE of the ERS instance in a Master/Slave configuration) # OCF_RESKEY_PRE_START_USEREXIT (optional, lists a script which can be executed before the resource is started) # OCF_RESKEY_POST_START_USEREXIT (optional, lists a script which can be executed after the resource is started) # OCF_RESKEY_PRE_STOP_USEREXIT (optional, lists a script which can be executed before the resource is stopped) # OCF_RESKEY_POST_STOP_USEREXIT (optional, lists a script which can be executed after the resource is stopped) # ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### SH=/bin/sh sapinstance_usage() { methods=`sapinstance_methods` methods=`echo $methods | tr ' ' '|'` cat <<-! usage: $0 ($methods) $0 manages a SAP Instance as an HA resource. The 'start' operation starts the instance or the ERS instance in a Master/Slave configuration The 'stop' operation stops the instance The 'status' operation reports whether the instance is running The 'monitor' operation reports whether the instance seems to be working The 'promote' operation starts the primary instance in a Master/Slave configuration The 'demote' operation stops the primary instance and starts the ERS instance The 'notify' operation always returns SUCCESS The 'validate-all' operation reports whether the parameters are valid The 'methods' operation reports on the methods $0 supports ! } sapinstance_meta_data() { cat < 2.01 Resource script for SAP. It manages a SAP Instance as an HA resource. SAP instance resource agent The full qualified SAP instance name. e.g. P01_DVEBMGS00_sapp01ci instance name: SID_INSTANCE_VIR-HOSTNAME The full qualified path where to find sapstartsrv and sapcontrol. path of sapstartsrv and sapcontrol The full qualified path where to find the SAP START profile. path of start profile The name of the SAP START profile. start profile name After that time in seconds a monitor operation is executed by the resource agent. Does the monitor return SUCCESS, the start is handled as SUCCESS. This is useful to resolve timing problems with e.g. the J2EE-Addin instance. Check the successful start after that time (do not wait for J2EE-Addin) The SAPInstance resource agent tries to recover a failed start attempt automaticaly one time. This is done by killing runing instance processes and executing cleanipc. Enable or disable automatic startup recovery The full qualified path where to find a script or program which should be executed before this resource gets started. path to a pre-start script The full qualified path where to find a script or program which should be executed after this resource got started. path to a post-start script The full qualified path where to find a script or program which should be executed before this resource gets stopped. path to a pre-start script The full qualified path where to find a script or program which should be executed after this resource got stopped. path to a post-start script - + END } # # methods: What methods/operations do we support? # sapinstance_methods() { cat <<-! start stop status monitor promote demote notify validate-all methods meta-data usage ! } # # is_clone : find out if we are configured to run in a Master/Slave configuration # is_clone() { if [ -n "$OCF_RESKEY_CRM_meta_clone_max" ] \ && [ "$OCF_RESKEY_CRM_meta_clone_max" -gt 0 ] then if [ "$OCF_RESKEY_CRM_meta_clone_max" -ne 2 ] || \ [ "$OCF_RESKEY_CRM_meta_clone_node_max" -ne 1 ] || \ [ "$OCF_RESKEY_CRM_meta_master_node_max" -ne 1 ] || \ [ "$OCF_RESKEY_CRM_meta_master_max" -ne 1 ] then ocf_log err "Clone options misconfigured. (expect: clone_max=2,clone_node_max=1,master_node_max=1,master_max=1)" exit $OCF_ERR_CONFIGURED fi if [ -z "$OCF_RESKEY_ERS_InstanceName" ] then ocf_log err "In a Master/Slave configuration the ERS_InstanceName parameter is mandatory." exit $OCF_ERR_ARGS fi else return 0 fi return 1 } # # sapinstance_init : Define global variables with default values, if optional parameters are not set # # sapinstance_init() { myInstanceName="$1" SID=`echo "$myInstanceName" | cut -d_ -f1` InstanceName=`echo "$myInstanceName" | cut -d_ -f2` InstanceNr=`echo "$InstanceName" | sed 's/.*\([0-9][0-9]\)$/\1/'` SAPVIRHOST=`echo "$myInstanceName" | cut -d_ -f3` # optional OCF parameters, we try to guess which directories are correct if [ -z "$OCF_RESKEY_DIR_EXECUTABLE" ] then if [ -x /usr/sap/$SID/$InstanceName/exe/sapstartsrv -a -x /usr/sap/$SID/$InstanceName/exe/sapcontrol ] then DIR_EXECUTABLE="/usr/sap/$SID/$InstanceName/exe" SAPSTARTSRV="/usr/sap/$SID/$InstanceName/exe/sapstartsrv" SAPCONTROL="/usr/sap/$SID/$InstanceName/exe/sapcontrol" elif [ -x /usr/sap/$SID/SYS/exe/run/sapstartsrv -a -x /usr/sap/$SID/SYS/exe/run/sapcontrol ] then DIR_EXECUTABLE="/usr/sap/$SID/SYS/exe/run" SAPSTARTSRV="/usr/sap/$SID/SYS/exe/run/sapstartsrv" SAPCONTROL="/usr/sap/$SID/SYS/exe/run/sapcontrol" else ocf_log warn "Cannot find sapstartsrv and sapcontrol executable, please set DIR_EXECUTABLE parameter!" exit $OCF_NOT_RUNNING fi else DIR_EXECUTABLE="$OCF_RESKEY_DIR_EXECUTABLE" SAPSTARTSRV="$OCF_RESKEY_DIR_EXECUTABLE/sapstartsrv" SAPCONTROL="$OCF_RESKEY_DIR_EXECUTABLE/sapcontrol" fi if [ -z "$OCF_RESKEY_DIR_PROFILE" ] then if [ -d /usr/sap/$SID/SYS/profile/ ] then DIR_PROFILE="/usr/sap/$SID/SYS/profile" else ocf_log warn "Expected /usr/sap/$SID/SYS/profile/ to be a directory, please set DIR_PROFILE parameter!" exit $OCF_NOT_RUNNING fi else DIR_PROFILE="$OCF_RESKEY_DIR_PROFILE" fi if [ "$myInstanceName" != "$OCF_RESKEY_InstanceName" ] then currentSTART_PROFILE=$OCF_RESKEY_ERS_START_PROFILE else currentSTART_PROFILE=$OCF_RESKEY_START_PROFILE fi if [ -z "$currentSTART_PROFILE" ] then SAPSTARTPROFILE="$DIR_PROFILE/START_${InstanceName}_${SAPVIRHOST}" if [ ! -r $SAPSTARTPROFILE ] then ocf_log warn "Expected $SAPSTARTPROFILE to be the instance START profile, please set START_PROFILE parameter!" exit $OCF_NOT_RUNNING fi else SAPSTARTPROFILE="$currentSTART_PROFILE" fi if [ -z "$OCF_RESKEY_START_WAITTIME" ] then export OCF_RESKEY_START_WAITTIME=3600 fi if [ -z "$OCF_RESKEY_AUTOMATIC_RECOVER" ] then OCF_RESKEY_AUTOMATIC_RECOVER=0 else case "$OCF_RESKEY_AUTOMATIC_RECOVER" in 1|true|TRUE|yes|YES) export OCF_RESKEY_AUTOMATIC_RECOVER=1;; 0|false|FALSE|no|NO) export OCF_RESKEY_AUTOMATIC_RECOVER=0;; esac fi if [ -z "$OCF_RESKEY_MONITOR_SERVICES" ] then export OCF_RESKEY_MONITOR_SERVICES="disp+work|msg_server|enserver|enrepserver|jcontrol|jstart" fi # as root user we need the library path to the SAP kernel to be able to call sapcontrol if [ `echo $LD_LIBRARY_PATH | grep -c "^$DIR_EXECUTABLE\>"` -eq 0 ]; then LD_LIBRARY_PATH=$DIR_EXECUTABLE:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH fi sidadm="`echo $SID | tr [:upper:] [:lower:]`adm" return $OCF_SUCCESS } # # check_sapstartsrv : Before using sapcontrol we make sure that the sapstartsrv is running for the correct instance. # We cannot use sapinit and the /usr/sap/sapservices file in case of an enquerep instance, # because then we have two instances with the same instance number. # check_sapstartsrv() { restart=0 runninginst="" chkrc=$OCF_SUCCESS output=`$SAPCONTROL -nr $InstanceNr -function ParameterValue INSTANCE_NAME -format script` if [ $? -eq 0 ] then runninginst=`echo "$output" | grep '^0 : ' | cut -d' ' -f3` if [ "$runninginst" != "$InstanceName" ] then ocf_log warn "sapstartsrv is running for instance $runninginst, that service will be killed" restart=1 fi else ocf_log warn "sapstartsrv is not running for instance $SID-$InstanceName, it will be started now" restart=1 fi if [ -z "$runninginst" ]; then runninginst=$InstanceName; fi if [ $restart -eq 1 ] then pkill -9 -f "sapstartsrv.*$runninginst" $SAPSTARTSRV pf=$SAPSTARTPROFILE -D -u $sidadm # now make sure the daemon has been started and is able to respond srvrc=1 while [ $srvrc -eq 1 -a `pgrep -f "sapstartsrv.*$runninginst" | wc -l` -gt 0 ] do sleep 1 $SAPCONTROL -nr $InstanceNr -function GetProcessList > /dev/null 2>&1 srvrc=$? done if [ $srvrc -ne 1 ] then ocf_log info "sapstartsrv for instance $SID-$InstanceName was restarted !" chkrc=$OCF_SUCCESS else ocf_log error "sapstartsrv for instance $SID-$InstanceName could not be started!" chkrc=$OCF_NOT_RUNNING fi fi return $chkrc } # # sapuserexit : Many SAP customers need some additional processes/tools to run their SAP systems. # This specialties do not allow a totally generic SAP cluster resource agent. # Someone should write a resource agent for each additional process you need, if it # is required to monitor that process within the cluster manager. To enable # you to extent this resource agent without developing a new one, this user exit # was introduced. # sapuserexit() { NAME="$1" VALUE="$2" if [ -n "$VALUE" ] then if [ -x "$VALUE" ] then ocf_log info "Calling userexit ${NAME} with customer script file ${VALUE}" eval "$VALUE" >& /dev/null ocf_log info "Exiting userexit ${NAME} with customer script file ${VALUE}, returncode: $?" else ocf_log warn "Attribute ${NAME} is set to ${VALUE}, but this file is not executable" fi fi return 0 } # # cleanup_instance : remove resources (processes and shared memory) from a crashed instance) # cleanup_instance() { pkill -9 -f -U $sidadm $InstanceName $DIR_EXECUTABLE/cleanipc $InstanceNr remove return 0 } # # sapinstance_start : Start the SAP instance # sapinstance_start() { sapuserexit PRE_START_USEREXIT "$OCF_RESKEY_PRE_START_USEREXIT" rc=$OCF_NOT_RUNNING loopcount=0 while [ $loopcount -lt 2 ] do loopcount=$(($loopcount + 1)) check_sapstartsrv output=`$SAPCONTROL -nr $InstanceNr -function Start` rc=$? ocf_log info "Starting SAP Instance $SID-$InstanceName: $output" if [ $rc -ne 0 ] then ocf_log err "SAP Instance $SID-$InstanceName start failed." return $OCF_ERR_GENERIC fi startrc=1 while [ $startrc -gt 0 ] do waittime_start=`date +%s` output=`$SAPCONTROL -nr $InstanceNr -function WaitforStarted $OCF_RESKEY_START_WAITTIME 10` startrc=$? waittime_stop=`date +%s` if [ $startrc -ne 0 ] then if [ $(($waittime_stop - $waittime_start)) -ge $OCF_RESKEY_START_WAITTIME ] then sapinstance_monitor NOLOG if [ $? -eq $OCF_SUCCESS ] then output="START_WAITTIME ($OCF_RESKEY_START_WAITTIME) has elapsed, but instance monitor returned SUCCESS. Instance considered running." startrc=0; loopcount=2 fi else if [ $loopcount -eq 1 -a $OCF_RESKEY_AUTOMATIC_RECOVER -eq 1 ] then ocf_log warn "SAP Instance $SID-$InstanceName start failed: $output" ocf_log warn "Try to recover $SID-$InstanceName" cleanup_instance else loopcount=2 fi startrc=-1 fi else loopcount=2 fi done done if [ $startrc -eq 0 ] then ocf_log info "SAP Instance $SID-$InstanceName started: $output" rc=$OCF_SUCCESS sapuserexit POST_START_USEREXIT "$OCF_RESKEY_POST_START_USEREXIT" else ocf_log err "SAP Instance $SID-$InstanceName start failed: $output" rc=$OCF_NOT_RUNNING fi return $rc } # # sapinstance_recover: Try startup of failed instance by cleaning up resources # sapinstance_recover() { cleanup_instance sapinstance_start return $? } # # sapinstance_stop: Stop the SAP instance # sapinstance_stop() { sapuserexit PRE_STOP_USEREXIT "$OCF_RESKEY_PRE_STOP_USEREXIT" check_sapstartsrv output=`$SAPCONTROL -nr $InstanceNr -function Stop` if [ $? -eq 0 ] then output=`$SAPCONTROL -nr $InstanceNr -function WaitforStopped 3600 1` if [ $? -eq 0 ] then ocf_log info "SAP Instance $SID-$InstanceName stopped: $output" rc=$OCF_SUCCESS else ocf_log err "SAP Instance $SID-$InstanceName stop failed: $output" rc=$OCF_ERR_GENERIC fi else ocf_log err "SAP Instance $SID-$InstanceName stop failed: $output" rc=$OCF_ERR_GENERIC fi sapuserexit POST_STOP_USEREXIT "$OCF_RESKEY_POST_STOP_USEREXIT" return $rc } # # sapinstance_monitor: Can the given SAP instance do anything useful? # sapinstance_monitor() { MONLOG=$1 check_sapstartsrv rc=$? if [ $rc -eq $OCF_SUCCESS ] then count=0 LOCALHOST=`hostname` output=`$SAPCONTROL -nr $InstanceNr -host $LOCALHOST -function GetProcessList -format script` # we have to parse the output, because the returncode doesn't tell anything about the instance status for SERVNO in `echo "$output" | grep '^[0-9] ' | cut -d' ' -f1 | sort -u` do COLOR=`echo "$output" | grep "^$SERVNO dispstatus: " | cut -d' ' -f3` SERVICE=`echo "$output" | grep "^$SERVNO name: " | cut -d' ' -f3` STATE=0 case $COLOR in GREEN|YELLOW) STATE=$OCF_SUCCESS;; *) STATE=$OCF_NOT_RUNNING;; esac SEARCH=`echo "$OCF_RESKEY_MONITOR_SERVICES" | sed 's/\+/\\\+/g' | sed 's/\./\\\./g'` if [ `echo "$SERVICE" | egrep -c "$SEARCH"` -eq 1 ] then if [ $STATE -eq $OCF_NOT_RUNNING ] then if [ "$MONLOG" != "NOLOG" ] then ocf_log err "SAP instance service $SERVICE is not running with status $COLOR !" fi rc=$STATE fi count=1 fi done if [ $count -eq 0 -a $rc -eq $OCF_SUCCESS ] then if [ "$MONLOG" != "NOLOG" ] then ocf_log err "The SAP instance does not run any services which this RA could monitor!" fi rc=$OCF_ERR_ARGS fi fi return $rc } # # sapinstance_validate: Check the symantic of the input parameters # sapinstance_validate() { rc=$OCF_SUCCESS if [ `echo "$SID" | grep -c '^[A-Z][A-Z0-9][A-Z0-9]$'` -ne 1 ] then ocf_log err "Parsing instance profile name: '$SID' is not a valid system ID!" rc=$OCF_ERR_ARGS fi if [ `echo "$InstanceName" | grep -c '^[A-Z].*[0-9][0-9]$'` -ne 1 ] then ocf_log err "Parsing instance profile name: '$InstanceName' is not a valid instance name!" rc=$OCF_ERR_ARGS fi if [ `echo "$InstanceNr" | grep -c '^[0-9][0-9]$'` -ne 1 ] then ocf_log err "Parsing instance profile name: '$InstanceNr' is not a valid instance number!" rc=$OCF_ERR_ARGS fi if [ `echo "$SAPVIRHOST" | grep -c '^[A-Za-z][A-Za-z0-9_-]*$'` -ne 1 ] then ocf_log err "Parsing instance profile name: '$SAPVIRHOST' is not a valid hostname!" rc=$OCF_ERR_ARGS fi return $rc } # # sapinstance_start_clone # sapinstance_start_clone() { sapinstance_init $OCF_RESKEY_ERS_InstanceName ${HA_SBIN_DIR}/crm_master -v 100 -l reboot sapinstance_start return $? } # # sapinstance_stop_clone # sapinstance_stop_clone() { sapinstance_init $OCF_RESKEY_ERS_InstanceName ${HA_SBIN_DIR}/crm_master -v 0 -l reboot sapinstance_stop return $? } # # sapinstance_monitor_clone # sapinstance_monitor_clone() { # resource agents running in Master mode must return other returncodes than default if [ "$OCF_RESKEY_CRM_meta_op_target_rc" -eq $OCF_RUNNING_MASTER ] then sapinstance_init $OCF_RESKEY_InstanceName sapinstance_monitor case "$?" in $OCF_SUCCESS) return $OCF_RUNNING_MASTER;; $OCF_NOT_RUNNING) ${HA_SBIN_DIR}/crm_master -v 10 -l reboot return $OCF_FAILED_MASTER;; *) return $?;; esac else sapinstance_init $OCF_RESKEY_ERS_InstanceName sapinstance_monitor return $? fi } # # sapinstance_promote_clone: In a Master/Slave configuration get Master by starting the SCS instance and stopping the ERS instance # The order is important here to behave correct from the application levels view # sapinstance_promote_clone() { sapinstance_init $OCF_RESKEY_InstanceName ocf_log info "Promoting $SID-$InstanceName to running Master." sapinstance_start rc=$? if [ $rc -eq $OCF_SUCCESS ]; then sapinstance_init $OCF_RESKEY_ERS_InstanceName sapinstance_stop rc=$? fi return $rc } # # sapinstance_demote_clone: In a Master/Slave configuration get Slave by stopping the SCS instance and starting the ERS instance # sapinstance_demote_clone() { sapinstance_init $OCF_RESKEY_InstanceName ocf_log info "Demoting $SID-$InstanceName to a slave." sapinstance_stop rc=$? if [ $rc -eq $OCF_SUCCESS ]; then sapinstance_init $OCF_RESKEY_ERS_InstanceName sapinstance_start rc=$? fi return $rc } # # sapinstance_notify: After promotion of one master in the cluster, we make sure that all clones reset thier master # value back to 100. This is because a failed monitor on a master might have degree one clone # instance to score 10. # sapinstance_notify() { local n_type="$OCF_RESKEY_CRM_meta_notify_type" local n_op="$OCF_RESKEY_CRM_meta_notify_operation" if [ "${n_type}_${n_op}" = "post_promote" ]; then ${HA_SBIN_DIR}/crm_master -v 100 -l reboot fi } # # 'main' starts here... # ## GLOBALS SID="" sidadm="" InstanceName="" InstanceNr="" SAPVIRHOST="" DIR_EXECUTABLE="" SAPSTARTSRV="" SAPCONTROL="" DIR_PROFILE="" SAPSTARTPROFILE="" CLONE=0 if ( [ $# -ne 1 ] ) then sapinstance_usage exit $OCF_ERR_ARGS fi ACTION=$1 if [ "$ACTION" = "status" ]; then ACTION=monitor fi # These operations don't require OCF instance parameters to be set case "$ACTION" in usage|methods) sapinstance_$ACTION exit $OCF_SUCCESS;; meta-data) sapinstance_meta_data exit $OCF_SUCCESS;; notify) sapinstance_notify exit $OCF_SUCCESS;; *);; esac US=`id -u -n` US=`echo $US` if [ $US != root ] then ocf_log err "$0 must be run as root" exit $OCF_ERR_PERM fi # parameter check if [ -z "$OCF_RESKEY_InstanceName" ] then ocf_log err "Please set OCF_RESKEY_InstanceName to the name to the SAP instance profile!" exit $OCF_ERR_ARGS fi is_clone; CLONE=$? if [ ${CLONE} -eq 1 ] then CLACT=_clone else sapinstance_init $OCF_RESKEY_InstanceName fi # What kind of method was invoked? case "$ACTION" in start|stop|monitor|promote|demote) sapinstance_$ACTION$CLACT exit $?;; validate-all) sapinstance_validate exit $?;; *) sapinstance_methods exit $OCF_ERR_UNIMPLEMENTED;; esac diff --git a/heartbeat/SendArp b/heartbeat/SendArp index 7567ee96e..2f7a21fe3 100644 --- a/heartbeat/SendArp +++ b/heartbeat/SendArp @@ -1,252 +1,252 @@ #!/bin/sh # # # Copyright (c) 2006, Huang Zhen # Converting original heartbeat RA to OCF RA. # # Copyright (C) 2004 Horms # # Based on IPaddr2: Copyright (C) 2003 Tuomo Soini # # License: GNU General Public License (GPL) # Support: linux-ha@lists.linux-ha.org # # This script send out gratuitous Arp for an IP address # # It can be used _instead_ of the IPaddr2 or IPaddr resource # to send gratuitous arp for an IP address on a given interface, # without adding the address to that interface. I.e. if for # some reason you want to send gratuitous arp for addresses # managed by IPaddr2 or IPaddr on an additional interface. # # OCF parameters are as below: # OCF_RESKEY_ip # OCF_RESKEY_nic # # # 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_ROOT}/resource.d/heartbeat/.ocf-shellfuncs SENDARP=$HA_BIN/send_arp VLDIR=${HA_RSCTMP}/IPaddr SENDARPPIDDIR=${HA_RSCTMP}/send_arp BASEIP="$OCF_RESKEY_ip" INTERFACE="$OCF_RESKEY_nic" RESIDUAL="" SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$BASEIP" # Set default values : ${ARP_INTERVAL_MS=200} # milliseconds between ARPs : ${ARP_REPEAT=5} # repeat count : ${ARP_BACKGROUND=yes} # no to run in foreground : ${ARP_NETMASK=ffffffffffff} # netmask for ARP ####################################################################### sendarp_meta_data() { cat < 1.0 This script send out gratuitous Arp for an IP address SendArp resource agent The IP address for sending arp package. IP address The nic for sending arp package. NIC - + END } ####################################################################### sendarp_usage() { cat < 1.0 Resource script for ServeRAID. It enables/disables shared ServeRAID merge groups. ServeRAID resource agent The adapter number of the ServeRAID adapter. serveraid The logical drive under consideration. mergegroup - - + + END } ServeRAID_methods() { cat <<-! start stop status validate-all methods usage meta-data ! } ServeRAIDSCSI="/proc/scsi/ips" IPS=ipssend proc_scsi=/proc/scsi/scsi parseinst() { sr_adapter=error sr_mergegroup=error hostid=error sr_logicaldrivenumber=error if [ $# -ne 2 ] then ocf_log err "Invalid ServeRAID instance: $*" exit $OCF_ERR_ARGS fi PerlScript='next unless /^Host/; $_ .= <>.<>; print "$1 " if /SERVERAID/ and /Proces/ and /scsi(\d+)/' # Get the list of host ids of the ServeRAID host adapters hostlist=`$PERL -ne "${PerlScript}" <$proc_scsi` # Figure the host id of the desired ServeRAID adapter hostid=`echo $hostlist | cut -d' ' -f$1` if [ ! -f "$ServeRAIDSCSI/$hostid" ] then ocf_log err "No such ServeRAID adapter: $1" exit $OCF_ERR_ARGS fi case $2 in [1-8]);; *) ocf_log err "Invalid Shared Merge Group Number: $2" exit $OCF_ERR_ARGS;; esac sr_adapter=$1 sr_mergegroup=$2 CheckRaidLevel return $? } SRLogicalDriveConfig() { $IPS getconfig $sr_adapter ld } MergeGroupToSCSI_ID() { PerlScript="while (<>) { /logical drive number *([0-9]+)/i && (\$ld=\$1); /part of merge group *: *$sr_mergegroup *\$/i && print \$ld - 1, \"\n\"; }" ID=`SRLogicalDriveConfig | $PERL -e "$PerlScript"` case $ID in [0-9]*) echo "$ID"; return 0;; *) return 1;; esac } MergeGroupRaidLevel() { PerlScript="while (<>) { /RAID level *: *([0-9]+[A-Za-z]*)/i && (\$ld=\$1); /part of merge group *: *$sr_mergegroup *\$/i && print \$ld, \"\n\"; }" Level=`SRLogicalDriveConfig | $PERL -e "$PerlScript"` case $Level in ?*) echo "$Level"; return 0;; *) return 1;; esac } CheckRaidLevel() { RAIDlevel=`MergeGroupRaidLevel` case $RAIDlevel in *5*) ocf_log err "ServeRAID device $sr_adapter $sr_mergegroup is RAID level $RAIDlevel" ocf_log err "This level of ServeRAID RAID is not supported for failover by the firmware." exit $OCF_ERR_GENERIC;; esac return $OCF_SUCCESS } ReleaseSCSI() { targetid=`MergeGroupToSCSI_ID` echo "${SCSI}remove-single-device $hostid 0 $targetid 0" > $proc_scsi } AddSCSI() { targetid=`MergeGroupToSCSI_ID` echo "${SCSI}add-single-device $hostid 0 $targetid 0" > $proc_scsi } # # start: Enable the given ServeRAID device # ServeRAID_start() { if ServeRAID_status $serveraid $mergegroup then ocf_log debug "ServeRAID merge group $serveraid $mergegroup is running." return $OCF_SUCCESS else if # # Normally we do a MERGE PARTNER, but if we still own the drive for # some reason, then we'll need to do a MERGE OWN instead... # out=`$IPS MERGE $sr_adapter $sr_mergegroup PARTNER 2>&1` if [ $? -eq $srsuccess ] then ocf_log info "$out" else ocf_run $IPS MERGE $sr_adapter $sr_mergegroup OWN fi then : OK All is well! targetid=`MergeGroupToSCSI_ID` sr_logicaldrivenumber=`expr $targetid + 1` #run $IPS SYNCH $sr_adapter $sr_logicaldrivenumber & # This version of the SYNCH command requires the 6.10 or later # ServeRAID support CD. # To avoid issues when called by lrmd, redirect stdout->stderr. # Use () to create a subshell to make the redirection be synchronized. ( ocf_run $IPS SYNCH $sr_adapter $sr_mergegroup & ) >&2 AddSCSI else return $? fi fi if ServeRAID_status "$@" then return $OCF_SUCCESS else ocf_log err "ServeRAID device $1 not active!" exit $OCF_ERR_GENERIC fi } # # stop: Disable the given ServeRAID device # ServeRAID_stop() { parseinst "$@" ReleaseSCSI if ocf_run $IPS UNMERGE $sr_adapter $sr_mergegroup then : UNMERGE $sr_adapter $sr_mergegroup worked fi if ServeRAID_status "$@" then ocf_log err "ServeRAID device $@ is still active!" return $OCF_ERR_GENERIC else return $OCF_SUCCESS fi } # # status: is the given device now available? # ServeRAID_status() { parseinst "$@" # # The output we're looking for # Part of merge group : 2 # SRLogicalDriveConfig \ | grep -i "part of merge group[ ]*: *$sr_mergegroup *\$" >/dev/null } # # validate_all: are the OCF instance parameters valid? # ServeRAID_validate_all() { check_binary $PERL # parseinst() will do all the work... parseinst "$@" return $? } if ( [ $# -ne 1 ] ) then usage exit $OCF_ERR_ARGS fi # These operations don't require OCF instance parameters to be set case "$1" in meta-data) meta_data exit $OCF_SUCCESS;; # # methods: What methods do we support? # methods) ServeRAID_methods exit $?;; usage) usage exit $OCF_SUCCESS;; *) ;; esac if ( [ -z "$OCF_RESKEY_serveraid" ] || [ -z "$OCF_RESKEY_mergegroup" ] ) then ocf_log err "You have to set the OCF_RESKEY_serveraid and OCF_RESKEY_mergegroup\n enviroment virables before running $0 !" # usage exit $OCF_ERR_GENERIC fi : Right Number of arguments.. serveraid=$OCF_RESKEY_serveraid mergegroup=$OCF_RESKEY_mergegroup # Look for the start, stop, status, or methods calls... case "$1" in stop) ServeRAID_stop $serveraid $mergegroup exit $?;; start) ServeRAID_start $serveraid $mergegroup exit $?;; status|monitor) if ServeRAID_status $serveraid $mergegroup then ocf_log debug "ServeRAID merge group $serveraid $mergegroup is running." exit $OCF_SUCCESS else ocf_log debug "ServeRAID merge group $serveraid $mergegroup is stopped." exit $OCF_NOT_RUNNING fi exit $?;; validate-all) ServeRAID_validate_all $serveraid $mergegroup exit $?;; *) usage exit $OCF_ERR_UNIMPLEMENTED;; esac diff --git a/heartbeat/Squid b/heartbeat/Squid index ed52a2029..589f2dedb 100644 --- a/heartbeat/Squid +++ b/heartbeat/Squid @@ -1,446 +1,446 @@ #!/bin/bash # # 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_ROOT}/resource.d/heartbeat/.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. The RA of Squid 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 This is an omittable parameter. On a stop action, a normal stop method is firstly used. and then the confirmation of its completion is awaited for the specified seconds by this parameter. The default value is 10. Number of seconds to await to confirm a normal stop method 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.*[0-9]+\.[0-9]+\.+[0-9]+\.[0-9]+:'$SQUID_PORT'/{ 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_log err "$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_log err "$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 $status 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_log err "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_log err "SQUID_EXE is not defined" exit $OCF_ERR_CONFIGURED fi if [[ ! -x "$SQUID_EXE" ]]; then ocf_log err "$SQUID_EXE is not found" exit $OCF_ERR_CONFIGURED fi SQUID_PIDFILE="${OCF_RESKEY_squid_pidfile}" if [[ -z "$SQUID_PIDFILE" ]]; then ocf_log err "SQUID_PIDFILE is not defined" exit $OCF_ERR_CONFIGURED fi SQUID_PORT="${OCF_RESKEY_squid_port}" if [[ -z "$SQUID_PORT" ]]; then ocf_log err "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-5}" 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/VIPArip b/heartbeat/VIPArip index febe71467..4a597d1ac 100644 --- a/heartbeat/VIPArip +++ b/heartbeat/VIPArip @@ -1,285 +1,285 @@ #!/bin/sh # # License: GNU General Public License (GPL) # Support: linux-ha@lists.linux-ha.org # Author: Huang Zhen # Copyright (c) 2006 International Business Machines # # Virtual IP Address by RIP2 protocol. # This script manages IP alias in different subnet with quagga/ripd. # It can add an IP alias, or remove one. # # The quagga package should be installed to run this RA # # usage: $0 {start|stop|status|monitor|validate-all|meta-data} # # The "start" arg adds an IP alias. # Surprisingly, the "stop" arg removes one. :-) # # OCF parameters are as below # OCF_RESKEY_ip The IP address in different subnet # OCF_RESKEY_nic The nic for broadcast the route information # ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs HA_HBCONF_DIR=${HA_DIR} VLDIR=$HA_RSCTMP/VIPArip RIPDCONF=$VLDIR/ripd.conf USAGE="usage: $0 {start|stop|status|monitor|validate-all|meta-data}"; ####################################################################### LC_ALL=C export LC_ALL . $HA_HBCONF_DIR/shellfuncs meta_data() { cat < 1.0 Virtual IP Address by RIP2 protocol. This script manages IP alias in different subnet with quagga/ripd. It can add an IP alias, or remove one. Virtual IP Address by RIP2 protocol The IPv4 address in different subnet, for example "192.168.1.1". The IP address in different subnet The nic for broadcast the route information. The ripd uses this nic to broadcast the route informaton to others The nic for broadcast the route information - + END exit $OCF_SUCCESS } usage() { echo $USAGE >&2 } new_config_file() { echo new_config_file $1 $2 $3 cat >$RIPDCONF < $RIPDCONF.tmp cp $RIPDCONF.tmp $RIPDCONF } add_ip() { echo add_ip $1 sed "s/ip_tag/ip_tag\naccess-list private permit $1\/32/g" $RIPDCONF > $RIPDCONF.tmp cp $RIPDCONF.tmp $RIPDCONF } del_ip() { echo del_ip $1 sed "/$1/d" $RIPDCONF > $RIPDCONF.tmp cp $RIPDCONF.tmp $RIPDCONF if $GREP "access-list private permit" $RIPDCONF>/dev/null then echo some other IP is running reload_config else stop_quagga echo remove $RIPDCONF rm $RIPDCONF fi } add_nic() { echo add_nic $1 if $GREP "network $1" $RIPDCONF >/dev/null then echo the nic is already in the config file else sed "s/nic_tag/nic_tag\n no passive-interface $1\n network $1\n distribute-list private out $1\n distribute-list private in $1/g" $RIPDCONF > $RIPDCONF.tmp cp $RIPDCONF.tmp $RIPDCONF fi } reload_config() { echo reload_config echo $RIPDCONF: cat $RIPDCONF echo killall -SIGHUP ripd killall -SIGHUP ripd } start_quagga() { echo start_quagga echo $RIPDCONF: cat $RIPDCONF echo /usr/sbin/zebra -d /usr/sbin/zebra -d echo /usr/sbin/ripd -d -f $RIPDCONF /usr/sbin/ripd -d -f $RIPDCONF } stop_quagga() { echo stop_quagga echo $RIPDCONF: cat $RIPDCONF echo killall -SIGTERM ripd killall -SIGTERM ripd echo killall -SIGTERM zebra killall -SIGTERM zebra } start_rip_ip() { echo start_rip_ip check_params if [ -d "$VLDIR/" ] || mkdir -p "$VLDIR/" then : Directory $VLDIR now exists else ocf_log err "Could not create \"$VLDIR/\"." exit $OCF_ERR_GENERIC fi if [ x"$OCF_RESKEY_nic" = x ] then echo OCF_RESKEY_nic is null, set to eth0 OCF_RESKEY_nic="eth0" fi if $IP2UTIL addr | $GREP $OCF_RESKEY_ip >/dev/null then ocf_log err "Invalid OCF_RESKEY_ip [$OCF_RESKEY_ip]" exit $OCF_ERR_ARGS fi $IP2UTIL addr add $OCF_RESKEY_ip/32 dev lo if [ -f "$RIPDCONF" ] then # there is a config file, add new data(IP,nic,metric) # to the existing config file. add_ip $OCF_RESKEY_ip add_nic $OCF_RESKEY_nic set_metric 1 reload_config echo sleep 3 sleep 3 set_metric 3 reload_config else new_config_file $OCF_RESKEY_ip $OCF_RESKEY_nic 1 start_quagga echo sleep 3 sleep 3 set_metric 3 reload_config fi return $OCF_SUCCESS } stop_rip_ip() { echo stop_rip_ip check_params status_rip_ip if [ $? = $OCF_NOT_RUNNING ] then ocf_log err "Invalid OCF_RESKEY_ip [$OCF_RESKEY_ip]" exit $OCF_ERR_ARGS fi $IP2UTIL addr del $OCF_RESKEY_ip dev lo echo sleep 2 sleep 2 del_ip $OCF_RESKEY_ip return $OCF_SUCCESS } status_rip_ip() { check_params if $IP2UTIL addr | $GREP $OCF_RESKEY_ip >/dev/null then if $GREP $OCF_RESKEY_ip $RIPDCONF >/dev/null then if pidof ripd >/dev/null then return $OCF_SUCCESS fi fi fi return $OCF_NOT_RUNNING } if [ $# -ne 1 ] then usage exit $OCF_ERR_ARGS fi case $1 in start) start_rip_ip;; stop) stop_rip_ip;; status) status_rip_ip;; monitor) status_rip_ip;; validate-all) check_binary $IP2UTIL exit $OCF_SUCCESS;; meta-data) meta_data;; usage) usage; exit $OCF_SUCCESS;; *) usage exit $OCF_ERR_ARGS ;; esac diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain index 081310596..c8b969ef5 100644 --- a/heartbeat/VirtualDomain +++ b/heartbeat/VirtualDomain @@ -1,319 +1,340 @@ #!/bin/sh # # Support: linux-ha@lists.linux-ha.org # License: GNU General Public License (GPL) # # Resource Agent for domains managed by the libvirt API. # Requires a running libvirt daemon (libvirtd). # # usage: $0 {start|stop|status|monitor|migrate_to|migrate_from|meta-data|validate-all} # ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs LC_ALL="C" LANG="C" # Defaults OCF_RESKEY_force_stop_default=0 OCF_RESKEY_hypervisor_default="$(virsh --quiet uri)" : ${OCF_RESKEY_force_stop=${OCF_RESKEY_force_stop_default}} : ${OCF_RESKEY_hypervisor=${OCF_RESKEY_hypervisor_default}} ####################################################################### usage() { echo "usage: $0 {start|stop|status|monitor|migrate_to|migrate_from|meta-data|validate-all}" } meta_data() { cat < 1.0 Resource agent for a virtual domain (a.k.a. domU, virtual machine, virtual environment etc., depending on context) managed by libvirtd. Manages virtual domains Absolute path to the libvirt configuration file, for this virtual domain. Virtual domain configuration file Hypervisor URI to connect to. See the libvirt documentation for details on supported URI formats. The default is system dependent. Hypervisor URI Forcefully shut down ("destroy") the domain on stop. Enable this only if your virtual domain (or your virtualization backend) does not support graceful shutdown. Force shutdown on stop Transport used to connect to the remote hypervisor while migrating. Please refer to the libvirt documentation for details on transports available. If this parameter is omitted, the resource will use libvirt's default transport to connect to the remote hypervisor. Remote hypervisor transport To additionally monitor services within the virtual domain, add this parameter with a list of scripts to monitor. Note: when monitor scripts are used, the start and migrate_from operations will complete only when all monitor scripts have completed successfully. Be sure to set the timeout of these operations to accommodate this delay. space-separated list of monitor scripts EOF } # Set options to be passed to virsh: VIRSH_OPTIONS="--connect=${OCF_RESKEY_hypervisor} --quiet" VirtualDomain_Define() { # Note: passing in the domain name from outside the script is # intended for testing and debugging purposes only. Don't do this # in production, instead let the script figure out the domain name # from the config file. You have been warned. if [ -z "$DOMAIN_NAME" ]; then DOMAIN_NAME="$(virsh ${VIRSH_OPTIONS} define ${OCF_RESKEY_config} | sed -e 's/Domain \(.*\) defined from .*$/\1/')" \ || return $OCF_ERR_GENERIC else ocf_log warn "Domain name ${DOMAIN_NAME} already defined, overriding configuration file ${OCF_RESKEY_config}. You should do this for testing only." fi } VirtualDomain_Status() { rc=$OCF_ERR_GENERIC - status="`virsh $VIRSH_OPTIONS domstate $DOMAIN_NAME`" - case $status in - "shut off"|"no state") - # shut off: domain is defined, but not started - # no state: domain is migrating (migration target only) - rc=$OCF_NOT_RUNNING - ;; - running|paused|blocked|idle) - rc=$OCF_SUCCESS - ;; - esac - ocf_log debug "Virtual domain $DOMAIN_NAME is currently $status." + status="no state" + while [ "$status" = "no state" ]; do + status="`virsh $VIRSH_OPTIONS domstate $DOMAIN_NAME`" + case "$status" in + "shut off") + # shut off: domain is defined, but not started + ocf_log debug "Virtual domain $DOMAIN_NAME is currently $status." + rc=$OCF_NOT_RUNNING + ;; + running|paused|idle|blocked) + # running: domain is currently actively consuming cycles + # paused: domain is paused (suspended) + # idle: domain is running but idle + # blocked: synonym for idle used by legacy Xen versions + ocf_log debug "Virtual domain $DOMAIN_NAME is currently $status." + rc=$OCF_SUCCESS + ;; + "no state") + # "no state" may occur when the domain is currently + # being migrated (on the migration target only), or + # whenever virsh can't reliably obtain the domain + # state. + ocf_log info "Virtual domain $DOMAIN_NAME currently has no state, retrying." + ;; + *) + # any other output is unexpected. + ocf_log error "Virtual domain $DOMAIN_NAME has unknown status \"$status\"!" + ;; + esac + sleep 1 + done return $rc } VirtualDomain_Start() { if VirtualDomain_Status ${DOMAIN_NAME}; then ocf_log info "Virtual domain $DOMAIN_NAME already running." return $OCF_SUCCESS fi virsh $VIRSH_OPTIONS start ${DOMAIN_NAME} rc=$? if [ $rc -ne 0 ]; then ocf_log error "Failed to start virtual domain ${DOMAIN_NAME}." return $OCF_ERR_GENERIC fi while sleep 1; do VirtualDomain_Monitor && return $OCF_SUCCESS done } VirtualDomain_Stop() { if VirtualDomain_Status ${DOMAIN_NAME}; then case $OCF_RESKEY_force_stop in [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) op="destroy" ;; *) op="shutdown" ;; esac virsh $VIRSH_OPTIONS $op ${DOMAIN_NAME} while sleep 1; do VirtualDomain_Status if [ $? -eq $OCF_NOT_RUNNING ]; then return $OCF_SUCCESS fi done else ocf_log info "Domain $DOMAIN_NAME already stopped." return $OCF_SUCCESS fi } VirtualDomain_Migrate_To() { local target_node local remoteuri local transport_suffix target_node="$OCF_RESKEY_CRM_meta_migrate_target" if VirtualDomain_Status ${DOMAIN_NAME}; then # Find out the remote hypervisor to connect to. That is, turn # something like "qemu://foo:9999/system" into # "qemu+tcp://bar:9999/system" if [ -n "${OCF_RESKEY_migration_transport}" ]; then transport_suffix="+${OCF_RESKEY_migration_transport}" fi # Scared of that sed expression? So am I. :-) remoteuri=$(echo ${OCF_RESKEY_hypervisor} | sed -e "s,\(.*\)://[^/:]*\(:\?[0-9]*\)/\(.*\),\1${transport_suffix}://${target_node}\2/\3,") # OK, we know where to connect to. Now do the actual migration. - ocf_log info "$DOMAIN_NAME: Starting live migration to ${remoteuri}" + ocf_log info "$DOMAIN_NAME: Starting live migration to ${target_node} (using remote hypervisor URI ${remoteuri})." virsh ${VIRSH_OPTIONS} migrate --live $DOMAIN_NAME ${remoteuri} rc=$? if [ $rc -ne 0 ]; then ocf_log err "$DOMAIN_NAME: live migration to ${remoteuri} failed: $rc" return $OCF_ERR_GENERIC else - ocf_log info "$DOMAIN_NAME: live migration to ${remoteuri} succeeded." + ocf_log info "$DOMAIN_NAME: live migration to ${target_node} succeeded." return $OCF_SUCCESS fi else ocf_log err "$DOMAIN_NAME: migrate_to: Not active locally!" return $OCF_ERR_GENERIC fi } VirtualDomain_Migrate_From() { while sleep 1; do - VirtualDomain_Monitor && return $OCF_SUCCESS + VirtualDomain_Monitor && break done + ocf_log info "$DOMAIN_NAME: live migration from ${OCF_RESKEY_CRM_meta_migrate_source} succeeded." + return $OCF_SUCCESS } VirtualDomain_Monitor() { # First, check the domain status. If that returns anything other # than $OCF_SUCCESS, something is definitely wrong. VirtualDomain_Status ${DOMAIN_NAME} rc=$? if [ ${rc} -eq ${OCF_SUCCESS} ]; then # OK, the generic status check turned out fine. Now, if we # have monitor scripts defined, run them one after another. for script in ${OCF_RESKEY_monitor_scripts}; do script_output="$($script 2>&1)" script_rc=$? if [ ${script_rc} -ne ${OCF_SUCCESS} ]; then # A monitor script returned a non-success exit # code. Stop iterating over the list of scripts, log a # warning message, and propagate $OCF_ERR_GENERIC. ocf_log warn "Monitor command \"${script}\" for domain ${DOMAIN_NAME} returned ${script_rc} with output: ${script_output}" rc=$OCF_ERR_GENERIC break else ocf_log debug "Monitor command \"${script}\" for domain ${DOMAIN_NAME} completed successfully with output: ${script_output}" fi done fi return ${rc} } VirtualDomain_Validate_All() { # Required binaries: for binary in virsh sed; do check_binary $binary done if [ -z $OCF_RESKEY_config ]; then ocf_log error "Missing configuration parameter \"config\"." return $OCF_ERR_CONFIGURED fi # check if we can read the config file (otherwise we're unable to # deduce $DOMAIN_NAME from it, see below) if [ ! -r $OCF_RESKEY_config ]; then ocf_log error "Configuration file $OCF_RESKEY_config does not exist or is not readable." return $OCF_ERR_INSTALLED 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 # Everything except usage and meta-data must pass the validate test VirtualDomain_Validate_All || exit $? # Define the domain on startup, and re-define (harmlessly) # on every invocation. This also sets DOMAIN_NAME. If this fails, # bail out. VirtualDomain_Define || exit $? case $1 in start) VirtualDomain_Start ;; stop) VirtualDomain_Stop ;; migrate_to) VirtualDomain_Migrate_To ;; migrate_from) VirtualDomain_Migrate_From ;; status) VirtualDomain_Status ;; monitor) VirtualDomain_Monitor ;; validate-all) ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $? diff --git a/heartbeat/WAS b/heartbeat/WAS index fe2fc1da8..345dd074c 100644 --- a/heartbeat/WAS +++ b/heartbeat/WAS @@ -1,571 +1,571 @@ #!/bin/sh # # # WAS # # Description: Manages a Websphere Application Server as an HA resource # # # Author: Alan Robertson # Support: linux-ha@lists.linux-ha.org # License: GNU General Public License (GPL) # Copyright: (C) 2002 - 2005 International Business Machines, Inc. # # # An example usage in /etc/ha.d/haresources: # node1 10.0.0.170 WAS::/opt/WebSphere/ApplicationServer/config/server-cfg.xml # # See usage() function below for more details... # # OCF parameters are as below: # OCF_RESKEY_config # (WAS-configuration file, used for the single server edition of WAS) # OCF_RESKEY_port # (WAS--port-number, used for the advanced edition of WAS) ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### WASDIR=/opt/WebSphere/AppServer if [ ! -d $WASDIR ] then WASDIR=/usr/WebSphere/AppServer fi STARTTIME=300 # 5 minutes DEFAULT_WASPORTS="9080" # # WASBIN=$WASDIR/bin DEFAULT=$WASDIR/config/server-cfg.xml # # Print usage message # usage() { methods=`WAS_methods | grep -v methods` methods=`echo $methods | tr ' ' '|'` cat <<-! usage: $0 ($methods) For the single server edition of WAS, you have to set the following enviroment virable: OCF_RESKEY_config (WAS-configuration file) For the advanced edition of WAS, you have to set the following enviroment virable: OCF_RESKEY_port (WAS--port-number) $0 manages a Websphere Application Server (WAS) as an HA resource The 'start' operation starts WAS. The 'stop' operation stops WAS. The 'status' operation reports whether WAS is running The 'monitor' operation reports whether the WAS seems to be working (httpd also needs to be working for this case) The 'validate-all' operation reports whether the OCF instance parameter (OCF_RESKEY_config or OCF_RESKEY_port) is valid The 'methods' operation reports on the methods $0 supports This is known to work with the Single Server edition of Websphere, and is believed to work with the Advanced edition too. Since the Advanced Edition has no configuration file (it's in a the database) you need to give a port number instead of a configuration file for this config parameter. The default configuration file for the single server edition is: $DEFAULT The default snoop-port for the advanced edition is: $DEFAULT_WASPORTS The start and stop operations must be run as root. The status operation will report a pid of "-" for the WAS root process using unless it is run as root. If you don't have xmllint on your system, parsing of WAS configuration files is very primitive. In this case, the port specification we need from the XML config file has to be on the same line as the first part of the tag. We run servlet/snoop on the first transport port listed in the config file for the "monitor" operation. ! } meta_data() { cat < 1.0 Resource script for WAS. It manages a Websphere Application Server (WAS) as an HA resource. WAS resource agent The WAS-configuration file. configration file The WAS-(snoop)-port-number. port - - + + END } # # Reformat the XML document in a sort of canonical form # if we can. If we don't have xmllint, we just cat it out # and hope for the best ;-) # xmlcat() { if [ "X$XMLcat" = X ] then XMLcat=`which xmllint 2>/dev/null` if [ "X${XMLcat}" = X -o ! -x "${XMLcat}" ] then XMLcat=cat else XMLcat="$XMLcat --recover --format" fi fi for j in "$@" do ${XMLcat} "$j" done } # #This is a bit skanky, but it works anyway... # # # # # # It's not really skanky if we can find xmllint on the system, because it # reformats tags so they are all on one line, which is all we we need... # # # Get the numbers of the ports WAS should be listening on... # # If we don't have xmllint around, then the applicationserver and the # port= specification have to be on the same line in the XML config file. # GetWASPorts() { case $1 in [0-9]*) echo "$1" | tr ',' '\012';; *) xmlcat $1 | grep -i 'transports.*applicationserver:HTTPTransport' | grep port= | sed -e 's%.*port= *"* *%%' \ -e 's%[^0-9][^0-9]*.*$%%' # Delete up to port=, throw away optional quote and optional # white space. # Throw away everything after the first non-digit. # This should leave us the port number all by itself... esac } # # We assume that the first port listed in the # is the one we should run servlet/snoop on. # GetWASSnoopPort() { GetWASPorts "$@" | head -n1 } # # Return information on the processname/id for the WAS ports # # pid/java is the expected output. Several lines, one per port... # # WASPortInfo() { pat="" once=yes PortCount=0 for j in $* do case $pat in "") pat="$j";; *) pat="$pat|$j";; esac PortCount=`expr $PortCount + 1` done netstat -ltnp 2>/dev/null| egrep -i "($pat) .*LISTEN" | sed 's%.*LISTEN *%%' } # # Return the number of WAS ports which are open # CheckWASPortsInUse() { count=`WASPortInfo "$@" | wc -l` echo $count } # # Return the pid(s) of the processes that have WAS ports open # WASPIDs() { WASPortInfo "$@" | sort -u | cut -f1 -d/ } # # The version of ps that returns all processes and their (long) args # It's only used by WAS_procs, which isn't used for anything ;-) # ps_long() { ps axww } # # The total set of WAS processes (single server only) # WAS_procs() { ps_long | grep -i "config=$1" | grep -i java | cut -d' ' -f1 } # # methods: What methods/operations do we support? # WAS_methods() { cat <<-! start stop status methods validate-all meta-data usage ! if have_binary $WGET then echo monitor fi } # # Return WAS status (silently) # WAS_status() { WASPorts=`GetWASPorts $1` PortsInUse=`CheckWASPortsInUse $WASPorts` case $PortsInUse in 0) false;; *) true;; esac } # # Report on WAS status to stdout... # WAS_report_status() { WASPorts=`GetWASPorts $1` PortCount=`echo $WASPorts | wc -w` PortCount=`echo $PortCount` PortsInUse=`CheckWASPortsInUse $WASPorts` case $PortsInUse in 0) ocf_log debug "WAS: server $1 is stopped."; return $OCF_NOT_RUNNING;; *) pids=`WASPIDs $WASPorts` if [ $PortsInUse -ge $PortCount ] then ocf_log debug "WAS: server $1 is running (pid" $pids "et al)." else ocf_log debug "WAS: server $1 is running (pid $pids et al) but not listening on all ports." fi return $OCF_SUCCESS;; esac } # # Monitor WAS - does it really seem to be working? # # For this we invoke the snoop applet via wget. # # This is actually faster than WAS_status above... # WAS_monitor() { trap '[ -z "$tmpfile" ] || rmtempfile "$tmpfile"' 0 tmpfile=`maketempfile` || return 1 SnoopPort=`GetWASSnoopPort $1` output=`$WGET -nv -O$tmpfile http://localhost:$SnoopPort/servlet/snoop 2>&1` rc=$? if [ $rc -eq 0 ] then if grep -i 'user-agent.*Wget' $tmpfile >/dev/null then : OK else ocf_log "err" "WAS: $1: no user-agent from snoop application" rc=$OCF_ERR_GENERIC fi else ocf_log "err" "WAS: $1: wget failure: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # Start WAS instance # WAS_start() { # Launch Arguments: # # -configFile # -nodeName # -serverName # -oltEnabled # -oltHost # -oltPort # -debugEnabled # -jdwpPort # -debugSource # -serverTrace # -serverTraceFile # -script [] # -platform # -noExecute # -help if [ -x $WASBIN/startServer.sh ] then cmd="$WASBIN/startServer.sh -configFile $1" else cmd="$WASBIN/startupServer.sh" fi if ocf_run $cmd then if WAS_wait_4_start $STARTTIME "$@" then #true return $OCF_SUCCESS else ocf_log "err" "WAS server $1 did not start correctly" return $OCF_ERR_GENERIC fi else #false return $OCF_ERR_GENERIC fi } # # Wait for WAS to actually start up. # # It seems to take between 30 and 60 seconds for it to # start up on a trivial WAS instance. # WAS_wait_4_start() { max=$1 retries=0 shift while [ $retries -lt $max ] do if WAS_status "$@" then return $OCF_SUCCESS else sleep 1 fi retries=`expr $retries + 1` done WAS_status "$@" } # # Shut down WAS # WAS_stop() { # They don't return good return codes... # And, they seem to allow anyone to stop WAS (!) if [ -x $WASBIN/stopServer.sh ] then ocf_run $WASBIN/stopServer.sh -configFile $1 else WASPorts=`GetWASPorts $1` kill `WASPIDs $WASPorts` fi if WAS_status $1 then ocf_log "err" "WAS: $1 did not stop correctly" #false return $OCF_ERR_GENERIC else #true return $OCF_SUCCESS fi } # # Check if the port is valid # CheckPort() { ocf_is_decimal "$1" && [ $1 -gt 0 ] } WAS_validate_all() { if [ -x $WASBIN/startServer.sh ]; then # $arg should be config file if [ ! -f "$arg" ]; then ocf_log err "Configuration file [$arg] does not exist" exit $OCF_ERR_ARGS fi # $arg should specify a valid port number at the very least local WASPorts=`GetWASPorts $arg` if [ -z "$WASPorts" ]; then ocf_log err "No port number specified in configuration file [$arg]" exit $OCF_ERR_CONFIGURED fi local port local have_valid_port=false for port in $WASPorts; do if CheckPort $port; then have_valid_port=true break fi done if [ "false" = "$have_valid_port" ]; then ocf_log err "No valid port number specified in configuration file [$arg]" exit $OCF_ERR_CONFIGURED fi elif [ -x $WASBIN/startupServer.sh ]; then # $arg should be port number if CheckPort "$arg"; then ocf_log err "Port number is required but [$arg] is not valid port number" exit $OCF_ERR_ARGS fi else # Do not know hot to validate_all ocf_log warn "Do not know how to validate-all, assuming validation OK" return $OCF_SUCCESS fi } # # 'main' starts here... # if ( [ $# -ne 1 ] ) then usage exit $OCF_ERR_ARGS fi # # Supply default configuration parameter(s) # if ( [ -z $OCF_RESKEY_config ] && [ -z $OCF_RESKEY_port ] ) then if [ -f $DEFAULT ] then arg=$DEFAULT else arg=$DEFAULT_WASPORTS fi elif [ ! -z $OCF_RESKEY_config ] then arg=$OCF_RESKEY_config else arg=$OCF_RESKEY_port fi if [ ! -f $arg ] then case $arg in [0-9]*) ;; # ignore port numbers... *) ocf_log "err" "WAS configuration file $arg does not exist!" usage exit $OCF_ERR_ARGS;; esac fi # What kind of method was invoked? case "$1" in meta-data) meta_data exit $OCF_SUCCESS;; start) WAS_start $arg exit $?;; stop) WAS_stop $arg exit $?;; status) WAS_report_status $arg exit $?;; monitor) WAS_monitor $arg exit $?;; validate-all) WAS_validate_all $arg exit $?;; methods) WAS_methods exit $?;; usage) usage exit $OCF_SUCCESS;; *) usage exit $OCF_ERR_UNIMPLEMENTED;; esac diff --git a/heartbeat/WAS6 b/heartbeat/WAS6 index 771e5d553..858efce9c 100644 --- a/heartbeat/WAS6 +++ b/heartbeat/WAS6 @@ -1,545 +1,545 @@ #!/bin/sh # WAS6 # # Description: Manages a Websphere Application Server as an HA resource # # # Author: Ru Xiang Min # Support: linux-ha@lists.linux-ha.org # License: GNU General Public License (GPL) # Copyright: (C) 2006 International Business Machines China, Ltd., Inc. # # # An example usage in /etc/ha.d/haresources: # node1 10.0.0.170 WAS::/opt/IBM/WebSphere/AppServer/profiles/default/config/cells/Node01Cell/nodes/Node01/serverindex.xml # # See usage() function below for more details... # # OCF parameters are as below: # OCF_RESKEY_profile # (WAS profile name, used for the single server edition of WAS6) ####################################################################### # Initialization: . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ####################################################################### WAS_DIR=/opt/IBM/WebSphere/AppServer if [ ! -d $WAS_DIR ] then WAS_DIR=/usr/IBM/WebSphere/AppServer fi STARTTIME=300 # 5 minutes DEFAULT_WASPORTS="9080" # # WAS_BIN=$WAS_DIR/bin DEFAULT=default # # Print usage message # usage() { methods=`WAS_methods | grep -v methods` methods=`echo $methods | tr ' ' '|'` cat <<-! usage: $0 ($methods) For the single server edition of WAS6, you have to set the following enviroment virable: OCF_RESKEY_profile (WAS profile name) $0 manages a Websphere Application Server 6(WAS6) as an HA resource The 'start' operation starts WAS6. The 'stop' operation stops WAS6. The 'status' operation reports whether WAS6 is running The 'monitor' operation reports whether the WAS6 seems to be working (httpd also needs to be working for this case) The 'validate-all' operation reports whether the OCF instance parameter (OCF_RESKEY_profileName ) is valid The 'methods' operation reports on the methods $0 supports This is known to work with the Single Server edition of Websphere. The default profile name for the single server edition is: $DEFAULT The start and stop operations must be run as root. The status operation will report a pid of "-" for the WAS root process using unless it is run as root. If you don't have xmllint on your system, parsing of WAS configuration files is very primitive. We run servlet/snoop on the seventh transport port listed in the config file for the "monitor" operation. ! } meta_data() { cat < 1.0 Resource script for WAS6. It manages a Websphere Application Server (WAS6) as an HA resource. WAS6 resource agent The WAS profile name. profile name - - + + END } # # Reformat the XML document in a sort of canonical form # if we can. If we don't have xmllint, we just cat it out # and hope for the best ;-) # xmlcat() { if [ "X$XMLcat" = X ] then XMLcat=`which xmllint 2>/dev/null` if [ "X${XMLcat}" = X -o ! -x "${XMLcat}" ] then XMLcat=cat else XMLcat="$XMLcat --recover --format" fi fi for j in "$@" do ${XMLcat} "$j" done } # #This is a bit skanky, but it works anyway... # # It's not really skanky if we can find xmllint on the system, because it # reformats tags so they are all on one line, which is all we we need... # # # Get the numbers of the ports WAS should be listening on... # # If we don't have xmllint around, then the applicationserver and the # port= specification have to be on the same line in the XML config file. # GetWASPorts() { case $1 in [0-9]*) echo "$1" | tr ',' '\012';; *) xmlcat ${WAS_DIR}/profiles/${WAS_PROFILE_NAME}/config/cells/${WAS_CELL}/nodes/${WAS_NODE}/serverindex.xml | grep port= | sed -e 's%.*port= *"* *%%' \ -e 's%[^0-9][^0-9]*.*$%%' # Delete up to port=, throw away optional quote and optional # white space. # Throw away everything after the first non-digit. # This should leave us the port number all by itself... esac } # # We assume that the seventh port listed in the serverindex.xml # is the one we should run servlet/snoop on. # GetWASSnoopPort() { GetWASPorts "$@" | sed -n '7p' } # # Return information on the processname/id for the WAS ports # # pid/java is the expected output. Several lines, one per port... # # WASPortInfo() { pat="" once=yes PortCount=0 for j in $* do case $pat in "") pat="$j";; *) pat="$pat|$j";; esac PortCount=`expr $PortCount + 1` done netstat -ltnp 2>/dev/null| egrep -i "($pat) .*LISTEN" | sed 's%.*LISTEN *%%' } # # Return the number of WAS ports which are open # CheckWASPortsInUse() { count=`WASPortInfo "$@" | wc -l` echo $count } # # Return the pid(s) of the processes that have WAS ports open # WASPIDs() { WASPortInfo "$@" | sort -u | cut -f1 -d/ } # # The version of ps that returns all processes and their (long) args # It's only used by WAS_procs, which isn't used for anything ;-) # ps_long() { ps axww } # # The total set of WAS processes (single server only) # WAS_procs() { ps_long | grep -i "config=$1" | grep -i java | cut -d' ' -f1 } # # methods: What methods/operations do we support? # WAS_methods() { cat <<-! start stop status methods validate-all meta-data usage ! if have_binary $WGET then echo " monitor" fi } # # Return WAS status (silently) # WAS_status() { WASPorts=`GetWASPorts $1` PortsInUse=`CheckWASPortsInUse $WASPorts` case $PortsInUse in 0) false;; *) true;; esac } # # Report on WAS status to stdout... # WAS_report_status() { WASPorts=`GetWASPorts $1` PortCount=`echo $WASPorts | wc -w` PortCount=`echo $PortCount` PortsInUse=`CheckWASPortsInUse $WASPorts` case $PortsInUse in 0) ocf_log debug "WAS: server $1 is stopped."; return $OCF_NOT_RUNNING;; *) pids=`WASPIDs $WASPorts` if [ $PortsInUse -ge $PortCount ] then ocf_log debug "WAS: server $1 is running (pid" $pids "et al)." else ocf_log debug "WAS: server $1 is running (pid $pids et al) but not listening on all ports." fi return $OCF_SUCCESS;; esac } # # Monitor WAS - does it really seem to be working? # # For this we invoke the snoop applet via wget. # # This is actually faster than WAS_status above... # WAS_monitor() { trap '[ -z "$tmpfile" || rmtempfile "$tmpfile"' 0 tmpfile=`maketempfile` || exit 1 SnoopPort=`GetWASSnoopPort $1` output=`$WGET -nv -O$tmpfile http://localhost:$SnoopPort/snoop 2>&1` rc=$? if [ $rc -eq 0 ] then if grep -i 'user-agent.*Wget' $tmpfile >/dev/null then : OK else ocf_log "err" "WAS: $1: no user-agent from snoop application" rc=$OCF_ERR_GENERIC fi else ocf_log "err" "WAS: $1: wget failure: $output" rc=$OCF_ERR_GENERIC fi return $rc } # # Start WAS instance # WAS_start() { # Launch Arguments: # -nowait # -quiet # -logfile # -replacelog # -trace # -script [