1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00
samba-mirror/ctdb/config/functions
Ronnie Sahlberg 3cbaf935af sugegstion from metze,
use killtcp and kill both directions of the nfs connections.
we used to kill only one direction since the other direction was unkillble
but recent kernels allow us to kill both

(This used to be ctdb commit 8001ae580bcc28d45f6026b529d7ffc247cbba34)
2009-11-06 09:54:03 +11:00

550 lines
15 KiB
Plaintext

# utility functions for ctdb event scripts
#######################################
# pull in a system config file, if any
loadconfig() {
name="$1"
if [ -f /etc/sysconfig/$name ]; then
. /etc/sysconfig/$name
elif [ -f /etc/default/$name ]; then
. /etc/default/$name
elif [ -f $CTDB_BASE/sysconfig/$name ]; then
. $CTDB_BASE/sysconfig/$name
fi
}
##############################################################
# determine on what type of system (init style) we are running
detect_init_style() {
# only do detection if not already set:
test "x$CTDB_INIT_STYLE" != "x" && return
if [ -x /sbin/startproc ]; then
CTDB_INIT_STYLE="suse"
elif [ -x /sbin/start-stop-daemon ]; then
CTDB_INIT_STYLE="debian"
else
CTDB_INIT_STYLE="redhat"
fi
}
######################################################
# simulate /sbin/service on platforms that don't have it
service() {
service_name="$1"
op="$2"
# do nothing, when no service was specified
test "x$service_name" = "x" && return
if [ -x /sbin/service ]; then
/sbin/service "$service_name" "$op"
elif [ -x /etc/init.d/$service_name ]; then
/etc/init.d/$service_name "$op"
elif [ -x /etc/rc.d/init.d/$service_name ]; then
/etc/rc.d/init.d/$service_name "$op"
fi
}
######################################################
# simulate /sbin/service (niced) on platforms that don't have it
nice_service() {
service_name="$1"
op="$2"
# do nothing, when no service was specified
test "x$service_name" = "x" && return
if [ -x /sbin/service ]; then
nice /sbin/service "$service_name" "$op"
elif [ -x /etc/init.d/$service_name ]; then
nice /etc/init.d/$service_name "$op"
elif [ -x /etc/rc.d/init.d/$service_name ]; then
nice /etc/rc.d/init.d/$service_name "$op"
fi
}
######################################################
# wait for a command to return a zero exit status
# usage: ctdb_wait_command SERVICE_NAME <command>
######################################################
ctdb_wait_command() {
service_name="$1"
wait_cmd="$2"
[ -z "$wait_cmd" ] && return;
all_ok=0
echo "Waiting for service $service_name to start"
while [ $all_ok -eq 0 ]; do
$wait_cmd > /dev/null 2>&1 && all_ok=1
ctdb status > /dev/null 2>&1 || {
echo "ctdb daemon has died. Exiting wait for $service_name"
exit 1
}
[ $all_ok -eq 1 ] || sleep 1
done
echo "Local service $service_name is up"
}
######################################################
# wait for a set of tcp ports
# usage: ctdb_wait_tcp_ports SERVICE_NAME <ports...>
######################################################
ctdb_wait_tcp_ports() {
service_name="$1"
shift
wait_ports="$*"
[ -z "$wait_ports" ] && return;
all_ok=0
echo "Waiting for tcp service $service_name to start"
while [ $all_ok -eq 0 ]; do
all_ok=1
for p in $wait_ports; do
if [ -x /usr/bin/netcat ]; then
/usr/bin/netcat -z 127.0.0.1 $p > /dev/null || all_ok=0
elif [ -x /usr/bin/nc ]; then
/usr/bin/nc -z 127.0.0.1 $p > /dev/null || all_ok=0
elif [ -x /usr/bin/netstat ]; then
(netstat -a -n | egrep "0.0.0.0:$p[[:space:]]*LISTEN" > /dev/null) || all_ok=0
elif [ -x /bin/netstat ]; then
(netstat -a -n | egrep "0.0.0.0:$p[[:space:]]*LISTEN" > /dev/null) || all_ok=0
else
echo "No tool to check tcp ports availabe. can not check in ctdb_wait_tcp_ports"
return
fi
done
[ $all_ok -eq 1 ] || sleep 1
ctdb status > /dev/null 2>&1 || {
echo "ctdb daemon has died. Exiting tcp wait $service_name"
exit 1
}
done
echo "Local tcp services for $service_name are up"
}
######################################################
# wait for a set of directories
# usage: ctdb_wait_directories SERVICE_NAME <directories...>
######################################################
ctdb_wait_directories() {
service_name="$1"
shift
wait_dirs="$*"
[ -z "$wait_dirs" ] && return;
all_ok=0
echo "Waiting for local directories for $service_name"
while [ $all_ok -eq 0 ]; do
all_ok=1
for d in $wait_dirs; do
[ -d $d ] || all_ok=0
done
[ $all_ok -eq 1 ] || sleep 1
ctdb status > /dev/null 2>&1 || {
echo "ctdb daemon has died. Exiting directory wait for $service_name"
exit 1
}
done
echo "Local directories for $service_name are available"
}
######################################################
# check that a rpc server is registered with portmap
# and responding to requests
# usage: ctdb_check_rpc SERVICE_NAME PROGNUM VERSION
######################################################
ctdb_check_rpc() {
service_name="$1"
prognum="$2"
version="$3"
rpcinfo -u localhost $prognum $version > /dev/null || {
echo "ERROR: $service_name not responding to rpc requests"
exit 1
}
}
######################################################
# check a set of directories is available
# return 1 on a missing directory
# usage: ctdb_check_directories_probe SERVICE_NAME <directories...>
######################################################
ctdb_check_directories_probe() {
service_name="$1"
shift
for d ; do
case "$d" in
*%*)
continue
;;
*)
[ -d "$d" ] || return 1
esac
done
return 0
}
######################################################
# check a set of directories is available
# usage: ctdb_check_directories SERVICE_NAME <directories...>
######################################################
ctdb_check_directories() {
# Note: ctdb_check_directories_probe sets both $service_name and $d.
ctdb_check_directories_probe "$@" || {
echo "ERROR: $service_name directory $d not available"
exit 1
}
}
######################################################
# check a set of tcp ports
# usage: ctdb_check_tcp_ports SERVICE_NAME <ports...>
######################################################
ctdb_check_tcp_ports() {
service_name="$1"
shift
wait_ports="$*"
[ -z "$wait_ports" ] && return;
# check availability of netcat or netstat first
NETCAT=""
NETSTAT=""
if [ -x /usr/bin/netstat ]; then
NETSTAT=/usr/bin/netstat
elif [ -x /bin/netstat ]; then
NETSTAT=/bin/netstat
elif [ -x /usr/bin/netcat ]; then
NETCAT=/usr/bin/netcat
elif [ -x /bin/netcat ]; then
NETCAT=/bin/netcat
elif [ -x /usr/bin/nc ]; then
NETCAT=/usr/bin/nc
elif [ -x /bin/nc ]; then
NETCAT=/bin/nc
fi
for p in $wait_ports; do
all_ok=1
if [ "x${NETCAT}" != "x" ]; then
${NETCAT} -z 127.0.0.1 $p > /dev/null || all_ok=0
elif [ "x${NETSTAT}" != "x" ]; then
if ! ${NETSTAT} -a -n | egrep "0.0.0.0:$p .*LISTEN" > /dev/null ; then
if ! ${NETSTAT} -a -n | egrep ":::$p .*LISTEN" > /dev/null ; then
all_ok=0
fi
fi
else
echo "ERROR: neither netcat (or nc) nor netstat found!"
echo "ERROR: can't monitor ${service_name} tcp port ${p}"
all_ok=0
fi
[ $all_ok -eq 1 ] || {
echo "ERROR: $service_name tcp port $p is not responding"
exit 1
}
done
}
######################################################
# check a unix socket
# usage: ctdb_check_unix_socket SERVICE_NAME <socket_path>
######################################################
ctdb_check_unix_socket() {
service_name="$1"
socket_path="$2"
[ -z "$socket_path" ] && return;
# check availability of netstat first
NETSTAT=""
if [ -x $(type -p netstat) ]; then
NETSTAT=$(type -p netstat)
elif [ -x /usr/bin/netstat ]; then
NETSTAT=/usr/bin/netstat
elif [ -x /bin/netstat ]; then
NETSTAT=/bin/netstat
fi
all_ok=1
if [ "x$NETSTAT" != "x" ]; then
if $NETSTAT -l -a -n | grep -qE "^unix.*LISTEN.*${socket_path}$"; then
all_ok=1
else
all_ok=0
fi
else
[ -S ${socket_path} ] && all_ok=1 || all_ok=0
fi
[ $all_ok -eq 1 ] || {
echo "ERROR: $service_name socket $socket_path not found"
exit 1
}
}
######################################################
# check a command returns zero status
# usage: ctdb_check_command SERVICE_NAME <command>
######################################################
ctdb_check_command() {
service_name="$1"
wait_cmd="$2"
[ -z "$wait_cmd" ] && return;
$wait_cmd > /dev/null 2>&1 || {
echo "ERROR: $service_name - $wait_cmd returned error"
exit 1
}
}
################################################
# kill off any TCP connections with the given IP
################################################
kill_tcp_connections() {
_IP="$1"
_failed=0
_killcount=0
connfile="$CTDB_BASE/state/connections.$_IP"
netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' > $connfile
netstat -tn |egrep "^tcp.*[[:space:]]+::ffff:$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' >> $connfile
while read dest src; do
srcip=`echo $src | sed -e "s/:[^:]*$//"`
srcport=`echo $src | sed -e "s/^.*://"`
destip=`echo $dest | sed -e "s/:[^:]*$//"`
destport=`echo $dest | sed -e "s/^.*://"`
echo "Killing TCP connection $srcip:$srcport $destip:$destport"
ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1
case $destport in
# we only do one-way killtcp for CIFS
139|445) : ;;
# for all others we do 2-way
*)
ctdb killtcp $destip:$destport $srcip:$srcport >/dev/null 2>&1 || _failed=1
;;
esac
_killcount=`expr $_killcount + 1`
done < $connfile
/bin/rm -f $connfile
[ $_failed = 0 ] || {
echo "Failed to send killtcp control"
return;
}
[ $_killcount -gt 0 ] || {
return;
}
_count=0
while netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" > /dev/null; do
sleep 1
_count=`expr $_count + 1`
[ $_count -gt 3 ] && {
echo "Timed out killing tcp connections for IP $_IP"
return;
}
done
echo "killed $_killcount TCP connections to released IP $_IP"
}
##################################################################
# kill off the local end for any TCP connections with the given IP
##################################################################
kill_tcp_connections_local_only() {
_IP="$1"
_failed=0
_killcount=0
connfile="$CTDB_BASE/state/connections.$_IP"
netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' > $connfile
netstat -tn |egrep "^tcp.*[[:space:]]+::ffff:$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' >> $connfile
while read dest src; do
srcip=`echo $src | sed -e "s/:[^:]*$//"`
srcport=`echo $src | sed -e "s/^.*://"`
destip=`echo $dest | sed -e "s/:[^:]*$//"`
destport=`echo $dest | sed -e "s/^.*://"`
echo "Killing TCP connection $srcip:$srcport $destip:$destport"
ctdb killtcp $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1
_killcount=`expr $_killcount + 1`
done < $connfile
/bin/rm -f $connfile
[ $_failed = 0 ] || {
echo "Failed to send killtcp control"
return;
}
[ $_killcount -gt 0 ] || {
return;
}
_count=0
while netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" > /dev/null; do
sleep 1
_count=`expr $_count + 1`
[ $_count -gt 3 ] && {
echo "Timed out killing tcp connections for IP $_IP"
return;
}
done
echo "killed $_killcount TCP connections to released IP $_IP"
}
########################################################
# start/stop the nfs service on different platforms
########################################################
startstop_nfs() {
PLATFORM="unknown"
[ -x /etc/init.d/nfsserver ] && {
PLATFORM="sles"
}
[ -x /etc/init.d/nfslock ] && {
PLATFORM="rhel"
}
case $PLATFORM in
sles)
case $1 in
start)
service nfsserver start
;;
stop)
service nfsserver stop > /dev/null 2>&1
;;
esac
;;
rhel)
case $1 in
start)
service nfslock start
service nfs start
;;
stop)
service nfs stop > /dev/null 2>&1
service nfslock stop > /dev/null 2>&1
;;
esac
;;
*)
echo "Unknown platform. NFS is not supported with ctdb"
exit 1
;;
esac
}
########################################################
# start/stop the nfs lockmanager service on different platforms
########################################################
startstop_nfslock() {
PLATFORM="unknown"
[ -x /etc/init.d/nfsserver ] && {
PLATFORM="sles"
}
[ -x /etc/init.d/nfslock ] && {
PLATFORM="rhel"
}
case $PLATFORM in
sles)
# for sles there is no service for lockmanager
# so we instead just shutdown/restart nfs
case $1 in
start)
service nfsserver start
;;
stop)
service nfsserver stop > /dev/null 2>&1
;;
esac
;;
rhel)
case $1 in
start)
service nfslock start
;;
stop)
service nfslock stop > /dev/null 2>&1
;;
esac
;;
*)
echo "Unknown platform. NFS locking is not supported with ctdb"
exit 1
;;
esac
}
########################################################
# remove an ip address from an interface
########################################################
remove_ip() {
# the ip tool will delete all secondary IPs if this is the primary.
# To work around this _very_ annoying behaviour we have to keep a
# record of the secondaries and re-add them afterwards. yuck
secondaries=""
if ip addr list dev $2 primary | grep -q "inet $1 " ; then
secondaries=`ip addr list dev $2 secondary | grep " inet " | awk '{print $2}'`
fi
ip addr del $1 dev $2 >/dev/null 2>/dev/null || failed=1
[ -z "$secondaries" ] || {
for i in $secondaries; do
if ip addr list dev $2 | grep -q "inet $i" ; then
echo "kept secondary $i on dev $2"
else
echo "re-adding secondary address $i to dev $2"
ip addr add $i dev $2 || failed=1
fi
done
}
}
########################################################
# some simple logic for counting events - per eventscript
# usage: ctdb_counter_init <tag>
# ctdb_counter_incr <tag>
# ctdb_counter_limit <tag> <limit>
# e.g. <tag> = "fail-count"
# ctdb_counter_limit succeeds when count >= <limit>
########################################################
_ctdb_counter_common () {
_tag="$1"
_eventscript="${0##*/}" # basename
_counter_file="$CTDB_BASE/state/${_eventscript}-${_tag}"
mkdir -p "${_counter_file%/*}" # dirname
}
ctdb_counter_init () {
_ctdb_counter_common "$1"
echo -n > "$_counter_file"
}
ctdb_counter_incr () {
_ctdb_counter_common "$1"
# unary counting!
echo -n 1 >> "$_counter_file"
}
ctdb_counter_limit () {
_ctdb_counter_common "$1"
_limit="$2"
# unary counting!
_size=$(stat -c "%s" "$_counter_file" 2>/dev/null || echo 0)
[ $_size -ge $_limit ]
}
########################################################
# load a site local config file
########################################################
[ -x $CTDB_BASE/rc.local ] && {
. $CTDB_BASE/rc.local
}
[ -d $CTDB_BASE/rc.local.d ] && {
for i in $CTDB_BASE/rc.local.d/* ; do
[ -x "$i" ] && . "$i"
done
}