Whamcloud - gitweb
LU-8457 pacemaker: Pacemaker script to monitor LNet
[fs/lustre-release.git] / contrib / scripts / pacemaker / healthLNET
1 #!/bin/sh
2 #
3 #
4 #       LNet OCF RA
5 #
6
7 # License:      GNU General Public License (GPL)v2
8 # Description:  Manages ZFS and Lustre on a shared storage
9 # Written by:   Gabriele Paciucci
10 # Release Date: 01 September 2016
11 # Release Version: 0.99
12
13 # Copyright (c) 2009 Andrew Beekhof
14 # Copyright (c) 2016, Intel Corporation
15
16 #
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of version 2 of the GNU General Public License as
19 # published by the Free Software Foundation.
20 #
21 # This program is distributed in the hope that it would be useful, but
22 # WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 #
25 # Further, this software is distributed without any warranty that it is
26 # free of the rightful claim of any third person regarding infringement
27 # or the like.  Any license provided herein, whether implied or
28 # otherwise, applies only to this software file.  Patent licenses, if
29 # any, provided herein do not apply to combinations of this program with
30 # other software, or any other product whatsoever.
31 #
32 # You should have received a copy of the GNU General Public License
33 # along with this program; if not, write the Free Software Foundation,
34 # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
35 #
36
37 #######################################################################
38 # Initialization:
39
40 : ${OCF_FUNCTIONS=${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs}
41 . ${OCF_FUNCTIONS}
42 : ${__OCF_ACTION=$1}
43
44 #######################################################################
45
46 meta_data() {
47         cat <<END
48 <?xml version="1.0"?>
49 <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
50 <resource-agent name="healthLNET">
51 <version>0.99</version>
52
53 <longdesc lang="en">
54 Every time the monitor action is run, this resource agent records (in the CIB)
55 the current number of lctl ping nodes the host can connect to.
56 </longdesc>
57 <shortdesc lang="en">LNet connectivity</shortdesc>
58
59 <parameters>
60
61 <parameter name="pidfile" unique="0">
62 <longdesc lang="en">PID file</longdesc>
63 <shortdesc lang="en">PID file</shortdesc>
64 <content type="string" default="$HA_VARRUN/ping-${OCF_RESOURCE_INSTANCE}" />
65 </parameter>
66
67 <parameter name="dampen" unique="0">
68 <longdesc lang="en">
69 The time to wait (dampening) further changes occur
70 </longdesc>
71 <shortdesc lang="en">Dampening interval</shortdesc>
72 <content type="integer" default="5s"/>
73 </parameter>
74
75 <parameter name="name" unique="0">
76 <longdesc lang="en">
77 The name of the attributes to set.  This is the name to be used in the constraints.
78 </longdesc>
79 <shortdesc lang="en">Attribute name</shortdesc>
80 <content type="string" default="pingd"/>
81 </parameter>
82
83 <parameter name="multiplier" unique="0">
84 <longdesc lang="en">
85 The number by which to multiply the number of connected ping nodes by
86 </longdesc>
87 <shortdesc lang="en">Value multiplier</shortdesc>
88 <content type="integer" default=""/>
89 </parameter>
90
91 <parameter name="host_list" unique="0" required="1">
92 <longdesc lang="en">
93 The list of ping nodes to count.
94 </longdesc>
95 <shortdesc lang="en">Host list</shortdesc>
96 <content type="string" default=""/>
97 </parameter>
98
99 <parameter name="attempts" unique="0">
100 <longdesc lang="en">
101 Number of ping attempts, per host, before declaring it dead
102 </longdesc>
103 <shortdesc lang="en">no. of ping attempts</shortdesc>
104 <content type="integer" default="2"/>
105 </parameter>
106
107 <parameter name="timeout" unique="0">
108 <longdesc lang="en">
109 How long, in seconds, to wait before declaring a ping lost
110 </longdesc>
111 <shortdesc lang="en">ping timeout in seconds</shortdesc>
112 <content type="integer" default="2"/>
113 </parameter>
114
115 <parameter name="lctl" unique="0">
116 <longdesc lang="en">
117 Option to enable lctl ping. The default is true
118 </longdesc>
119 <shortdesc lang="en">Extra Options</shortdesc>
120 <content type="string" default="true"/>
121 </parameter>
122
123 <parameter name="device" unique="0">
124 <longdesc lang="en">
125 Device used for the LNET network. We assume the same device accross the cluster
126 </longdesc>
127 <shortdesc lang="en">LNET device</shortdesc>
128 <content type="string" default=""/>
129 </parameter>
130
131
132 <parameter name="options" unique="0">
133 <longdesc lang="en">
134 A catch all for any other options that need to be passed to ping.
135 </longdesc>
136 <shortdesc lang="en">Extra Options</shortdesc>
137 <content type="string" default=""/>
138 </parameter>
139
140 <parameter name="failure_score" unique="0">
141 <longdesc lang="en">
142 Resource is failed if the score is less than failure_score.
143 Default never fails.
144 </longdesc>
145 <shortdesc lang="en">failure_score</shortdesc>
146 <content type="integer" default=""/>
147 </parameter>
148
149 <parameter name="debug" unique="0">
150 <longdesc lang="en">
151 Enables to use default attrd_updater verbose logging on every call.
152 </longdesc>
153 <shortdesc lang="en">Verbose logging</shortdesc>
154 <content type="string" default="false"/>
155 </parameter>
156
157 </parameters>
158
159 <actions>
160 <action name="start"   timeout="300s" />
161 <action name="stop"    timeout="300s" />
162 <action name="reload"  timeout="300s" />
163 <action name="monitor" depth="0"  timeout="300s" interval="20s"/>
164 <action name="meta-data"  timeout="5" />
165 <action name="validate-all"  timeout="30" />
166 </actions>
167 </resource-agent>
168 END
169 }
170
171 #######################################################################
172
173 ping_conditional_log() {
174         level=$1; shift
175         if [ ${OCF_RESKEY_debug} = "true" ]; then
176                 ocf_log $level "$*"
177         fi
178 }
179
180 ping_usage() {
181         cat <<END
182         usage: $0 {start|stop|monitor|migrate_to|migrate_from|validate-all|meta-data}
183
184         Expects to have a fully populated OCF RA-compliant environment set.
185         END
186 }
187
188 ping_start() {
189     ping_monitor
190     if [ $? =  $OCF_SUCCESS ]; then
191         return $OCF_SUCCESS
192     fi
193     touch ${OCF_RESKEY_pidfile}
194     ping_update
195 }
196
197 ping_stop() {
198
199     rm -f ${OCF_RESKEY_pidfile}
200     attrd_updater -D -n $OCF_RESKEY_name -d $OCF_RESKEY_dampen $attrd_options
201     return $OCF_SUCCESS
202 }
203
204 ping_monitor() {
205     if [ -f ${OCF_RESKEY_pidfile} ]; then
206         ping_update
207         if [ $? -eq 0 ]; then
208             return $OCF_SUCCESS
209         fi
210         return $OCF_ERR_GENERIC
211     fi
212     return $OCF_NOT_RUNNING
213 }
214
215 ping_validate() {
216     # Is the state directory writable?
217     state_dir=`dirname "$OCF_RESKEY_pidfile"`
218     touch "$state_dir/$$"
219     if [ $? != 0 ]; then
220         ocf_log err "Invalid location for 'state': $state_dir is not writable"
221         return $OCF_ERR_ARGS
222     fi
223     rm "$state_dir/$$"
224
225 # Pidfile better be an absolute path
226     case $OCF_RESKEY_pidfile in
227         /*) ;;
228         *) ocf_log warn "You should use an absolute path for pidfile not: $OCF_RESKEY_pidfile" ;;
229     esac
230
231 # Check the host list
232     if [ "x" = "x$OCF_RESKEY_host_list" ]; then
233         ocf_log err "Empty host_list.  Please specify some nodes to ping"
234         exit $OCF_ERR_CONFIGURED
235     fi
236
237     check_binary ping
238
239     return $OCF_SUCCESS
240 }
241
242 lctl_check() {
243     active=0
244     for host in $OCF_RESKEY_host_list; do
245         lctl_exe="lctl ping"
246
247         lctl_out=`$lctl_exe $host $OCF_RESKEY_timeout 2>&1`; rc=$?
248         # debug
249         # ocf_log info "$lctl_exe $host $OCF_RESKEY_timeout"
250
251         case $rc in
252             0) active=`expr $active + 1`;;
253             1) ping_conditional_log warn "$host is inactive: $lctl_out";;
254             *) ocf_log err "Unexpected result for '$lctl_exe $host $OCF_RESKEY_timeout' $rc: $p_out";;
255         esac
256     done
257     return $active
258
259
260 }
261
262
263
264 ping_check() {
265     active=0
266     for host in $OCF_RESKEY_host_list; do
267         p_exe=ping
268
269         case `uname` in
270             Linux) p_args="-n -q -W $OCF_RESKEY_timeout -c $OCF_RESKEY_attempts";;
271             Darwin) p_args="-n -q -t $OCF_RESKEY_timeout -c $OCF_RESKEY_attempts -o";;
272             *) ocf_log err "Unknown host type: `uname`"; exit $OCF_ERR_INSTALLED;;
273         esac
274
275         case $host in
276             *:*) p_exe=ping6
277         esac
278
279         p_out=`$p_exe $p_args $OCF_RESKEY_options $host 2>&1`; rc=$?
280
281         case $rc in
282             0) active=`expr $active + 1`;;
283             1) ping_conditional_log warn "$host is inactive: $p_out";;
284             *) ocf_log err "Unexpected result for '$p_exe $p_args $OCF_RESKEY_options $host' $rc: $p_out";;
285         esac
286     done
287     return $active
288 }
289
290 ping_update() {
291     # first I'm testing if I have the physical link up.
292     # If not I give up without any additional tests.
293     # but first we need to find which is the device we are using on the localhost.
294
295     CARRIER=/sys/class/net/$OCF_RESKEY_device/carrier
296     OPERSTATE=/sys/class/net/$OCF_RESKEY_device/operstate
297
298     CAR_STAT=$(cat $CARRIER)
299     OPER_STAT=$(cat $OPERSTATE)
300
301     # debug
302     # ocf_log info "$CAR_STAT - $OPER_STAT"
303
304     if [ "$CAR_STAT" == "1" ] && [ "$OPER_STAT" == "up" ]; then
305         if [ ${OCF_RESKEY_lctl} = "true" ]; then
306             lctl_check
307             active=$?
308         else
309             ping_check
310             active=$?
311         fi
312     else
313         active=0
314     fi
315
316     # debug
317     # ocf_log info "$active"
318
319     score=`expr $active \* $OCF_RESKEY_multiplier`
320     attrd_updater -n $OCF_RESKEY_name -v $score -d $OCF_RESKEY_dampen $attrd_options
321     rc=$?
322     case $rc in
323         0) ping_conditional_log debug "Updated $OCF_RESKEY_name = $score" ;;
324         *) ocf_log warn "Could not update $OCF_RESKEY_name = $score: rc=$rc";;
325     esac
326     if [ $rc -ne 0 ]; then
327         return $rc
328     fi
329
330     if [ -n "$OCF_RESKEY_failure_score" -a "$score" -lt "$OCF_RESKEY_failure_score" ]; then
331         ocf_log warn "$OCF_RESKEY_name is less than failure_score($OCF_RESKEY_failure_score)"
332         return 1
333     fi
334     return 0
335 }
336
337 : ${OCF_RESKEY_name:="pingd"}
338 : ${OCF_RESKEY_dampen:="5s"}
339 : ${OCF_RESKEY_attempts:="3"}
340 : ${OCF_RESKEY_multiplier:="1"}
341 : ${OCF_RESKEY_debug:="false"}
342 : ${OCF_RESKEY_lctl:="true"}
343 #: ${OCF_RESKEY_device:="eth1"}
344 : ${OCF_RESKEY_failure_score:="0"}
345
346 : ${OCF_RESKEY_CRM_meta_timeout:="20000"}
347 : ${OCF_RESKEY_CRM_meta_globally_unique:="true"}
348
349 integer=`echo ${OCF_RESKEY_timeout} | egrep -o '[0-9]*'`
350 case ${OCF_RESKEY_timeout} in
351     *[0-9]ms|*[0-9]msec) OCF_RESKEY_timeout=`expr $integer / 1000`;;
352     *[0-9]m|*[0-9]min) OCF_RESKEY_timeout=`expr $integer \* 60`;;
353     *[0-9]h|*[0-9]hr)  OCF_RESKEY_timeout=`expr $integer \* 60 \* 60`;;
354     *) OCF_RESKEY_timeout=$integer;;
355 esac
356
357 if [ -z ${OCF_RESKEY_timeout} ]; then
358     if [ x"$OCF_RESKEY_host_list" != x ]; then
359         host_count=`echo $OCF_RESKEY_host_list | awk '{print NF}'`
360         OCF_RESKEY_timeout=`expr $OCF_RESKEY_CRM_meta_timeout / $host_count / $OCF_RESKEY_attempts`
361         OCF_RESKEY_timeout=`expr $OCF_RESKEY_timeout / 1100` # Convert to seconds and finish 10% early
362     else
363         OCF_RESKEY_timeout=5
364     fi
365 fi
366
367 if [ ${OCF_RESKEY_timeout} -lt 1 ]; then
368     OCF_RESKEY_timeout=5
369 elif [ ${OCF_RESKEY_timeout} -gt 1000 ]; then
370     # ping actually complains if this value is too high, 5 minutes is plenty
371     OCF_RESKEY_timeout=300
372 fi
373
374 if [ ${OCF_RESKEY_CRM_meta_globally_unique} = "false" ]; then
375     : ${OCF_RESKEY_pidfile:="$HA_VARRUN/ping-${OCF_RESKEY_name}"}
376 else
377     : ${OCF_RESKEY_pidfile:="$HA_VARRUN/ping-${OCF_RESOURCE_INSTANCE}"}
378 fi
379
380 attrd_options='-q'
381 if ocf_is_true ${OCF_RESKEY_debug} ; then
382     attrd_options=''
383 fi
384
385 # Check the debug option
386 case "${OCF_RESKEY_debug}" in
387     true|True|TRUE|1)    OCF_RESKEY_debug=true;;
388     false|False|FALSE|0) OCF_RESKEY_debug=false;;
389     *)
390         ocf_log warn "Value for 'debug' is incorrect. Please specify 'true' or 'false' not: ${OCF_RESKEY_debug}"
391         OCF_RESKEY_debug=false
392         ;;
393 esac
394
395 case $__OCF_ACTION in
396 meta-data)      meta_data
397                 exit $OCF_SUCCESS
398                 ;;
399 start)          ping_start;;
400 stop)           ping_stop;;
401 monitor)        ping_monitor;;
402 reload)         ping_start;;
403 validate-all)   ping_validate;;
404 usage|help)     ping_usage
405                 exit $OCF_SUCCESS
406                 ;;
407 *)              ping_usage
408                 exit $OCF_ERR_UNIMPLEMENTED
409                 ;;
410 esac