#!/bin/sh
#
#             OCF Resource Agent for managing CTDB
#
# Copyright (c) 2009-2010 Novell Inc., Tim Serong
#                    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:
# - Verify timeouts are sane
# - Monitor differentiate between error and not running?
# - Do we need to verify globally unique setting?
# - Should set CTDB_NODES to ${HA_RSCTMP}/ctdb (generated based on
#   current nodes)
# - Be more clever about monitor op:
#   ctdb --socket=/tmp/ctdb.socket status
#	Number of nodes:2
#	pnn:0 192.168.101.14   DISABLED (THIS NODE)
#	pnn:1 192.168.101.15   DISABLED
#	Generation:665993634
#	Size:2
#	hash:0 lmaster:0
#	hash:1 lmaster:1
#	Recovery mode:NORMAL (0)
#	Recovery master:1
#   ^ if this says pnn:0...DISABLED|UNHEALTHY, there is a problem,
#     e.g. ctdb socket not specified in smb.conf.
# - Lots of "No public addresses file found. Nothing to do for
#   10.interfaces" junk in ctdb log file.  Can we fix/suppress this?
# - Look at enabling set_ctdb_variables() if necessary.
# - Probably possible for sysconfig file to not be restored if
#   CTDB dies unexpectedly.
#
#######################################################################
# Initialization:

: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
. ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs

#######################################################################
# Default parameter values:

: ${OCF_RESKEY_ctdb_config_dir:=/etc/ctdb}
: ${OCF_RESKEY_ctdb_binary:=/usr/bin/ctdb}
: ${OCF_RESKEY_ctdbd_binary:=/usr/sbin/ctdbd}
: ${OCF_RESKEY_ctdb_socket:=/var/lib/ctdb/ctdb.socket}
: ${OCF_RESKEY_ctdb_dbdir:=/var/lib/ctdb}
: ${OCF_RESKEY_ctdb_logfile:=/var/log/ctdb/log.ctdb}
: ${OCF_RESKEY_ctdb_debuglevel:=2}
: ${OCF_RESKEY_smb_conf:=/etc/samba/smb.conf}

#######################################################################

meta_data() {
	cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="CTDB" version="1.0">
<version>1.0</version>

<longdesc lang="en">
This resource agent manages CTDB, allowing one to use Clustered Samba
in a Linux-HA/Pacemaker cluster.  You need a shared filesystem
(e.g. OCFS2) on which CTDB lock and Samba state will be stored.
Configure shares in smb.conf on all nodes, and create /etc/ctdb/nodes
containing a list of private IP addresses of each node in the cluster.
Configure this RA as a clone, and it will take care of the rest.
For more information see http://linux-ha.org/wiki/CTDB_(resource_agent)
</longdesc>
<shortdesc lang="en">CTDB Resource Agent</shortdesc>

<parameters>

<parameter name="ctdb_recovery_lock" unique="1" required="1">
<longdesc lang="en">
The location of a shared lock file, common across all nodes.
This must be on shared storage, e.g.: /shared-fs/samba/ctdb.lock
</longdesc>
<shortdesc lang="en">CTDB shared lock file</shortdesc>
<content type="string" default="" />
</parameter>

<parameter name="smb_private_dir" unique="1" required="1">
<longdesc lang="en">
The directory for smbd to use for storing such files as
smbpasswd and secrets.tdb.  This must be on shared storage,
e.g.: /shared-fs/samba/private
</longdesc>
<shortdesc lang="en">Samba private dir</shortdesc>
<content type="string" default="" />
</parameter>

<parameter name="ctdb_config_dir" unique="0" required="0">
<longdesc lang="en">
The directory containing various CTDB configuration files.
The "nodes" and "notify.sh" scripts are expected to be
in this directory, as is the "events.d" subdirectory.
</longdesc>
<shortdesc lang="en">CTDB config file directory</shortdesc>
<content type="string" default="/etc/ctdb" />
</parameter>

<parameter name="ctdb_binary" unique="0" required="0">
<longdesc lang="en">
Full path to the CTDB binary.
</longdesc>
<shortdesc lang="en">CTDB binary path</shortdesc>
<content type="string" default="/usr/bin/ctdb" />
</parameter>

<parameter name="ctdbd_binary" unique="0" required="0">
<longdesc lang="en">
Full path to the CTDB cluster daemon binary.
</longdesc>
<shortdesc lang="en">CTDB Daemon binary path</shortdesc>
<content type="string" default="/usr/sbin/ctdbd" />
</parameter>

<parameter name="ctdb_socket" unique="0" required="0">
<longdesc lang="en">
Full path to the domain socket that ctdbd will create, used for
local clients to attach and communicate with the ctdb daemon.
</longdesc>
<shortdesc lang="en">CTDB socket location</shortdesc>
<content type="string" default="/var/lib/ctdb/ctdb.socket" />
</parameter>

<parameter name="ctdb_dbdir" unique="0" required="0">
<longdesc lang="en">
The directory to put the local CTDB database files in.
Persistent database files will be put in ctdb_dbdir/persistent.
</longdesc>
<shortdesc lang="en">CTDB database directory</shortdesc>
<content type="string" default="/var/lib/ctdb" />
</parameter>

<parameter name="ctdb_logfile" unique="0" required="0">
<longdesc lang="en">
Full path to log file. To log to syslog instead, use the
value "syslog".
</longdesc>
<shortdesc lang="en">CTDB log file location</shortdesc>
<content type="string" default="/var/log/ctdb/log.ctdb" />
</parameter>

<parameter name="ctdb_debuglevel" unique="0" required="0">
<longdesc lang="en">
What debug level to run at (0-10). Higher means more verbose.
</longdesc>
<shortdesc lang="en">CTDB debug level</shortdesc>
<content type="integer" default="2" />
</parameter>

<parameter name="smb_conf" unique="0" required="0">
<longdesc lang="en">
Path to default samba config file.
</longdesc>
<shortdesc lang="en">Path to smb.conf</shortdesc>
<content type="string" default="/etc/samba/smb.conf" />
</parameter>

</parameters>

<actions>
<action name="start"        timeout="90" />
<action name="stop"         timeout="100" />
<action name="monitor"      timeout="20" interval="10" depth="0" />
<action name="meta-data"    timeout="5" />
<action name="validate-all"   timeout="30" />
</actions>
</resource-agent>
END
}

