diff options
Diffstat (limited to 'heartbeat/IPaddr')
-rwxr-xr-x | heartbeat/IPaddr | 912 |
1 files changed, 912 insertions, 0 deletions
diff --git a/heartbeat/IPaddr b/heartbeat/IPaddr new file mode 100755 index 0000000..9b0ea81 --- /dev/null +++ b/heartbeat/IPaddr @@ -0,0 +1,912 @@ +#!/bin/sh +# +# License: GNU General Public License (GPL) +# Support: users@clusterlabs.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_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + +# Parameter defaults + +OCF_RESKEY_ip_default="" +OCF_RESKEY_nic_default="eth0" +OCF_RESKEY_cidr_netmask_default="" +OCF_RESKEY_broadcast_default="" +OCF_RESKEY_iflabel_default="" +OCF_RESKEY_lvs_support_default="false" +OCF_RESKEY_local_stop_script_default="" +OCF_RESKEY_local_start_script_default="" +OCF_RESKEY_ARP_INTERVAL_MS_default="500" +OCF_RESKEY_ARP_REPEAT_default="10" +OCF_RESKEY_ARP_BACKGROUND_default="yes" +OCF_RESKEY_ARP_NETMASK_default="ffffffffffff" + +: ${OCF_RESKEY_ip=${OCF_RESKEY_ip_default}} +: ${OCF_RESKEY_nic=${OCF_RESKEY_nic_default}} +: ${OCF_RESKEY_cidr_netmask=${OCF_RESKEY_cidr_netmask_default}} +: ${OCF_RESKEY_broadcast=${OCF_RESKEY_broadcast_default}} +: ${OCF_RESKEY_iflabel=${OCF_RESKEY_iflabel_default}} +: ${OCF_RESKEY_lvs_support=${OCF_RESKEY_lvs_support_default}} +: ${OCF_RESKEY_local_stop_script=${OCF_RESKEY_local_stop_script_default}} +: ${OCF_RESKEY_local_start_script=${OCF_RESKEY_local_start_script_default}} +: ${OCF_RESKEY_ARP_INTERVAL_MS=${OCF_RESKEY_ARP_INTERVAL_MS_default}} +: ${OCF_RESKEY_ARP_REPEAT=${OCF_RESKEY_ARP_REPEAT_default}} +: ${OCF_RESKEY_ARP_BACKGROUND=${OCF_RESKEY_ARP_BACKGROUND_default}} +: ${OCF_RESKEY_ARP_NETMASK=${OCF_RESKEY_ARP_NETMASK_default}} + +SENDARP=$HA_BIN/send_arp +FINDIF=$HA_BIN/findif +VLDIR=$HA_RSCTMP +SENDARPPIDDIR=$HA_RSCTMP +SENDARPPIDFILE="$SENDARPPIDDIR/send_arp-$OCF_RESKEY_ip" +USAGE="usage: $0 {start|stop|status|monitor|validate-all|meta-data}"; + +####################################################################### + +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 <<END +<?xml version="1.0"?> +<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> +<resource-agent name="IPaddr" version="1.0"> +<version>1.0</version> +<longdesc lang="en"> +This script manages IP alias IP addresses +It can add an IP alias, or remove one. +</longdesc> +<shortdesc lang="en">Manages virtual IPv4 addresses (portable version)</shortdesc> + +<parameters> +<parameter name="ip" unique="1" required="1"> +<longdesc lang="en"> +The IPv4 address to be configured in dotted quad notation, for example +"192.168.1.1". +</longdesc> +<shortdesc lang="en">IPv4 address</shortdesc> +<content type="string" default="${OCF_RESKEY_ip_default}" /> +</parameter> +<parameter name="nic" unique="0"> +<longdesc lang="en"> +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. + +Prerequisite: + +There must be at least one static IP address, which is not managed by +the cluster, assigned to the network interface. + +If you can not assign any static IP address on the interface, +modify this kernel parameter: +sysctl -w net.ipv4.conf.all.promote_secondaries=1 +(or per device) + +</longdesc> +<shortdesc lang="en">Network interface</shortdesc> +<content type="string" default="${OCF_RESKEY_nic_default}"/> +</parameter> + +<parameter name="cidr_netmask"> +<longdesc lang="en"> +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. +</longdesc> +<shortdesc lang="en">Netmask</shortdesc> +<content type="string" default="${OCF_RESKEY_cidr_netmask_default}"/> +</parameter> + +<parameter name="broadcast"> +<longdesc lang="en"> +Broadcast address associated with the IP. If left empty, the script will +determine this from the netmask. +</longdesc> +<shortdesc lang="en">Broadcast address</shortdesc> +<content type="string" default="${OCF_RESKEY_broadcast_default}"/> +</parameter> + +<parameter name="iflabel"> +<longdesc lang="en"> +You can specify an additional label for your IP address here. +</longdesc> +<shortdesc lang="en">Interface label</shortdesc> +<content type="string" default="${OCF_RESKEY_iflabel_default}"/> +</parameter> + +<parameter name="lvs_support"> +<longdesc lang="en"> +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. +</longdesc> +<shortdesc lang="en">Enable support for LVS DR</shortdesc> +<content type="boolean" default="${OCF_RESKEY_lvs_support_default}"/> +</parameter> + +<parameter name="local_stop_script"> +<longdesc lang="en"> +Script called when the IP is released +</longdesc> +<shortdesc lang="en">Script called when the IP is released</shortdesc> +<content type="string" default="${OCF_RESKEY_local_stop_script_default}"/> +</parameter> + +<parameter name="local_start_script"> +<longdesc lang="en"> +Script called when the IP is added +</longdesc> +<shortdesc lang="en">Script called when the IP is added</shortdesc> +<content type="string" default="${OCF_RESKEY_local_start_script_default}"/> +</parameter> + +<parameter name="ARP_INTERVAL_MS"> +<longdesc lang="en"> +milliseconds between ARPs +</longdesc> +<shortdesc lang="en">milliseconds between gratuitous ARPs</shortdesc> +<content type="integer" default="${OCF_RESKEY_ARP_INTERVAL_MS_default}"/> +</parameter> + +<parameter name="ARP_REPEAT"> +<longdesc lang="en"> +How many gratuitous ARPs to send out when bringing up a new address +</longdesc> +<shortdesc lang="en">repeat count</shortdesc> +<content type="integer" default="${OCF_RESKEY_ARP_REPEAT_default}"/> +</parameter> + +<parameter name="ARP_BACKGROUND"> +<longdesc lang="en"> +run in background (no longer any reason to do this) +</longdesc> +<shortdesc lang="en">run in background</shortdesc> +<content type="boolean" default="${OCF_RESKEY_ARP_BACKGROUND_default}"/> +</parameter> + +<parameter name="ARP_NETMASK"> +<longdesc lang="en"> +netmask for ARP - in nonstandard hexadecimal format. +</longdesc> +<shortdesc lang="en">netmask for ARP</shortdesc> +<content type="string" default="${OCF_RESKEY_ARP_NETMASK_default}"/> +</parameter> + +</parameters> + +<actions> +<action name="start" timeout="20s" /> +<action name="stop" timeout="20s" /> +<action name="monitor" depth="0" timeout="20s" interval="5s" /> +<action name="validate-all" timeout="20s" /> +<action name="meta-data" timeout="5s" /> +</actions> +</resource-agent> +END + exit $OCF_SUCCESS +} + +# The 'ping' command takes highly OS-dependent arguments, so this +# function creates a suitable argument list for the host OS's 'ping'. +# We use a subset of its functionality: +# 1. single packet +# 2. reasonable timeout (say 1 second) +# +# arguments: +# $1: IP address to ping +# result string: +# arguments for ping command +# +# If more flexibility is needed, they could be specified in the environment +# to this function, to adjust the resulting 'ping' arguments. +# David Lee <t.d.lee@durham.ac.uk> May 2007 +pingargs() { + _baseip=$1 + _timeout=1 # seconds + _pktcount=1 + _systype="`uname -s`" + case $_systype in + Linux) + # Default is perpetual ping: need "-c $_pktcount". + # -c count -t timetolive -q(uiet) -n(umeric) -W timeout + _pingargs="-c $_pktcount -q -n $_baseip" + ;; + SunOS) + # Default is immediate (or timeout) return. + _pingargs="$_baseip $_timeout" + ;; + *) + _pingargs="-c $_pktcount $_baseip" + ;; + esac + + echo "$_pingargs" +} + +# 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 + + if [ ! -z "${OCF_RESKEY_local_stop_script}" ]; then + if [ -x "${OCF_RESKEY_local_stop_script}" ]; then + ${OCF_RESKEY_local_stop_script} $* + fi + 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 " " " " | 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 + *:*) ifname=`echo $ifname | sed 's/:$//'`;; + *) 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/IPaddr-$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() { + 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/IPaddr-$NIC" + + if [ $rc != 0 ]; then + ocf_log warn "IP Address $OCF_RESKEY_ip NOT released: rc=$rc" + return $OCF_ERR_GENERIC + fi + return $OCF_SUCCESS +} + + +# +# 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 + + if [ ! -z "${OCF_RESKEY_local_start_script}" ]; then + if [ -x "${OCF_RESKEY_local_start_script}" ]; then + ${OCF_RESKEY_local_start_script} $* + fi + 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=$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 + MSG=`$PING $PINGARGS 2>&1` + if [ $? = 0 ]; then + return $OCF_SUCCESS + fi + done + + ocf_log err "$MSG" + 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() { + check_binary $AWK + check_binary $IFCONFIG + check_binary $ROUTE + check_binary $PING + + 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 + + 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 + +# 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 $? |