Sophie

Sophie

distrib > Fedora > 15 > i386 > by-pkgid > aec460a90bd5c896caaa1d0425124291 > files > 5

ctdb-1.0.114-2.fc15.i686.rpm

#!/bin/sh

#################################
# interface event script for ctdb
# this adds/removes IPs from your 
# public interface

. $CTDB_BASE/functions
loadconfig

[ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
	CTDB_PUBLIC_ADDRESSES=$CTDB_BASE/public_addresses
}

[ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && {
	echo "No public addresses file found. Nothing to do for 10.interfaces"
	exit 0
}

monitor_interfaces()
{
	local INTERFACES=`cat $CTDB_PUBLIC_ADDRESSES |
		sed -e "s/^[^\t ]*[\t ]*//" -e "s/,/ /g" -e "s/[\t ]*$//"`

	[ "$CTDB_PUBLIC_INTERFACE" ] && INTERFACES="$CTDB_PUBLIC_INTERFACE $INTERFACES"
	[ "$CTDB_NATGW_PUBLIC_IFACE" ] && INTERFACES="$CTDB_NATGW_PUBLIC_IFACE $INTERFACES"

	local IFACES=`ctdb ifaces -Y | grep -v '^:Name:LinkStatus:References:'`

	local I
	local IFACE

	for I in $IFACES; do
		IFACE=`echo -n "$I" | cut -d ':' -f2`
		INTERFACES="$IFACE $INTERFACES"
	done

	INTERFACES=`for IFACE in $INTERFACES ; do echo $IFACE ; done | sort | uniq`

	local fail=0
	local force_fail=0
	local ok=0
	for IFACE in $INTERFACES ; do

	    local OLDLINK=`echo -n "$IFACES" | grep "^:$IFACE:" | cut -d ':' -f3 | xargs`
	    test -z "$OLDLINK" && {
		force_fail=1
	    }

	    # These interfaces are sometimes bond devices
	    # When we use VLANs for bond interfaces, there will only
	    # be an entry in /proc for the underlying real interface
	    local REALIFACE=`echo $IFACE |sed -e 's/\..*$//'`
	    [ -f /proc/net/bonding/$REALIFACE ] && {
		grep -q 'Currently Active Slave: None' /proc/net/bonding/$REALIFACE && {
			echo "ERROR: No active slaves for bond device $REALIFACE"
			fail=1
			test -n "$OLDLINK" && {
				ctdb setifacelink $IFACE down
			}
			continue;
		}
		grep -q '^MII Status: up' /proc/net/bonding/$REALIFACE || {
			echo "ERROR: public network interface $REALIFACE is down"
			fail=1
			test -n "$OLDLINK" && {
				ctdb setifacelink $IFACE down
			}
			continue;
		}
		test -n "$OLDLINK" && {
			ok=1 # we only set ok for interfaces known to ctdbd
			ctdb setifacelink $IFACE up
		}
		return 0;
	    }

	    case $IFACE in
	    ib*)
		# we dont know how to test ib links
		;;
	    *)
		[ -z "$IFACE" ] || {
		    ethtool $IFACE | grep -q 'Link detected: yes' || {
			# On some systems, this is not successful when a
			# cable is plugged but the interface has not been
			# brought up previously. Bring the interface up and
			# try again...
			/sbin/ip link set $IFACE up
			ethtool $IFACE | grep -q 'Link detected: yes' || {
			    echo "ERROR: No link on the public network interface $IFACE"
			    fail=1
			    test -n "$OLDLINK" && {
				ctdb setifacelink $IFACE down
			    }
			    continue
			}
		    }
		    test -n "$OLDLINK" && {
			ok=1 # we only set ok for interfaces known to ctdbd
			ctdb setifacelink $IFACE up
		    }
		}
		;;
	    esac

	done

	test x"$fail" = x"0" && {
		return 0;
	}

	test x"$force_fail" != x"0" && {
		return 1;
	}

	test x"$ok" = x"1" && {
		return 2;
	}

	return 1;
}

