7c7b07413ab403eedfbceb42ad0f66eda82020ff
[janger/samba-autobuild/.git] / ctdb / doc / examples / nfs-ganesha-callout
1 #!/bin/sh
2
3 # This is an example CTDB NFS callout script for Ganesha.  It is based
4 # on the last version of 60.ganesha shipped with CTDB.  As such, it
5 # does not try to monitor RPC services that were not monitored by
6 # 60.ganesha - this might be a useful improvement.  It has also not
7 # been properly tested.
8
9 # You should check your version of NFS Ganesha to see if it ships with
10 # a newer callout.
11
12 # To use this:
13 #
14 # * Set CTDB_NFS_CALLOUT in your CTDB configuration to point to (a
15 #   copy of) this script, making sure it is executable.
16 #
17 # * Create a new directory alongside the nfs-checks.d directory, for
18 #   example nfs-checks-ganesha.d.  Install 20.nfs-ganesha.check in
19 #   this directory.  Symlink to any other check files from
20 #   nfs-checks.d that should still be used, such as
21 #   00.portmapper.check.  Set CTDB_NFS_CHECKS_DIR to point to this new
22 #   directory of check files.
23 #
24 # * It is recommended, but not required, to install the grace_period
25 #   script (usually shipped in a utils package for NFS-Ganesha) to
26 #   /usr/bin/grace_period
27
28 # I (Martin Schwenke) hereby relicense all of my contributions to this
29 # callout (and, previously, to 60.ganesha) to a license compatible
30 # with NFS Ganesha (right now this is LGPLv3, but I'm flexible).
31 # There may be other contributions to be considered for relicensing,
32 # particularly those in commit 28cbe527d47822f870e8252495ab2a1c8fddd12f.
33
34 ######################################################################
35
36 # Exit on 1st error
37 set -e
38
39 # Filesystem type and mount point for the (typically clustered)
40 # volume that will contain the NFS-Ganesha state.
41 state_fs="${CTDB_NFS_STATE_FS_TYPE:-gpfs}"
42 state_dir="${CTDB_NFS_STATE_MNT}" # No sane default.
43
44 # To change the following, edit the default values below.  Do not set
45 # these - they aren't configuration variables, just hooks for testing.
46 nfs_exports_file="${CTDB_NFS_EXPORTS_FILE:-/etc/ganesha/ganesha.conf}"
47 nfs_service="${CTDB_NFS_SERVICE:-nfs-ganesha}"
48 ganesha_rec_subdir=${CTDB_GANESHA_REC_SUBDIR:-.ganesha}
49 procfs=${PROCFS_PATH:-/proc}
50
51 case "$state_fs" in
52 gpfs)
53         GANRECDIR="/var/lib/nfs/ganesha"
54         ;;
55 glusterfs)
56         if [ -z "${state_dir}" ]; then
57                 echo "CTDB_NFS_STATE_MNT not defined for GlusterFS"
58                 exit 1
59         fi
60         host=$(hostname)
61         NODESTATEDIR="$state_dir/nfs-ganesha/$host"
62         GANSTATEDIR="$state_dir/nfs-ganesha/.noderefs"
63         NODESTATELN="$GANSTATEDIR/$host"
64         ;;
65 esac
66
67
68 ##################################################
69
70 usage ()
71 {
72         _c=$(basename "$0")
73         cat <<EOF
74 usage: $_c { shutdown | startup }
75        $_c { stop | start | check } nfs
76        $_c { releaseip | takeip }
77        $_c { monitor-list-shares }
78 EOF
79     exit 1
80 }
81
82
83 ##################################################
84 # Basic service stop and start
85
86 basic_stop ()
87 {
88         case "$1" in
89         nfs)
90                 service "$nfs_service" stop
91                 ;;
92         *)
93                 usage
94         esac
95 }
96
97 basic_start ()
98 {
99         case "$1" in
100         nfs)
101                 service "$nfs_service" start
102                 ;;
103         *)
104                 usage
105         esac
106 }
107
108 ##################################################
109 # "stop" and "start" options for restarting
110
111 service_stop ()
112 {
113     case "$1" in
114         nfs)
115             basic_stop "nfs"
116             ;;
117         nlockmgr)
118             # Do nothing - used by statd-callout
119             :
120             ;;
121         *)
122             usage
123     esac
124 }
125
126 service_start ()
127 {
128         case "$1" in
129         nfs)
130                 basic_start "nfs"
131                 ;;
132         nlockmgr)
133                 # Do nothing - used by statd-callout
134                 :
135                 ;;
136         *)
137                 usage
138         esac
139 }
140
141 ##################################################
142 # Nitty gritty - monitoring and IP handling
143
144 # Check that a symlink exists, create it otherwise.
145 # Usage: check_ln <TARGET> <LINK>
146 check_ln ()
147 {
148         if [ ! -L "${2}" ] ; then
149                 rm -vrf "${2}"
150         else
151                 _t=$(readlink "${2}")
152                 if [ "$_t" != "${1}" ] ; then
153                         rm -v "${2}"
154                 fi
155         fi
156         # This is not an "else".  It also re-creates the link if it was
157         # removed above!
158         if [ ! -e "${2}" ]; then
159                 ln -sfv "${1}" "${2}"
160         fi
161 }
162
163 # Return 'active' if the shared filesystem is accessible.
164 get_cluster_fs_state ()
165 {
166         case $state_fs in
167         gpfs)
168                 /usr/lpp/mmfs/bin/mmgetstate | awk 'NR == 4 { print $3 }'
169                 ;;
170         glusterfs)
171                 # Since we're past create_ganesha_recdirs(), we're active.
172                 echo "active"
173                 ;;
174         *)
175                 echo "File system $state_fs not supported"
176                 exit 1
177                 ;;
178         esac
179 }
180
181 create_ganesha_recdirs ()
182 {
183         if ! _mounts=$(mount | grep "$state_fs"); then
184                 echo "Failed to find mounts of type $state_fs"
185                 exit 1
186         fi
187         if [ -z "$_mounts" ]; then
188                 echo "startup $state_fs not ready"
189                 exit 0
190         fi
191
192         case $state_fs in
193         gpfs)
194                 _mntpt=$(echo "$_mounts" | sort | awk 'NR == 1 {print $3}')
195                 _link_dst="${_mntpt}/${ganesha_rec_subdir}"
196                 mkdir -vp "$_link_dst"
197                 check_ln "$_link_dst" "$GANRECDIR"
198                 ;;
199         glusterfs)
200                 [ -d /var/lib/nfs.backup ] || \
201                         mv /var/lib/nfs /var/lib/nfs.backup
202                 check_ln "$NODESTATEDIR" /var/lib/nfs
203
204                 mkdir -p "${NODESTATEDIR}/ganesha/v4recov"
205                 mkdir -p "${NODESTATEDIR}/ganesha/v4old"
206                 mkdir -p "${NODESTATEDIR}/statd/sm"
207                 mkdir -p "${NODESTATEDIR}/statd/sm.bak"
208                 touch "${NODESTATEDIR}/state"
209                 touch "${NODESTATEDIR}/statd/state"
210
211                 mkdir -p "$GANSTATEDIR"
212                 check_ln "$NODESTATEDIR" "$NODESTATELN"
213                 for _dir in "${GANSTATEDIR}/"* ; do
214                         # Handle no directories case
215                         if [ ! -d "$_dir" ] ; then
216                                 break
217                         fi
218
219                         _node="${_dir##*/}" # basename
220                         if [ "${_node}" != "${host}" ]; then
221                                 check_ln "${GANSTATEDIR}/${_node}/ganesha" \
222                                          "${NODESTATEDIR}/ganesha/${_node}"
223                                 check_ln "${GANSTATEDIR}/${_node}/statd" \
224                                          "${NODESTATEDIR}/statd/${_node}"
225                         fi
226                 done
227                 ;;
228         esac
229 }
230
231 service_check ()
232 {
233         create_ganesha_recdirs
234
235         # Always succeed if cluster filesystem is not active
236         _cluster_fs_state=$(get_cluster_fs_state)
237         if [ "$_cluster_fs_state" != "active" ] ; then
238                 return 0
239         fi
240
241         # Check that NFS Ganesha is running, according to PID file
242         _pidfile="/var/run/ganesha.pid"
243         _ganesha="/usr/bin/ganesha.nfsd"
244         if ! { read -r _pid < "$_pidfile" && \
245                 grep "$_ganesha" "${procfs}/${_pid}/cmdline" ; } >/dev/null 2>&1
246         then
247
248                 echo "ERROR: NFS Ganesha not running according to PID file"
249                 return 1
250         fi
251
252         return 0
253 }
254
255 #-------------------------------------------------
256
257 nfs_releaseip ()
258 {
259         if [ -x "/usr/bin/grace_period" ]; then
260                 /usr/bin/grace_period "2:${2}"
261         else
262                 dbus-send --print-reply --system --dest=org.ganesha.nfsd \
263                           /org/ganesha/nfsd/admin org.ganesha.nfsd.admin.grace \
264                           string:"2:${2}"
265         fi
266 }
267
268 nfs_takeip ()
269 {
270         case  $state_fs in
271         glusterfs)
272                 check_ln "$NODESTATEDIR" "${GANSTATEDIR}/${2}"
273                 ;;
274         esac
275         if [ -x "/usr/bin/grace_period" ]; then
276                 /usr/bin/grace_period "5:${2}"
277         else
278                 dbus-send --print-reply --system --dest=org.ganesha.nfsd \
279                           /org/ganesha/nfsd/admin org.ganesha.nfsd.admin.grace \
280                           string:"5:${2}"
281         fi
282 }
283
284 ##################################################
285 # service init startup and final shutdown
286
287 nfs_shutdown ()
288 {
289         basic_stop "nfs"
290 }
291
292 nfs_startup ()
293 {
294         basic_stop "nfs" || true
295
296         create_ganesha_recdirs
297
298         basic_start "nfs"
299         _f="${procfs}/sys/net/ipv4/tcp_tw_recycle"
300         if [ -f "$_f" ] ; then
301                 echo 1 >"$_f"
302         fi
303 }
304
305 ##################################################
306 # list share directories
307
308 nfs_monitor_list_shares ()
309 {
310         grep Path "$nfs_exports_file" |
311                 cut -f2 -d\" |
312                 sort -u
313 }
314
315 ##################################################
316
317 nfs_register ()
318 {
319         cat <<EOF
320 shutdown
321 startup
322 stop
323 start
324 check
325 releaseip
326 takeip
327 monitor-list-shares
328 EOF
329 }
330
331 ##################################################
332
333 action="$1"
334 shift
335
336 case "$action" in
337 shutdown)            nfs_shutdown            ;;
338 startup)             nfs_startup             ;;
339 stop)                service_stop "$1"       ;;
340 start)               service_start "$1"      ;;
341 check)               service_check "$1"      ;;
342 releaseip)           nfs_releaseip "$@"      ;;
343 takeip)              nfs_takeip "$@"         ;;
344 monitor-list-shares) nfs_monitor_list_shares ;;
345 register)            nfs_register            ;;
346 monitor-pre|monitor-post|releaseip-pre|takeip-pre)
347         # Not required/implemented
348         :
349         ;;
350 *)
351         usage
352 esac