Merge branch 'stable-2.11' into stable-2.12
[ganeti-github.git] / daemons / daemon-util.in
1 #!/bin/bash
2 #
3
4 # Copyright (C) 2009, 2011, 2012 Google Inc.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are
9 # met:
10 #
11 # 1. Redistributions of source code must retain the above copyright notice,
12 # this list of conditions and the following disclaimer.
13 #
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19 # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 set -e
31
32 @SHELL_ENV_INIT@
33
34 readonly defaults_file="$SYSCONFDIR/default/ganeti"
35
36 # This is a list of all daemons and the order in which they're started. The
37 # order is important as there are dependencies between them. On shutdown,
38 # they're stopped in reverse order.
39 DAEMONS=(
40   ganeti-noded
41   ganeti-wconfd
42   ganeti-rapi
43   ganeti-luxid
44   ganeti-kvmd
45   )
46
47 # This is the list of daemons that are loaded on demand; they should only be
48 # stopped, not started.
49 ON_DEMAND_DAEMONS=(
50   ganeti-metad
51   )
52
53 _confd_enabled() {
54   [[ "@CUSTOM_ENABLE_CONFD@" == True ]]
55 }
56
57 if _confd_enabled; then
58   DAEMONS+=( ganeti-confd )
59 fi
60
61 _mond_enabled() {
62   [[ "@CUSTOM_ENABLE_MOND@" == True ]]
63 }
64
65 if _mond_enabled; then
66   DAEMONS+=( ganeti-mond )
67 fi
68
69 # The full list of all daemons we know about
70 ALL_DAEMONS=( ${DAEMONS[@]} ${ON_DEMAND_DAEMONS[@]} )
71
72 NODED_ARGS=
73 CONFD_ARGS=
74 WCONFD_ARGS=
75 LUXID_ARGS=
76 RAPI_ARGS=
77 MOND_ARGS=
78
79 # Read defaults file if it exists
80 if [[ -s $defaults_file ]]; then
81   . $defaults_file
82 fi
83
84 # Meant to facilitate use utilities in /etc/rc.d/init.d/functions in case
85 # start-stop-daemon is not available.
86 _ignore_error() {
87   eval "$@" || :
88 }
89
90 _daemon_pidfile() {
91   echo "$RUN_DIR/$1.pid"
92 }
93
94 _daemon_executable() {
95   echo "@PREFIX@/sbin/$1"
96 }
97
98 _daemon_usergroup() {
99   case "$1" in
100     confd)
101       echo "@GNTCONFDUSER@:@GNTCONFDGROUP@"
102       ;;
103     wconfd)
104       echo "@GNTWCONFDUSER@:@GNTWCONFDGROUP@"
105       ;;
106     luxid)
107       echo "@GNTLUXIDUSER@:@GNTLUXIDGROUP@"
108       ;;
109     rapi)
110       echo "@GNTRAPIUSER@:@GNTRAPIGROUP@"
111       ;;
112     noded)
113       echo "@GNTNODEDUSER@:@GNTNODEDGROUP@"
114       ;;
115     mond)
116       echo "@GNTMONDUSER@:@GNTMONDGROUP@"
117       ;;
118     *)
119       echo "root:@GNTDAEMONSGROUP@"
120       ;;
121   esac
122 }
123
124 # Checks whether the local machine is part of a cluster
125 check_config() {
126   local server_pem=$DATA_DIR/server.pem
127   local fname
128
129   for fname in $server_pem; do
130     if [[ ! -f $fname ]]; then
131       echo "Missing configuration file $fname" >&2
132       return 1
133     fi
134   done
135
136   return 0
137 }
138
139 # Checks the exit code of a daemon
140 check_exitcode() {
141   if [[ "$#" -lt 1 ]]; then
142     echo 'Missing exit code.' >&2
143     return 1
144   fi
145
146   local rc="$1"; shift
147
148   case "$rc" in
149     0) ;;
150     11)
151       echo "not master"
152     ;;
153     *)
154       echo "exit code $rc"
155       return 1
156     ;;
157   esac
158
159   return 0
160 }
161
162 # Checks if we should use systemctl to start/stop daemons
163 use_systemctl() {
164   # Is systemd running as PID 1?
165   [ -d /run/systemd/system ] || return 1
166
167   type -p systemctl >/dev/null || return 1
168
169   # Does systemd know about Ganeti at all?
170   loadstate="$(systemctl show -pLoadState ganeti.target)"
171   if [ "$loadstate" = "LoadState=loaded" ]; then
172     return 0
173   fi
174
175   return 1
176 }
177
178 # Prints path to PID file for a daemon.
179 daemon_pidfile() {
180   if [[ "$#" -lt 1 ]]; then
181     echo 'Missing daemon name.' >&2
182     return 1
183   fi
184
185   local name="$1"; shift
186
187   _daemon_pidfile $name
188 }
189
190 # Prints path to daemon executable.
191 daemon_executable() {
192   if [[ "$#" -lt 1 ]]; then
193     echo 'Missing daemon name.' >&2
194     return 1
195   fi
196
197   local name="$1"; shift
198
199   _daemon_executable $name
200 }
201
202 # Prints a list of all daemons in the order in which they should be started
203 list_start_daemons() {
204   local name
205
206   for name in "${DAEMONS[@]}"; do
207     echo "$name"
208   done
209 }
210
211 # Prints a list of all daemons in the order in which they should be stopped
212 list_stop_daemons() {
213   for name in "${ALL_DAEMONS[@]}"; do
214     echo "$name"
215   done | tac
216 }
217
218 # Checks whether a daemon name is known
219 is_daemon_name() {
220   if [[ "$#" -lt 1 ]]; then
221     echo 'Missing daemon name.' >&2
222     return 1
223   fi
224
225   local name="$1"; shift
226
227   for i in "${ALL_DAEMONS[@]}"; do
228     if [[ "$i" == "$name" ]]; then
229       return 0
230     fi
231   done
232
233   echo "Unknown daemon name '$name'" >&2
234   return 1
235 }
236
237 # Checks whether daemon is running
238 check() {
239   if [[ "$#" -lt 1 ]]; then
240     echo 'Missing daemon name.' >&2
241     return 1
242   fi
243
244   local name="$1"; shift
245   local pidfile=$(_daemon_pidfile $name)
246   local daemonexec=$(_daemon_executable $name)
247
248   if use_systemctl; then
249     activestate="$(systemctl show -pActiveState "${name}.service")"
250     if [ "$activestate" = "ActiveState=active" ]; then
251       return 0
252     else
253       return 1
254     fi
255   elif type -p start-stop-daemon >/dev/null; then
256     start-stop-daemon --stop --signal 0 --quiet \
257       --pidfile $pidfile
258   else
259     _ignore_error status \
260       -p $pidfile \
261       $daemonexec
262   fi
263 }
264
265 # Starts a daemon
266 start() {
267   if [[ "$#" -lt 1 ]]; then
268     echo 'Missing daemon name.' >&2
269     return 1
270   fi
271
272   local name="$1"; shift
273   # Convert daemon name to uppercase after removing "ganeti-" prefix
274   local plain_name=${name#ganeti-}
275   local ucname=$(tr a-z A-Z <<<$plain_name)
276   local pidfile=$(_daemon_pidfile $name)
277   local usergroup=$(_daemon_usergroup $plain_name)
278   local daemonexec=$(_daemon_executable $name)
279
280   if [[ "$name" == ganeti-confd ]] \
281       && ! _confd_enabled; then
282     echo 'ganeti-confd disabled at build time' >&2
283     return 1
284   fi
285
286   if use_systemctl; then
287     systemctl start "${name}.service"
288     return $?
289   fi
290
291   # Read $<daemon>_ARGS and $EXTRA_<daemon>_ARGS
292   eval local args="\"\$${ucname}_ARGS \$EXTRA_${ucname}_ARGS\""
293
294   @PKGLIBDIR@/ensure-dirs
295
296   if type -p start-stop-daemon >/dev/null; then
297     start-stop-daemon --start --quiet --oknodo \
298       --pidfile $pidfile \
299       --startas $daemonexec \
300       --chuid $usergroup \
301       -- $args "$@"
302   else
303     # TODO: Find a way to start daemon with a group, until then the group must
304     # be removed
305     _ignore_error daemon \
306       --pidfile $pidfile \
307       --user ${usergroup%:*} \
308       $daemonexec $args "$@"
309   fi
310
311 }
312
313 # Stops a daemon
314 stop() {
315   if [[ "$#" -lt 1 ]]; then
316     echo 'Missing daemon name.' >&2
317     return 1
318   fi
319
320   local name="$1"; shift
321   local pidfile=$(_daemon_pidfile $name)
322
323   if use_systemctl; then
324     systemctl stop "${name}.service"
325   elif type -p start-stop-daemon >/dev/null; then
326     start-stop-daemon --stop --quiet --oknodo --retry 30 \
327       --pidfile $pidfile
328   else
329     _ignore_error killproc -p $pidfile $name
330   fi
331 }
332
333 # Starts a daemon if it's not yet running
334 check_and_start() {
335   local name="$1"
336
337   if ! check $name; then
338     if use_systemctl; then
339       echo "${name} supervised by systemd but not running, will not restart."
340       return 1
341     fi
342
343     start $name
344   fi
345 }
346
347 # Starts the master role
348 start_master() {
349   if use_systemctl; then
350     systemctl start ganeti-master.target
351   else
352     start ganeti-wconfd
353     start ganeti-rapi
354     start ganeti-luxid
355   fi
356 }
357
358 # Stops the master role
359 stop_master() {
360   if use_systemctl; then
361     systemctl stop ganeti-master.target
362   else
363     stop ganeti-luxid
364     stop ganeti-rapi
365     stop ganeti-wconfd
366   fi
367 }
368
369 # Start all daemons
370 start_all() {
371   use_systemctl && systemctl start ganeti.target
372   # Fall through so that we detect any errors.
373
374   for i in $(list_start_daemons); do
375     local rc=0
376
377     # Try to start daemon
378     start $i || rc=$?
379
380     if ! errmsg=$(check_exitcode $rc); then
381       echo "$errmsg" >&2
382       return 1
383     fi
384   done
385
386   return 0
387 }
388
389 # Stop all daemons
390 stop_all() {
391   if use_systemctl; then
392     systemctl stop ganeti.target
393   else
394     for i in $(list_stop_daemons); do
395       stop $i
396     done
397   fi
398 }
399
400 # SIGHUP a process to force re-opening its logfiles
401 rotate_logs() {
402   if [[ "$#" -lt 1 ]]; then
403     echo 'Missing daemon name.' >&2
404     return 1
405   fi
406
407   local name="$1"; shift
408   local pidfile=$(_daemon_pidfile $name)
409   local daemonexec=$(_daemon_executable $name)
410
411   if type -p start-stop-daemon >/dev/null; then
412     start-stop-daemon --stop --signal HUP --quiet \
413       --oknodo --pidfile $pidfile
414   else
415     _ignore_error killproc \
416       -p $pidfile \
417       $daemonexec -HUP
418   fi
419 }
420
421 # SIGHUP all processes
422 rotate_all_logs() {
423   for i in $(list_stop_daemons); do
424     rotate_logs $i
425   done
426 }
427
428 # Reloads the SSH keys
429 reload_ssh_keys() {
430   @RPL_SSH_INITD_SCRIPT@ restart
431 }
432
433 # Read @SYSCONFDIR@/rc.d/init.d/functions if start-stop-daemon not available
434 if ! type -p start-stop-daemon >/dev/null && \
435    [[ -f @SYSCONFDIR@/rc.d/init.d/functions ]]; then
436   _ignore_error . @SYSCONFDIR@/rc.d/init.d/functions
437 fi
438
439 if [[ "$#" -lt 1 ]]; then
440   echo "Usage: $0 <action>" >&2
441   exit 1
442 fi
443
444 orig_action=$1; shift
445
446 if [[ "$orig_action" == *_* ]]; then
447   echo "Command must not contain underscores" >&2
448   exit 1
449 fi
450
451 # Replace all dashes (-) with underlines (_)
452 action=${orig_action//-/_}
453
454 # Is it a known function?
455 if ! declare -F "$action" >/dev/null 2>&1; then
456   echo "Unknown command: $orig_action" >&2
457   exit 1
458 fi
459
460 # Call handler function
461 $action "$@"