case "$1" in 
     #############################
     # called when ctdbd starts up
     init)
	# make sure that we only respond to ARP messages from the NIC where
	# a particular ip address is associated.
	[ -f /proc/sys/net/ipv4/conf/all/arp_filter ] && {
	    echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
	}
	cat "$CTDB_PUBLIC_ADDRESSES" | cut -d/ -f1 | while read _IP; do
		_IP_HELD=`/sbin/ip addr show | grep "inet $_IP/"`
		[ -z "$_IP_HELD" ] || {
			_IFACE=`echo $_IP_HELD | sed -e "s/.*\s//"`
			_NM=`echo $_IP_HELD | sed -e "s/.*$_IP\///" -e "s/\s.*//"`
			echo "Removing public address $_IP/$_NM from device $_IFACE"
			delete_ip_from_iface $_IFACE $_IP $_NM
		}
	done
	;;

     #############################
     # called after ctdbd has done its initial recovery
     # and we start the services to become healthy
     startup)
	monitor_interfaces

	;;


     ################################################
     # called when ctdbd wants to claim an IP address
     takeip)
	if [ $# != 4 ]; then
	   echo "must supply interface, IP and maskbits"
	   exit 1
	fi
	iface=$2
	ip=$3
	maskbits=$4

	add_ip_to_iface $iface $ip $maskbits || {
		exit 1;
	}

	# cope with the script being killed while we have the interface blocked
	iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null

	# flush our route cache
	echo 1 > /proc/sys/net/ipv4/route/flush
	;;


     ##################################################
     # called when ctdbd wants to release an IP address
     releaseip)
	if [ $# != 4 ]; then
	   echo "must supply interface, IP and maskbits"
	   exit 1
	fi

	# releasing an IP is a bit more complex than it seems. Once the IP
	# is released, any open tcp connections to that IP on this host will end
	# up being stuck. Some of them (such as NFS connections) will be unkillable
	# so we need to use the killtcp ctdb function to kill them off. We also
	# need to make sure that no new connections get established while we are 
	# doing this! So what we do is this:
	# 1) firewall this IP, so no new external packets arrive for it
	# 2) use netstat -tn to find existing connections, and kill them 
	# 3) remove the IP from the interface
	# 4) remove the firewall rule
	iface=$2
	ip=$3
	maskbits=$4

	failed=0
	# we do an extra delete to cope with the script being killed
	iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
	iptables -I INPUT -i $iface -d $ip -j DROP
	kill_tcp_connections $ip

	delete_ip_from_iface $iface $ip $maskbits || {
		iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
		exit 1;
	}

	iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null

	# flush our route cache
	echo 1 > /proc/sys/net/ipv4/route/flush
	;;

     ##################################################
     # called when ctdbd wants to update an IP address
     updateip)
	if [ $# != 5 ]; then
	   echo "must supply old interface, new interface, IP and maskbits"
	   exit 1
	fi

	# moving an IP is a bit more complex than it seems.
	# First we drop all traffic on the old interface.
	# Then we try to add the ip to the new interface and before
	# we finally remove it from the old interface.
	#
	# 1) firewall this IP, so no new external packets arrive for it
	# 2) add the IP to the new interface
	# 3) remove the IP from the old interface
	# 4) remove the firewall rule
	# 5) use ctdb gratiousarp to propagate the new mac address
	# 6) use netstat -tn to find existing connections, and tickle them
	oiface=$2
	niface=$3
	ip=$4
	maskbits=$5

	failed=0
	# we do an extra delete to cope with the script being killed
	iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
	iptables -I INPUT -i $oiface -d $ip -j DROP

	# we make sure the interface is up first
	add_ip_to_iface $niface $ip $maskbits || {
		iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
		exit 1;
	}

	delete_ip_from_iface $oiface $ip $maskbits || {
		delete_ip_from_iface $niface $ip $maskbits
		iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
		exit 1;
	}

	# cope with the script being killed while we have the interface blocked
	iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null

	# flush our route cache
	echo 1 > /proc/sys/net/ipv4/route/flush

	# propagate the new mac address
	ctdb gratiousarp $ip $niface

	# tickle all existing connections, so that dropped packets
	# are retransmited and the tcp streams work

	tickle_tcp_connections $ip

	;;


     ###########################################
     # called when ctdbd has finished a recovery
     recovered)
	;;

     ####################################
     # called when ctdbd is shutting down
     shutdown)
	;;

     monitor)
	monitor_interfaces
	ret=$?

	test x"$ret" = x"2" && {
		test x"$CTDB_PARTIALLY_ONLINE_INTERFACES" != x"yes" && {
			exit 1;
		}
		# as long as we have one interface available don't become
		# unhealthy
		ret=0
	}

	test x"$ret" != x"0" && {
		exit 1;
	}
	;;
    *)
	ctdb_standard_event_handler "$@"
	;;
esac

exit 0