#######################################################################

# Figure out path to /etc/sysconfig/ctdb (same logic as
# loadconfig() from /etc/ctdb/functions
if [ -f /etc/sysconfig/ctdb ]; then
	CTDB_SYSCONFIG=/etc/sysconfig/ctdb
elif [ -f /etc/default/ctdb ]; then
	CTDB_SYSCONFIG=/etc/default/ctdb
elif [ -f $OCF_RESKEY_ctdb_config_dir/ctdb ]; then
	CTDB_SYSCONFIG=$OCF_RESKEY_ctdb_config_dir/ctdb
fi

# Backup paths
CTDB_SYSCONFIG_BACKUP=${HA_RSCTMP}/ctdb-${OCF_RESOURCE_INSTANCE}

# This function has no effect (currently no way to set CTDB_SET_*)
# but remains here in case we need it in future.
set_ctdb_variables() {
	rv=$OCF_SUCCESS
	set | grep ^CTDB_SET_ | cut -d_ -f3- |
	while read v; do
		varname=`echo $v | cut -d= -f1`
		value=`echo $v | cut -d= -f2`
		$OCF_RESKEY_ctdb_binary --socket=$OCF_RESKEY_ctdb_socket setvar $varname $value || rv=$OCF_ERR_GENERIC
	done || rv=$OCF_ERR_GENERIC
	return $rv
}


# Add necessary settings to /etc/samba/smb.conf.  In a perfect world,
# we'd be able to generate a new, temporary, smb.conf file somewhere,
# something like:
#     include = /etc/samba/smb.conf
#     [global]
#       clustering = yes
#       # ...etc...
# Unfortunately, we can't do this, because there's no way to tell the
# smb init script where the temporary config is, so we just edit
# the default config file.
init_smb_conf() {
	grep -Eiv \
		'^[[:space:]]*(# CTDB-RA:|passdb backend|clustering|idmap backend|private dir|ctdbd socket)' \
		$OCF_RESKEY_smb_conf | sed "/^[[:space:]]*\[global\]/ a\\
\t# CTDB-RA: Begin auto-generated section (do not change below)\n\
\tpassdb backend = tdbsam\n\
\tclustering = yes\n\
\tidmap backend = tdb2\n\
\tprivate dir = $OCF_RESKEY_smb_ectory.
</leturn 3;;
  esac
}

