X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=config%2Ffunctions;h=4dc645b7985046b4dff1745446f5fc8dd1f0f2cb;hb=2a060eed9a2d69c55bf5f4e1acffe4cdf62eee96;hp=3c47e4a16a2dd0fc2bfee655ca6177007010cee7;hpb=9b8179ad043a80e0e18eeba427a7b7b15690d039;p=sahlberg%2Fctdb.git diff --git a/config/functions b/config/functions old mode 100644 new mode 100755 index 3c47e4a1..4dc645b7 --- a/config/functions +++ b/config/functions @@ -1,45 +1,82 @@ -#!/bin/sh # utility functions for ctdb event scripts +PATH=/bin:/usr/bin:/usr/sbin:/sbin:$PATH + ####################################### # 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 +_loadconfig() { + + if [ -z "$1" ] ; then + foo="${service_config:-${service_name}}" + if [ -n "$foo" ] ; then + loadconfig "$foo" + fi + elif [ "$1" != "ctdb" ] ; then + loadconfig "ctdb" + fi + + + if [ -f /etc/sysconfig/$1 ]; then + . /etc/sysconfig/$1 + elif [ -f /etc/default/$1 ]; then + . /etc/default/$1 + elif [ -f $CTDB_BASE/sysconfig/$1 ]; then + . $CTDB_BASE/sysconfig/$1 fi } +loadconfig () { + _loadconfig "$@" +} + +############################################################## +# 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" + _service_name="$1" + _op="$2" + + # do nothing, when no service was specified + [ -z "$_service_name" ] && 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" + /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" + _service_name="$1" + _op="$2" + + # do nothing, when no service was specified + [ -z "$_service_name" ] && 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" + 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 } @@ -84,64 +121,58 @@ ctdb_wait_tcp_ports() { 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\s*LISTEN" > /dev/null) || all_ok=0 + (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\s*LISTEN" > /dev/null) || all_ok=0 + (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 + return 127 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 + return 1 } done echo "Local tcp services for $service_name are up" } - -###################################################### -# wait for a set of directories -# usage: ctdb_wait_directories SERVICE_NAME -###################################################### -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" + progname="$1" prognum="$2" version="$3" - rpcinfo -u localhost $prognum $version > /dev/null || { - echo "ERROR: $service_name not responding to rpc requests" - exit 1 - } + + ctdb_check_rpc_out=$(rpcinfo -u localhost $prognum $version 2>&1) + if [ $? -ne 0 ] ; then + ctdb_check_rpc_out="ERROR: $progname failed RPC check: +$ctdb_check_rpc_out" + echo "$ctdb_check_rpc_out" + return 1 + fi +} + +###################################################### +# check a set of directories is available +# return 1 on a missing directory +# usage: ctdb_check_directories_probe SERVICE_NAME +###################################################### +ctdb_check_directories_probe() { + while IFS="" read d ; do + case "$d" in + *%*) + continue + ;; + *) + [ -d "${d}/." ] || return 1 + esac + done } ###################################################### @@ -149,43 +180,41 @@ ctdb_check_rpc() { # usage: ctdb_check_directories SERVICE_NAME ###################################################### ctdb_check_directories() { - service_name="$1" - shift - wait_dirs="$*" - [ -z "$wait_dirs" ] && return; - for d in $wait_dirs; do - [ -d $d ] || { - echo "ERROR: $service_name directory $d not available" - exit 1 - } - done + n="${1:-${service_name}}" + ctdb_check_directories_probe || { + echo "ERROR: $n directory \"$d\" not available" + exit 1 + } } ###################################################### # check a set of tcp ports -# usage: ctdb_check_tcp_ports SERVICE_NAME +# usage: ctdb_check_tcp_ports ###################################################### ctdb_check_tcp_ports() { - service_name="$1" - shift - wait_ports="$*" - [ -z "$wait_ports" ] && return; - for p in $wait_ports; do - all_ok=1 - 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 .*LISTEN" > /dev/null ) || all_ok=0 - elif [ -x /bin/netstat ]; then - (netstat -a -n | egrep "0.0.0.0:$p .*LISTEN" > /dev/null ) || all_ok=0 - fi - [ $all_ok -eq 1 ] || { - echo "ERROR: $service_name tcp port $p is not responding" - exit 1 - } - done + + for p ; do + if ! netstat -a -t -n | grep -q "0\.0\.0\.0:$p .*LISTEN" ; then + if ! netstat -a -t -n | grep -q ":::$p .*LISTEN" ; then + echo "ERROR: $service_name tcp port $p is not responding" + return 1 + fi + fi + done +} + +###################################################### +# check a unix socket +# usage: ctdb_check_unix_socket SERVICE_NAME +###################################################### +ctdb_check_unix_socket() { + socket_path="$1" + [ -z "$socket_path" ] && return + + if ! netstat --unix -a -n | grep -q "^unix.*LISTEN.*${socket_path}$"; then + echo "ERROR: $service_name socket $socket_path not found" + return 1 + fi } ###################################################### @@ -210,18 +239,71 @@ kill_tcp_connections() { _failed=0 _killcount=0 - connfile="$CTDB_BASE/state/connections.$_IP" - netstat -tn |egrep "^tcp.*\s+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' > $connfile + connfile="$CTDB_VARDIR/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 | cut -d: -f1` - srcport=`echo $src | cut -d: -f2` - destip=`echo $dest | cut -d: -f1` - destport=`echo $dest | cut -d: -f2` + 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_VARDIR/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 + done < $connfile /bin/rm -f $connfile + [ $_failed = 0 ] || { echo "Failed to send killtcp control" return; @@ -230,7 +312,7 @@ kill_tcp_connections() { return; } _count=0 - while netstat -tn |egrep "^tcp.*\s+$_IP:.*ESTABLISHED" > /dev/null; do + while netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" > /dev/null; do sleep 1 _count=`expr $_count + 1` [ $_count -gt 3 ] && { @@ -241,6 +323,36 @@ kill_tcp_connections() { echo "killed $_killcount TCP connections to released IP $_IP" } +################################################################## +# tickle any TCP connections with the given IP +################################################################## +tickle_tcp_connections() { + _IP="$1" + _failed=0 + + _killcount=0 + connfile="$CTDB_VARDIR/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 "Tickle TCP connection $srcip:$srcport $destip:$destport" + ctdb tickle $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1 + echo "Tickle TCP connection $destip:$destport $srcip:$srcport" + ctdb tickle $destip:$destport $srcip:$srcport >/dev/null 2>&1 || _failed=1 + done < $connfile + /bin/rm -f $connfile + + [ $_failed = 0 ] || { + echo "Failed to send tickle control" + return; + } +} + ######################################################## # start/stop the nfs service on different platforms ######################################################## @@ -262,6 +374,9 @@ startstop_nfs() { stop) service nfsserver stop > /dev/null 2>&1 ;; + restart) + service nfsserver restart + ;; esac ;; rhel) @@ -274,6 +389,10 @@ startstop_nfs() { service nfs stop > /dev/null 2>&1 service nfslock stop > /dev/null 2>&1 ;; + restart) + service nfslock restart + service nfs restart + ;; esac ;; *) @@ -306,6 +425,10 @@ startstop_nfslock() { stop) service nfsserver stop > /dev/null 2>&1 ;; + restart) + service nfsserver stop + service nfsserver start + ;; esac ;; rhel) @@ -316,6 +439,10 @@ startstop_nfslock() { stop) service nfslock stop > /dev/null 2>&1 ;; + restart) + service nfslock stop + service nfslock start + ;; esac ;; *) @@ -325,6 +452,416 @@ startstop_nfslock() { esac } +# better use delete_ip_from_iface() together with add_ip_to_iface +# remove_ip should be removed in future +remove_ip() { + local _ip_maskbits=$1 + local _iface=$2 + local _ip=`echo "$_ip_maskbits" | cut -d '/' -f1` + local _maskbits=`echo "$_ip_maskbits" | cut -d '/' -f2` + + delete_ip_from_iface "$_iface" "$_ip" "$_maskbits" + return $? +} + +add_ip_to_iface() +{ + local _iface=$1 + local _ip=$2 + local _maskbits=$3 + local _state_dir="$CTDB_VARDIR/state/interface_modify" + local _lockfile="$_state_dir/$_iface.flock" + local _readd_base="$_state_dir/$_iface.readd.d" + + mkdir -p $_state_dir || { + ret=$? + echo "Failed to mkdir -p $_state_dir - $ret" + return $ret + } + + test -f $_lockfile || { + touch $_lockfile + } + + flock --timeout 30 $_lockfile $CTDB_BASE/interface_modify.sh add "$_iface" "$_ip" "$_maskbits" "$_readd_base" + return $? +} + +delete_ip_from_iface() +{ + local _iface=$1 + local _ip=$2 + local _maskbits=$3 + local _state_dir="$CTDB_VARDIR/state/interface_modify" + local _lockfile="$_state_dir/$_iface.flock" + local _readd_base="$_state_dir/$_iface.readd.d" + + mkdir -p $_state_dir || { + ret=$? + echo "Failed to mkdir -p $_state_dir - $ret" + return $ret + } + + test -f $_lockfile || { + touch $_lockfile + } + + flock --timeout 30 $_lockfile $CTDB_BASE/interface_modify.sh delete "$_iface" "$_ip" "$_maskbits" "$_readd_base" + return $? +} + +setup_iface_ip_readd_script() +{ + local _iface=$1 + local _ip=$2 + local _maskbits=$3 + local _readd_script=$4 + local _state_dir="$CTDB_VARDIR/state/interface_modify" + local _lockfile="$_state_dir/$_iface.flock" + local _readd_base="$_state_dir/$_iface.readd.d" + + mkdir -p $_state_dir || { + ret=$? + echo "Failed to mkdir -p $_state_dir - $ret" + return $ret + } + + test -f $_lockfile || { + touch $_lockfile + } + + flock --timeout 30 $_lockfile $CTDB_BASE/interface_modify.sh readd_script "$_iface" "$_ip" "$_maskbits" "$_readd_base" "$_readd_script" + return $? +} + +######################################################## +# some simple logic for counting events - per eventscript +# usage: ctdb_counter_init +# ctdb_counter_incr +# ctdb_check_counter_limit +# ctdb_check_counter_limit succeeds when count >= +######################################################## +_ctdb_counter_common () { + _counter_file="$ctdb_fail_dir/$service_name" + mkdir -p "${_counter_file%/*}" # dirname +} +ctdb_counter_init () { + _ctdb_counter_common + + >"$_counter_file" +} +ctdb_counter_incr () { + _ctdb_counter_common + + # unary counting! + echo -n 1 >> "$_counter_file" +} +ctdb_check_counter_limit () { + _ctdb_counter_common + + _limit="${1:-${service_fail_limit}}" + _quiet="$2" + + # unary counting! + _size=$(stat -c "%s" "$_counter_file" 2>/dev/null || echo 0) + if [ $_size -ge $_limit ] ; then + echo "ERROR: more than $_limit consecutive failures for $service_name, marking cluster unhealthy" + exit 1 + elif [ $_size -gt 0 -a -z "$_quiet" ] ; then + echo "WARNING: less than $_limit consecutive failures ($_size) for $service_name, not unhealthy yet" + fi +} +ctdb_check_counter_equal () { + _ctdb_counter_common + + _limit=$1 + + # unary counting! + _size=$(stat -c "%s" "$_counter_file" 2>/dev/null || echo 0) + if [ $_size -eq $_limit ] ; then + return 1 + fi + return 0 +} + +######################################################## + +ctdb_spool_dir="/var/spool/ctdb" +ctdb_status_dir="$ctdb_spool_dir/status" +ctdb_fail_dir="$ctdb_spool_dir/failcount" +ctdb_active_dir="$ctdb_spool_dir/active" + +log_status_cat () +{ + echo "node is \"$1\", \"${script_name}\" reports problem: $(cat $2)" +} + +ctdb_checkstatus () +{ + if [ -r "$ctdb_status_dir/$script_name/unhealthy" ] ; then + log_status_cat "unhealthy" "$ctdb_status_dir/$script_name/unhealthy" + return 1 + elif [ -r "$ctdb_status_dir/$script_name/banned" ] ; then + log_status_cat "banned" "$ctdb_status_dir/$script_name/banned" + return 2 + else + return 0 + fi +} + +ctdb_setstatus () +{ + d="$ctdb_status_dir/$script_name" + case "$1" in + unhealthy|banned) + mkdir -p "$d" + cat "$2" >"$d/$1" + ;; + *) + for i in "banned" "unhealthy" ; do + rm -f "$d/$i" + done + ;; + esac +} + +ctdb_service_needs_reconfigure () +{ + [ -e "$ctdb_status_dir/$service_name/reconfigure" ] +} + +ctdb_service_set_reconfigure () +{ + d="$ctdb_status_dir/$service_name" + mkdir -p "$d" + >"$d/reconfigure" +} + +ctdb_service_unset_reconfigure () +{ + rm -f "$ctdb_status_dir/$service_name/reconfigure" +} + +ctdb_service_reconfigure () +{ + if [ -n "$service_reconfigure" ] ; then + eval $service_reconfigure + else + service "$service_name" restart + fi + ctdb_service_unset_reconfigure + ctdb_counter_init +} + +ctdb_compat_managed_service () +{ + if [ "$1" = "yes" ] ; then + t="$t $2 " + fi +} + +is_ctdb_managed_service () +{ + _service_name="${1:-${service_name}}" + + t=" $CTDB_MANAGED_SERVICES " + + ctdb_compat_managed_service "$CTDB_MANAGES_VSFTPD" "vsftpd" + ctdb_compat_managed_service "$CTDB_MANAGES_SAMBA" "samba" + ctdb_compat_managed_service "$CTDB_MANAGES_SCP" "scp" + ctdb_compat_managed_service "$CTDB_MANAGES_WINBIND" "winbind" + ctdb_compat_managed_service "$CTDB_MANAGES_HTTPD" "httpd" + ctdb_compat_managed_service "$CTDB_MANAGES_ISCSI" "iscsi" + ctdb_compat_managed_service "$CTDB_MANAGES_CLAMD" "clamd" + ctdb_compat_managed_service "$CTDB_MANAGES_NFS" "nfs" + ctdb_compat_managed_service "$CTDB_MANAGES_NFS" "nfs-ganesha-gpfs" + + # Returns 0 if "$_service_name" appears in $t + [ "${t#* ${_service_name} }" != "${t}" ] +} + +ctdb_start_stop_service () +{ + _service_name="${1:-${service_name}}" + + _active="$ctdb_active_dir/$_service_name" + if is_ctdb_managed_service "$_service_name"; then + if ! [ -e "$_active" ] ; then + echo "Starting service $_service_name" + ctdb_service_start || exit $? + mkdir -p "$ctdb_active_dir" + touch "$_active" + exit 0 + fi + else + if [ -e "$_active" ] ; then + echo "Stopping service $_service_name" + ctdb_service_stop || exit $? + rm -f "$_active" + exit 0 + fi + fi +} + +ctdb_service_start () +{ + if [ -n "$service_start" ] ; then + eval $service_start || return $? + else + service "$service_name" start || return $? + fi + ctdb_counter_init +} + +ctdb_service_stop () +{ + if [ -n "$service_stop" ] ; then + eval $service_stop + else + service "$service_name" stop + fi +} + +ctdb_standard_event_handler () +{ + case "$1" in + status) + ctdb_checkstatus + exit + ;; + setstatus) + shift + ctdb_setstatus "$@" + exit + ;; + esac +} + +ipv4_host_addr_to_net_addr() +{ + local HOST=$1 + local MASKBITS=$2 + + local HOST0=$(echo $HOST | awk -F . '{print $4}') + local HOST1=$(echo $HOST | awk -F . '{print $3}') + local HOST2=$(echo $HOST | awk -F . '{print $2}') + local HOST3=$(echo $HOST | awk -F . '{print $1}') + + local HOST_NUM=$(( $HOST0 + $HOST1 * 256 + $HOST2 * (256 ** 2) + $HOST3 * (256 ** 3) )) + + local MASK_NUM=$(( ( (2**32 - 1) * (2**(32 - $MASKBITS)) ) & (2**32 - 1) )) + + local NET_NUM=$(( $HOST_NUM & $MASK_NUM)) + + local NET0=$(( $NET_NUM & 255 )) + local NET1=$(( ($NET_NUM & (255 * 256)) / 256 )) + local NET2=$(( ($NET_NUM & (255 * 256**2)) / 256**2 )) + local NET3=$(( ($NET_NUM & (255 * 256**3)) / 256**3 )) + + echo "$NET3.$NET2.$NET1.$NET0" +} + +ipv4_maskbits_to_net_mask() +{ + local MASKBITS=$1 + + local MASK_NUM=$(( ( (2**32 - 1) * (2**(32 - $MASKBITS)) ) & (2**32 - 1) )) + + local MASK0=$(( $MASK_NUM & 255 )) + local MASK1=$(( ($MASK_NUM & (255 * 256)) / 256 )) + local MASK2=$(( ($MASK_NUM & (255 * 256**2)) / 256**2 )) + local MASK3=$(( ($MASK_NUM & (255 * 256**3)) / 256**3 )) + + echo "$MASK3.$MASK2.$MASK1.$MASK0" +} + +ipv4_is_valid_addr() +{ + local ADDR=$1 + local fail=0 + + local N=`echo $ADDR | sed -e 's/[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*//'` + test -n "$N" && fail=1 + + local ADDR0=$(echo $ADDR | awk -F . '{print $4}') + local ADDR1=$(echo $ADDR | awk -F . '{print $3}') + local ADDR2=$(echo $ADDR | awk -F . '{print $2}') + local ADDR3=$(echo $ADDR | awk -F . '{print $1}') + + test "$ADDR0" -gt 255 && fail=1 + test "$ADDR1" -gt 255 && fail=1 + test "$ADDR2" -gt 255 && fail=1 + test "$ADDR3" -gt 255 && fail=1 + + test x"$fail" != x"0" && { + #echo "IPv4: '$ADDR' is not a valid address" + return 1; + } + + return 0; +} + +# iptables doesn't like being re-entered, so flock-wrap it. +iptables() +{ + flock -w 30 /var/ctdb/iptables-ctdb.flock /sbin/iptables "$@" +} + +######################################################## +# tickle handling +######################################################## + +# Temporary directory for tickles. +tickledir="$CTDB_VARDIR/state/tickles" +mkdir -p "$tickledir" + +update_tickles () +{ + _port="$1" + + mkdir -p "$tickledir" # Just in case + + # Who am I? + _pnn=$(ctdb pnn) ; _pnn=${_pnn#PNN:} + + # What public IPs do I hold? + _ips=$(ctdb -Y ip | awk -F: -v pnn=$_pnn '$3 == pnn {print $2}') + + # IPs as a regexp choice + _ipschoice="($(echo $_ips | sed -e 's/ /|/g' -e 's/\./\\\\./g'))" + + # Record connections to our public IPs in a temporary file + _my_connections="${tickledir}/${_port}.connections" + rm -f "$_my_connections" + netstat -tn | + awk -v destpat="^${_ipschoice}:${_port}\$" \ + '$1 == "tcp" && $6 == "ESTABLISHED" && $4 ~ destpat {print $5, $4}' | + sort >"$_my_connections" + + # Record our current tickles in a temporary file + _my_tickles="${tickledir}/${_port}.tickles" + rm -f "$_my_tickles" + for _i in $_ips ; do + ctdb -Y gettickles $_i $_port | + awk -F: 'NR > 1 { printf "%s:%s %s:%s\n", $2, $3, $4, $5 }' + done | + sort >"$_my_tickles" + + # Add tickles for connections that we haven't already got tickles for + comm -23 "$_my_connections" "$_my_tickles" | + while read _src _dst ; do + ctdb addtickle $_src $_dst + done + + # Remove tickles for connections that are no longer there + comm -13 "$_my_connections" "$_my_tickles" | + while read _src _dst ; do + ctdb deltickle $_src $_dst + done + + rm -f "$_my_connections" "$_my_tickles" +} + ######################################################## # load a site local config file ######################################################## @@ -332,3 +869,13 @@ startstop_nfslock() { [ -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 +} + +script_name="${0##*/}" # basename +service_name="$script_name" # default is just the script name +service_fail_limit=1