Eventscripts - Remove local variable usage in 10.interfaces.
[obnox/samba/samba-obnox.git] / ctdb / config / events.d / 10.interface
1 #!/bin/sh
2
3 #################################
4 # interface event script for ctdb
5 # this adds/removes IPs from your 
6 # public interface
7
8 . $CTDB_BASE/functions
9 loadconfig
10
11 [ -z "$CTDB_PUBLIC_ADDRESSES" ] && {
12         CTDB_PUBLIC_ADDRESSES=$CTDB_BASE/public_addresses
13 }
14
15 [ ! -f "$CTDB_PUBLIC_ADDRESSES" ] && {
16         exit 0
17 }
18
19 monitor_interfaces()
20 {
21         INTERFACES=`cat $CTDB_PUBLIC_ADDRESSES |
22                 sed -e "s/^[^\t ]*[\t ]*//" -e "s/,/ /g" -e "s/[\t ]*$//"`
23
24         [ "$CTDB_PUBLIC_INTERFACE" ] && INTERFACES="$CTDB_PUBLIC_INTERFACE $INTERFACES"
25         [ "$CTDB_NATGW_PUBLIC_IFACE" ] && INTERFACES="$CTDB_NATGW_PUBLIC_IFACE $INTERFACES"
26
27
28         # For all but the 1st line, get the 2nd last field with commas
29         # changes to spaces.
30         IFACES=`ctdb -Y ip -v | sed -e '1d' -e 's/:[^:]*:$//' -e 's/^.*://' -e 's/,/ /g'`
31
32         INTERFACES=`for IFACE in $INTERFACES $IFACES ; do echo $IFACE ; done | sort | uniq`
33
34         fail=0
35         ok=0
36         for IFACE in $INTERFACES ; do
37
38             ip addr show $IFACE 2>/dev/null >/dev/null || {
39                 echo Interface $IFACE does not exist but it is used by public addresses.
40                 continue
41             }
42
43             # These interfaces are sometimes bond devices
44             # When we use VLANs for bond interfaces, there will only
45             # be an entry in /proc for the underlying real interface
46             REALIFACE=`echo $IFACE |sed -e 's/\..*$//'`
47             bi=$(get_proc "net/bonding/$REALIFACE") 2>/dev/null && {
48                 echo "$bi" | grep -q 'Currently Active Slave: None' && {
49                         echo "ERROR: No active slaves for bond device $REALIFACE"
50                         fail=1
51                         ctdb setifacelink $IFACE down >/dev/null 2>/dev/null
52                         continue;
53                 }
54                 echo "$bi" | grep -q '^MII Status: up' || {
55                         echo "ERROR: public network interface $REALIFACE is down"
56                         fail=1
57                         ctdb setifacelink $IFACE down >/dev/null 2>/dev/null
58                         continue;
59                 }
60                 echo "$bi" | grep -q '^Bonding Mode: IEEE 802.3ad Dynamic link aggregation' && {
61                         echo "$bi" | grep 'MII Status:' | tail -n +2 | grep -q '^MII Status: up' || {
62                                 echo No active slaves for 802.ad bond device $REALIFACE
63                                 ctdb setifacelink $IFACE down >/dev/null 2>/dev/null
64                                 fail=1
65                                 continue
66                         }
67                 }
68                 ok=1 # we only set ok for interfaces known to ctdbd
69                 ctdb setifacelink $IFACE up >/dev/null 2>/dev/null
70                 continue;
71             }
72
73             case $IFACE in
74             lo*)
75                 # loopback is always working
76                 ok=1 # we only set ok for interfaces known to ctdbd
77                 ctdb setifacelink $IFACE up >/dev/null 2>/dev/null
78                 ;;
79             ib*)
80                 # we dont know how to test ib links
81                 ok=1 # we only set ok for interfaces known to ctdbd
82                 ctdb setifacelink $IFACE up >/dev/null 2>/dev/null
83                 ;;
84             *)
85                 [ -z "$IFACE" ] || {
86                     [ "$(basename $(readlink /sys/class/net/$IFACE/device/driver) 2>/dev/null)" = virtio_net ] ||
87                     ethtool $IFACE | grep -q 'Link detected: yes' || {
88                         # On some systems, this is not successful when a
89                         # cable is plugged but the interface has not been
90                         # brought up previously. Bring the interface up and
91                         # try again...
92                         ip link set $IFACE up
93                         ethtool $IFACE | grep -q 'Link detected: yes' || {
94                             echo "ERROR: No link on the public network interface $IFACE"
95                             fail=1
96                             ctdb setifacelink $IFACE down >/dev/null 2>/dev/null
97                             continue
98                         }
99                     }
100                     ok=1 # we only set ok for interfaces known to ctdbd
101                     ctdb setifacelink $IFACE up >/dev/null 2>/dev/null
102                 }
103                 ;;
104             esac
105
106         done
107
108         test x"$fail" = x"0" && {
109                 return 0;
110         }
111
112         test x"$ok" = x"1" && {
113                 return 2;
114         }
115
116         return 1;
117 }
118
119 case "$1" in 
120      #############################
121      # called when ctdbd starts up
122      init)
123         # make sure that we only respond to ARP messages from the NIC where
124         # a particular ip address is associated.
125         get_proc sys/net/ipv4/conf/all/arp_filter >/dev/null 2>&1 && {
126             set_proc sys/net/ipv4/conf/all/arp_filter 1
127         }
128         ;;
129
130      #############################
131      # called after ctdbd has done its initial recovery
132      # and we start the services to become healthy
133      startup)
134         # Assume all links are good initially
135         INTERFACES=`for IFACE in $INTERFACES ; do echo $IFACE ; done | sort | uniq`
136
137         for IFACE in $INTERFACES ; do
138                 ctdb setifacelink $IFACE down >/dev/null 2>/dev/null
139         done
140         
141         monitor_interfaces
142
143         ;;
144
145
146      ################################################
147      # called when ctdbd wants to claim an IP address
148      takeip)
149         if [ $# != 4 ]; then
150            echo "must supply interface, IP and maskbits"
151            exit 1
152         fi
153         iface=$2
154         ip=$3
155         maskbits=$4
156
157         add_ip_to_iface $iface $ip $maskbits || {
158                 exit 1;
159         }
160
161         # cope with the script being killed while we have the interface blocked
162         iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
163
164         # flush our route cache
165         set_proc sys/net/ipv4/route/flush 1
166         ;;
167
168
169      ##################################################
170      # called when ctdbd wants to release an IP address
171      releaseip)
172         if [ $# != 4 ]; then
173            echo "must supply interface, IP and maskbits"
174            exit 1
175         fi
176
177         # releasing an IP is a bit more complex than it seems. Once the IP
178         # is released, any open tcp connections to that IP on this host will end
179         # up being stuck. Some of them (such as NFS connections) will be unkillable
180         # so we need to use the killtcp ctdb function to kill them off. We also
181         # need to make sure that no new connections get established while we are 
182         # doing this! So what we do is this:
183         # 1) firewall this IP, so no new external packets arrive for it
184         # 2) use netstat -tn to find existing connections, and kill them 
185         # 3) remove the IP from the interface
186         # 4) remove the firewall rule
187         iface=$2
188         ip=$3
189         maskbits=$4
190
191         failed=0
192         # we do an extra delete to cope with the script being killed
193         iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
194         iptables -I INPUT -i $iface -d $ip -j DROP
195         kill_tcp_connections $ip
196
197         delete_ip_from_iface $iface $ip $maskbits || {
198                 iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
199                 exit 1;
200         }
201
202         iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
203
204         # flush our route cache
205         set_proc sys/net/ipv4/route/flush 1
206         ;;
207
208      ##################################################
209      # called when ctdbd wants to update an IP address
210      updateip)
211         if [ $# != 5 ]; then
212            echo "must supply old interface, new interface, IP and maskbits"
213            exit 1
214         fi
215
216         # moving an IP is a bit more complex than it seems.
217         # First we drop all traffic on the old interface.
218         # Then we try to add the ip to the new interface and before
219         # we finally remove it from the old interface.
220         #
221         # 1) firewall this IP, so no new external packets arrive for it
222         # 2) add the IP to the new interface
223         # 3) remove the IP from the old interface
224         # 4) remove the firewall rule
225         # 5) use ctdb gratiousarp to propagate the new mac address
226         # 6) use netstat -tn to find existing connections, and tickle them
227         oiface=$2
228         niface=$3
229         ip=$4
230         maskbits=$5
231
232         failed=0
233         # we do an extra delete to cope with the script being killed
234         iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
235         iptables -I INPUT -i $oiface -d $ip -j DROP
236
237         delete_ip_from_iface $oiface $ip $maskbits 2>/dev/null
238         delete_ip_from_iface $niface $ip $maskbits 2>/dev/null
239
240         add_ip_to_iface $niface $ip $maskbits || {
241                 iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
242                 exit 1;
243         }
244
245         # cope with the script being killed while we have the interface blocked
246         iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
247
248         # flush our route cache
249         set_proc sys/net/ipv4/route/flush 1
250
251         # propagate the new mac address
252         ctdb gratiousarp $ip $niface
253
254         # tickle all existing connections, so that dropped packets
255         # are retransmited and the tcp streams work
256
257         tickle_tcp_connections $ip
258
259         ;;
260
261
262      ###########################################
263      # called when ctdbd has finished a recovery
264      recovered)
265         ;;
266
267      ####################################
268      # called when ctdbd is shutting down
269      shutdown)
270         ;;
271
272      monitor)
273         monitor_interfaces
274         ret=$?
275
276         test x"$ret" = x"2" && {
277                 test x"$CTDB_PARTIALLY_ONLINE_INTERFACES" != x"yes" && {
278                         exit 1;
279                 }
280                 # as long as we have one interface available don't become
281                 # unhealthy
282                 ret=0
283         }
284
285         test x"$ret" != x"0" && {
286                 exit 1;
287         }
288         ;;
289     *)
290         ctdb_standard_event_handler "$@"
291         ;;
292 esac
293
294 exit 0
295