# usage: rmtempdir TMPDIR
rmtempdir()
{
	[ $# = 1 ] || return 1
	if [ -e "$1" ]; then
		rmdir "$1" || return 1
	fi
	return 0
}

# usage: maketempfile [-d]
maketempfile()
{
	if [ $# = 1 -a "$1" = "-d" ]; then
		mktemp -d
		return -0
	elif [ $# != 0 ]; then
		return 1
	fi

	mktemp
	return 0
}

# usage: rmtempfile TMPFILE
rmtempfile ()
{
	[ $# = 1 ] || return 1
	if [ -e "$1" ]; then
		rm "$1" || return 1
	fi
	return 0
}

__ocf_set_defaults "$@"
                                                                                                                                                                                                      ./usr/lib/ocf/resource.d/heartbeat/.ocf-binaries                                                    0000644 0000000 0000000 00000003064 11526221466 020421  0                                                                                                    ustar   root                            root                                                                                                                                                                                                                   # Make sure PATH contains all the usual suspects
PATH="$PATH:/sbin:/bin:/usr/sbin:/usr/bin"

# Include /usr/ucb for finding whoami on Solaris
PATH="$PATH:/usr/ucb"

export PATH

# Binaries and binary options for use in Resource Agents
: ${AWK:=mawk}
: ${EGREP:="/bin/grep -E"}
: ${IFCONFIG_A_OPT:=""}
: ${MAILCMD:=mail}
: ${PING:=/bin/ping}
: ${SH:=/bin/bash}
: ${TEST:=/usr/bin/test}
: ${TESTPROG:=/usr/bin/test}

# Entries that should probably be removed
: ${BASENAME:=basename}
: ${BLOCKDEV:=blockdev}
: ${CAT:=cat}
: ${FSCK:=fsck}
: ${FUSER:=fuser}
: ${GETENT:=getent}
: ${GREP:=grep}
: ${IFCONFIG:=ifconfig}
: ${IPTABLES:=iptables}
: ${IP2UTIL:=ip}
: ${MDADM:=mdadm}
: ${MODPROBE:=modprobe}
: ${MOUNT:=mount}
: ${MSGFMT:=msgfmt}
: ${NETSTAT:=netstat}
: ${PERL:=perl}
: ${PYTHON:=python}
: ${RAIDSTART:=raidstart}
: ${RAIDSTOP:=raidstop}
: ${ROUTE:=route}
: ${UMOUNT:=umount}
: ${REBOOT:=reboot}
: ${POWEROFF_CMD:=poweroff}
: ${WGET:=wget}
: ${WHOAMI:=whoami}
: ${STRINGSCMD:=strings}
: ${SCP:=scp}
: ${SSH:=ssh}
: ${SWIG:=swig}
: ${GZIP_PROG:=gzip}
: ${TAR:=tar}
: ${MD5:=md5}
: ${DRBDADM:=drbdadm}
: ${DRBDSETUP:=drbdsetup}

check_binary () {
    if 
	have_binary "$1"
    then
        :
    else
	if [ "$OCF_NOT_RUNNING" = 7 ]; then
	    # Chances are we have a fully setup OCF environment
	    ocf_log err "Setup problem: Couldn't find utility $1"
	else 
	    echo "Setup problem: Couldn't find utility $1"
	fi
	exit $OCF_ERR_INSTALLED
    fi
}

have_binary () {
    bin=`echo $1 | sed -e 's/ -.*//'`
    if [ -x "`which $bin 2>/dev/null`" ]; then
	return 0
    fi
    return 1
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            ./usr/lib/ocf/resource.d/heartbeat/.ocf-directories                                                 0000644 0000000 0000000 00000001231 11526221466 021133  0                                                                                                    ustar   root                            root                                                                                                                                                                                                                   # Binaries and binary options for use in Resource Agents

prefix=/usr
exec_prefix=/usr
: ${INITDIR:=/etc/init.d}
: ${HA_DIR:=/etc/ha.d}
: ${HA_RCDIR:=$HA_DIR/rc.d}
: ${HA_CONFDIR=$HA_DIR/conf}
: ${HA_CF:=$HA_DIR/ha.cf}
: ${HA_VARLIB:=/var/lib/heartbeat}
: ${HA_RSCTMP:=/var/run/heartbeat/rsctmp}
: ${HA_FIFO:=/var/lib/heartbeat/fifo}
: ${HA_BIN:=/usr/lib/heartbeat}
: ${HA_SBIN_DIR:=/usr/sbin}
: ${HA_DATEFMT:="%Y/%m/%d_%T "}
: ${HA_DEBUGLOG:=/dev/null}
: ${HA_RESOURCEDIR:=$HA_DIR/resource.d}
: ${HA_DOCDIR:=/usr/share/doc/heartbeat}
: ${__SCRIPT_NAME:=`basename $0`}
: ${HA_LOGTAG:=$__SCRIPT_NAME[$$]}
: ${HA_VARRUN:=/var/run/}
: ${HA_VARLOCK:=/var/lock/subsys/}
                                                                                                                                                                                                                                                                                                                                                                       ./usr/lib/ocf/resource.d/heartbeat/.ocf-returncodes                                                 0000644 0000000 0000000 00000003515 11526221466 021163  0                                                                                                    ustar   root                            root                                                                                                                                                                                                                   #
# 	Common varibales for the OCF Resource Agents supplied by
# 	heartbeat.
#
# Copyright (c) 2004 SUSE LINUX AG, Andrew Beekhof
#                    All Rights Reserved.
#
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# 

OCF_SUCCESS=0
OCF_ERR_GENERIC=1
OCF_ERR_ARGS=2
OCF_ERR_UNIMPLEMENTED=3
OCF_ERR_PERM=4
OCF_ERR_INSTALLED=5
OCF_ERR_CONFIGURED=6
OCF_NOT_RUNNING=7

# Non-standard values.
#
# OCF does not include the concept of master/slave resources so we
#   need to extend it so we can discover a resource's complete state.
#
# OCF_RUNNING_MASTER:  
#    The resource is in "master" mode and fully operational
# OCF_FAILED_MASTER:
#    The resource is in "master" mode but in a failed state
# 
# The extra two values should only be used during a probe.
#
# Probes are used to discover resources that were started outside of
#    the CRM and/or left behind if the LRM fails.
# 
# They can be identified in RA scripts by checking for:
#   [ "${__OCF_ACTION}" = "monitor" -a "${OCF_RESKEY_CRM_meta_interval}" = "0" ]
# 
# Failed "slaves" should continue to use: OCF_ERR_GENERIC
# Fully operati