Merge branch 'stable-2.10' into stable-2.11
[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-masterd
42   ganeti-rapi
43   ganeti-luxid
44   ganeti-kvmd
45   )
46
47 _confd_enabled() {
48   [[ "@CUSTOM_ENABLE_CONFD@" == True ]]
49 }
50
51 if _confd_enabled; then
52   DAEMONS+=( ganeti-confd )
53 fi
54
55 _mond_enabled() {
56   [[ "@CUSTOM_ENABLE_MOND@" == True ]]
57 }
58
59 if _mond_enabled; then
60   DAEMONS+=( ganeti-mond )
61 fi
62
63 NODED_ARGS=
64 MASTERD_ARGS=
65 CONFD_ARGS=
66 LUXID_ARGS=
67 RAPI_ARGS=
68 MOND_ARGS=
69
70 # Read defaults file if it exists
71 if [[ -s $defaults_file ]]; then
72   . $defaults_file
73 fi
74
75 # Meant to facilitate use utilities in /etc/rc.d/init.d/functions in case
76 # start-stop-daemon is not available.
77 _ignore_error() {
78   eval "$@" || :
79 }
80
81 _daemon_pidfile() {
82   echo "$RUN_DIR/$1.pid"
83 }
84
85 _daemon_executable() {
86   echo "@PREFIX@/sbin/$1"
87 }
88
89 _daemon_usergroup() {
90   case "$1" in
91     masterd)
92       echo "@GNTMASTERUSER@:@GNTMASTERDGROUP@"
93       ;;
94     confd)
95       echo "@GNTCONFDUSER@:@GNTCONFDGROUP@"
96       ;;
97     luxid)
98       echo "@GNTLUXIDUSER@:@GNTLUXIDGROUP@"
99       ;;
100     rapi)
101       echo "@GNTRAPIUSER@:@GNTRAPIGROUP@"
102       ;;
103     noded)
104       echo "@GNTNODEDUSER@:@GNTNODEDGROUP@"
105       ;;
106     mond)
107       echo "@GNTMONDUSER@:@GNTMONDGROUP@"
108       ;;
109     *)
110       echo "root:@GNTDAEMONSGROUP@"
111       ;;
112   esac
113 }
114
115 # Checks whether the local machine is part of a cluster
116 check_config() {
117   local server_pem=$DATA_DIR/server.pem
118   local fname
119
120   for fname in $server_pem; do
121     if [[ ! -f $fname ]]; then
122       echo "Missing configuration file $fname" >&2
123       return 1
124     fi
125   done
126
127   return 0
128 }
129
130 # Checks the exit code of a daemon
131 check_exitcode() {
132   if [[ "$#" -lt 1 ]]; then
133     echo 'Missing exit code.' >&2
134     return 1
135   fi
136
137   local rc="$1"; shift
138
139   case "$rc" in
140     0) ;;
141     11)
142       echo "not master"
143     ;;
144     *)
145       echo "exit code $rc"
146       return 1
147     ;;
148   esac
149
150   return 0
151 }
152
153 # Prints path to PID file for a daemon.
154 daemon_pidfile() {
155   if [[ "$#" -lt 1 ]]; then
156     echo 'Missing daemon name.' >&2
157     return 1
158   fi
159
160   local name="$1"; shift
161
162   _daemon_pidfile $name
163 }
164
165 # Prints path to daemon executable.
166 daemon_executable() {
167   if [[ "$#" -lt 1 ]]; then
168     echo 'Missing daemon name.' >&2
169     return 1
170   fi
171
172   local name="$1"; shift
173
174   _daemon_executable $name
175 }
176
177 # Prints a list of all daemons in the order in which they should be started
178 list_start_daemons() {
179   local name
180
181   for name in "${DAEMONS[@]}"; do
182     echo "$name"
183   done
184 }
185
186 # Prints a list of all daemons in the order in which they should be stopped
187 list_stop_daemons() {
188   list_start_daemons | tac
189 }
190
191 # Checks whether a daemon name is known
192 is_daemon_name() {
193   if [[ "$#" -lt 1 ]]; then
194     echo 'Missing daemon name.' >&2
195     return 1
196   fi
197
198   local name="$1"; shift
199
200   for i in "${DAEMONS[@]}"; do
201     if [[ "$i" == "$name" ]]; then
202       return 0
203     fi
204   done
205
206   echo "Unknown daemon name '$name'" >&2
207   return 1
208 }
209
210 # Checks whether daemon is running
211 check() {
212   if [[ "$#" -lt 1 ]]; then
213     echo 'Missing daemon name.' >&2
214     return 1
215   fi
216
217   local name="$1"; shift
218   local pidfile=$(_daemon_pidfile $name)
219   local daemonexec=$(_daemon_executable $name)
220
221   if type -p start-stop-daemon >/dev/null; then
222     start-stop-daemon --stop --signal 0 --quiet \
223       --pidfile $pidfile
224   else
225     _ignore_error status \
226       -p $pidfile \
227       $daemonexec
228   fi
229 }
230
231 # Starts a daemon
232 start() {
233   if [[ "$#" -lt 1 ]]; then
234     echo 'Missing daemon name.' >&2
235     return 1
236   fi
237
238   local name="$1"; shift
239   # Convert daemon name to uppercase after removing "ganeti-" prefix
240   local plain_name=${name#ganeti-}
241   local ucname=$(tr a-z A-Z <<<$plain_name)
242   local pidfile=$(_daemon_pidfile $name)
243   local usergroup=$(_daemon_usergroup $plain_name)
244   local daemonexec=$(_daemon_executable $name)
245
246   if [[ "$name" == ganeti-confd ]] \
247       && ! _confd_enabled; then
248     echo 'ganeti-confd disabled at build time' >&2
249     return 1
250   fi
251
252   # Read $<daemon>_ARGS and $EXTRA_<daemon>_ARGS
253   eval local args="\"\$${ucname}_ARGS \$EXTRA_${ucname}_ARGS\""
254
255   @PKGLIBDIR@/ensure-dirs
256
257   if type -p start-stop-daemon >/dev/null; then
258     start-stop-daemon --start --quiet --oknodo \
259       --pidfile $pidfile \
260       --startas $daemonexec \
261       --chuid $usergroup \
262       -- $args "$@"
263   else
264     # TODO: Find a way to start daemon with a group, until then the group must
265     # be removed
266     _ignore_error daemon \
267       --pidfile $pidfile \
268       --user ${usergroup%:*} \
269       $daemonexec $args "$@"
270   fi
271
272 }
273
274 # Stops a daemon
275 stop() {
276   if [[ "$#" -lt 1 ]]; then
277     echo 'Missing daemon name.' >&2
278     return 1
279   fi
280
281   local name="$1"; shift
282   local pidfile=$(_daemon_pidfile $name)
283
284   if type -p start-stop-daemon >/dev/null; then
285     start-stop-daemon --stop --quiet --oknodo --retry 30 \
286       --pidfile $pidfile
287   else
288     _ignore_error killproc -p $pidfile $name
289   fi
290 }
291
292 # Starts a daemon if it's not yet running
293 check_and_start() {
294   local name="$1"
295
296   if ! check $name; then
297     start $name
298   fi
299 }
300
301 # Starts the master role
302 start_master() {
303   start ganeti-masterd
304   start ganeti-rapi
305   start ganeti-luxid
306 }
307
308 # Stops the master role
309 stop_master() {
310   stop ganeti-luxid
311   stop ganeti-rapi
312   stop ganeti-masterd
313 }
314
315 # Start all daemons
316 start_all() {
317   for i in $(list_start_daemons); do
318     local rc=0
319
320     # Try to start daemon
321     start $i || rc=$?
322
323     if ! errmsg=$(check_exitcode $rc); then
324       echo "$errmsg" >&2
325       return 1
326     fi
327   done
328
329   return 0
330 }
331
332 # Stop all daemons
333 stop_all() {
334   for i in $(list_stop_daemons); do
335     stop $i
336   done
337 }
338
339 # SIGHUP a process to force re-opening its logfiles
340 rotate_logs() {
341   if [[ "$#" -lt 1 ]]; then
342     echo 'Missing daemon name.' >&2
343     return 1
344   fi
345
346   local name="$1"; shift
347   local pidfile=$(_daemon_pidfile $name)
348   local daemonexec=$(_daemon_executable $name)
349
350   if type -p start-stop-daemon >/dev/null; then
351     start-stop-daemon --stop --signal HUP --quiet \
352       --oknodo --pidfile $pidfile
353   else
354     _ignore_error killproc \
355       -p $pidfile \
356       $daemonexec -HUP
357   fi
358 }
359
360 # SIGHUP all processes
361 rotate_all_logs() {
362   for i in $(list_stop_daemons); do
363     rotate_logs $i
364   done
365 }
366
367 # Reloads the SSH keys
368 reload_ssh_keys() {
369   @RPL_SSH_INITD_SCRIPT@ restart
370 }
371
372 # Read @SYSCONFDIR@/rc.d/init.d/functions if start-stop-daemon not available
373 if ! type -p start-stop-daemon >/dev/null && \
374    [[ -f @SYSCONFDIR@/rc.d/init.d/functions ]]; then
375   _ignore_error . @SYSCONFDIR@/rc.d/init.d/functions
376 fi
377
378 if [[ "$#" -lt 1 ]]; then
379   echo "Usage: $0 <action>" >&2
380   exit 1
381 fi
382
383 orig_action=$1; shift
384
385 if [[ "$orig_action" == *_* ]]; then
386   echo "Command must not contain underscores" >&2
387   exit 1
388 fi
389
390 # Replace all dashes (-) with underlines (_)
391 action=${orig_action//-/_}
392
393 # Is it a known function?
394 if ! declare -F "$action" >/dev/null 2>&1; then
395   echo "Unknown command: $orig_action" >&2
396   exit 1
397 fi
398
399 # Call handler function
400 $action "$@"